Introduzione
WordPress è uno dei Content Management System (CMS) più popolari in circolazione. Statisticamente, alimenta oltre il 39% di tutti i siti web che vedi nel world wide web. È una scelta popolare per via della sua estensibilità tramite plugin e del suo sistema di template flessibile. Ti consente di modificarne l'aspetto in pochi secondi. Inoltre, la sua amministrazione può essere effettuata tramite l'interfaccia web senza richiedere molte competenze tecniche.
Inoltre, WordPress è gratuito e open-source ed è basato su un MySQL database con elaborazione PHP. Puoi distribuire WordPress su uno stack LAMP (Linux, Apache, MySQL e PHP) o uno stack LEMP (Linux, Nginx, MySQL e PHP). Tuttavia, si rivela dispendioso in termini di tempo configurare lo stack ogni volta che si desidera effettuare una distribuzione.
Fortunatamente, i moderni metodi di distribuzione del software come il cloud computing, Docker, e Docker Compose hanno semplificato l'esperienza complessiva degli sviluppatori. Questi strumenti semplificano il processo di configurazione di qualsiasi stack evitando il sovraccarico di installare e configurare i singoli componenti ogni volta che si desidera distribuire un'applicazione. Invece, scrivi file di configurazione che verranno utilizzati per scaricare e creare immagini ed eseguirle nei container Docker, consentendoti di distribuire la tua applicazione con un solo comando.
I container sono ambienti standardizzati leggeri, virtualizzati, portabili e definiti dal software che consentono al software di essere eseguito in isolamento rispetto ad altri software in esecuzione sulla macchina host fisica. Docker Compose consente di gestire più container e garantire che comunichino tra loro. Ad esempio, il codice sorgente di un'applicazione e un database devono comunicare.
In questo tutorial, andremo a creare un'applicazione WordPress multi-container. Un'applicazione WordPress completa richiede tre container: database MySQL, server Nginx e codice sorgente di WordPress. Poiché la sicurezza è una priorità nei siti web moderni, otterremo un certificato SSL da Let’s Encrypt per proteggere la tua installazione. Successivamente, configureremo un cron job per controllare e rinnovare periodicamente i certificati, in modo che la sicurezza del tuo sito web sia mantenuta continuamente.
Prerequisiti
- Poiché questo è un tutorial pratico, dovresti avere un'installazione di Ubuntu 20.04 come ambiente operativo iniziale. Dovresti anche avere un utente non root con privilegi sudo. Ecco un tutorial passo-passo per aiutarti a configurare il tuo server Ubuntu.
- Devi anche installare Docker. Puoi fare riferimento a questo tutorial su come installare e utilizzare Docker su Ubuntu 18.04.
- Un'installazione di Docker Compose. Puoi seguire il Passaggio 1 del tutorial Come installare e configurare Docker Compose su Ubuntu 20.04.
- È richiesto un nome di dominio registrato per ottenere un certificato TLS/SSL da Let’s Encrypt. Ai fini di questo tutorial, utilizzeremo
example.com. - Configura i record DNS per indirizzare il traffico verso il tuo VPS. Ti servono due record DNS:
- Un record A con
example.comche punta all'indirizzo IP pubblico del tuo server. - Un record A con
www.example.comche punta all'indirizzo IP pubblico del tuo server.
- Un record A con
Passaggio 1: Definire le configurazioni per il server web
Il server web ospita i file del tuo sito web e consente agli utenti di accedere alla tua applicazione web. Pertanto, è opportuno che nel primo passaggio definiamo la configurazione per il server web. Definiremo un file di configurazione del server Nginx che includerà blocchi di posizione specifici per WordPress. Includeremo anche blocchi di posizione per indirizzare le richieste di verifica di Let’s Encrypt al client Certbot per i rinnovi automatici del certificato.
Iniziamo creando una directory per il progetto. Puoi scegliere il nome della directory che preferisci. Utilizzeremo wordpress_docker per questo tutorial. Inserisci il seguente comando per creare la directory ed entrarci:
|
1 |
mkdir wordpress_docker && cd wordpress_docker |
Successivamente, crea una directory per contenere i file di configurazione di Nginx con il comando:
|
1 |
mkdir nginx-conf |
Usa nano per aprire il file con il seguente comando:
|
1 |
nano nginx-conf/nginx.conf |
In questo file definiremo le direttive di base per la configurazione di un blocco server Nginx. Queste includono le direttive per il nome del server, la root dei documenti e i blocchi di posizione per indirizzare le richieste del plugin Certbot per i certificati, i file statici e l'elaborazione PHP. Puoi leggere il nostro tutorial su Come proteggere Nginx con Let’s Encrypt per saperne di più. Aggiungi il seguente codice al file, sostituendo example.com con il tuo nome di dominio registrato:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; index index.php index.html index.htm; root /var/www/html; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
Definiamo le sezioni che hai aggiunto:
-
Direttive:
listen: indica a Nginx di rimanere in ascolto sulla porta80. Questo consente l'uso del webroot di Certbot plugin per effettuare richieste di certificati. Una volta ottenuto un certificato SSL, aggiorneremo questa configurazione per utilizzare la porta443.server_name: definisce il nome di dominio che questa configurazione deve gestire. Il traffico verso il nome di dominio qui definito sarà indirizzato a questo particolare blocco server, e quindi alla root del documentoroot.root: definisce la directory root per le richieste al nome di dominio sopra indicato. Di solito è la directory che contiene i file effettivi del nostro sito web. Abbiamo impostato la directory su/var/www/html. Verrà creata come punto di montaggio Docker durante la fase di compilazione del container. Definiremo le istruzioni per questo processo all'interno del WordPress Dockerfile.index: questo definisce i file che verranno utilizzati come indici o come punto di ingresso per il server web durante l'elaborazione delle richieste. Abbiamo spostato index.php prima di index.html in modo che Nginx dia la priorità aindex.php.
-
Blocchi Location:
location ~ /.well-known/acme-challenge: gestisce le richieste alla directory well-known in cui Certbot aggiunge un file temporaneo per convalidare che il DNS per il dominio specificato punti al server particolare da cui stiamo richiedendo i certificati SSL. Questo è il motivo per cui dovresti aggiungere un dominio valido affinché questo passaggio funzioni, invece diexample.comche stiamo utilizzando in questo tutorial.location /: raccoglie le richieste URI e cede il controllo a WordPressindex.phpper richiedere gli argomenti per l'elaborazione.location ~ \.php$: gestisce l'elaborazione PHP e passa la richiesta al container WordPress (definiremo un file di configurazione per questo in un passaggio successivo). Abbiamo definito configurazioni specifiche per il protocollo FastCGI qui perché l'immagine Docker di WordPress si baserà sull'immagine php:fpm. Nginx utilizza un elaboratore PHP indipendente per le richieste specifiche di PHP. Utilizzeremo l'elaboratorephp-fpmfornito con l'immagine Dockerphp:fpmdi Docker.location ~ /\.ht: gestisce i file.htaccessche Nginx non utilizza. La direttivadeny allassicura che questi file non vengano mai serviti ai visitatori del sito web.location = /favicon.ico, location = /robots.txt: come si vede nella definizione, questo impedisce la registrazione delle richieste ai file/favicon.icoe/robots.txt.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: disattiva la registrazione delle richieste per i file statici e assicura che vengano memorizzati nella cache per ridurre il carico sul server.
Ora puoi salvare e chiudere il file premendo CTRL+X, Y, quindi INVIO. Questo completa il primo passaggio.
Passaggio 2: Definire le variabili d'ambiente
Le variabili d'ambiente sono necessarie per facilitare la comunicazione tra l'applicazione WordPress e il database. Assicurano inoltre la persistenza dei dati dell'applicazione. Le variabili d'ambiente includono informazioni sensibili come le credenziali del database e informazioni non sensibili come il nome del database e l'host.
Per motivi di sicurezza, è sempre una buona idea non aggiungere informazioni sensibili ai repository del progetto. Pertanto, invece di impostare i valori sensibili nel file Docker Compose, definiremo le credenziali MySQL all'interno dei file .env che non verranno inviati al repository del progetto, evitando il rischio di esposizione pubblica. All'interno della directory principale del progetto root ~/wordpress_docker apri il file .env:
|
1 |
nano .env |
|
1 2 3 |
MYSQL_ROOT_PASSWORD=la_tua_password_root_complessa MYSQL_USER=il_tuo_utente_database_wordpress MYSQL_PASSWORD=la_tua_password_database_wordpress_complessa |
La prossima cosa da fare è aggiungere il file .env ai file .gitignore e .dockerignore per garantire che non venga aggiunto rispettivamente ai tuoi repository o alle immagini Docker.
Questo non è necessario per questo tutorial, ma se vuoi lavorare con Git per il controllo della versione, inserisci il seguente comando per inizializzare la directory corrente come repository git:
|
1 |
git init |
Apri il file .gitignore con nano:
|
1 |
nano .gitignore |
Aggiungi la seguente riga:
|
1 |
.env |
Salva e chiudi il file. Successivamente, apri il file .dockerignore con nano:
|
1 |
nano .dockerignore |
Aggiungi la seguente riga:
|
1 |
.env |
Già che ci sei, puoi facoltativamente aggiungere altri file e directory associati allo sviluppo della tua applicazione:
|
1 2 3 |
.env .git docker-compose.yml |
Salva e chiudi il file quando hai finito. Questo è tutto per questo passaggio. Passiamo alla definizione di Docker Compose.
Passaggio 3: Configurare i servizi con Docker Compose
Docker Compose utilizza un file docker-compose.yml per compilare le immagini. Questo file contiene le definizioni dei servizi per la configurazione completa di un'applicazione. Le definizioni dei servizi sono fondamentalmente istruzioni su come verrà eseguito un container. Un servizio è un container effettivamente in esecuzione.
Docker Compose consente di definire diversi servizi per applicazioni multi-container collegando i vari servizi tra loro con reti e volumi condivisi. Vedrai questo in azione poiché definiremo tre container per la nostra applicazione: server web, installazione di WordPress e database. Aggiungeremo un quarto container per eseguire il client Certbot per i rinnovi dei certificati.
Inserisci il seguente comando per creare il file docker-compose.yml :
|
1 |
nano docker-compose.yml |
La prima riga in un file docker-compose.yml è la riga di definizione della versione. Abbiamo impostato 3 per la nostra. Successivamente, puoi iniziare a definire i tuoi servizi. Aggiungi il seguente frammento di codice nel file per definire il servizio db :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: '3' services: #MySQL Service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network |
Discutiamo di ciò che abbiamo nelle definizioni del servizio db qui sotto:
image: determina l'immagine su cui si baserà il container. È sempre meglio specificare una versione specifica (mysql:8.0) rispetto all'uso del tag latest (mysql:latest) poiché le versioni future delle immagini MySQL potrebbero andare in conflitto con la nostra applicazione se dovessimo ricompilare questa immagine. Puoi trovare maggiori informazioni sulle Best practice per i Dockerfile sulla documentazione ufficiale dei Dockerfile.container_name: qui specifichiamo il nome del container.restart: questa direttiva determina il comportamento di riavvio del container. Il valore predefinito ènoma noi lo abbiamo impostato per riavviarsi sempre (restart) a meno che non venga arrestato manualmente.env_file: questa direttiva viene utilizzata per specificare la posizione del file con le variabili d'ambiente (.env) utilizzato dalla nostra applicazione.environment: utilizzato per specificare variabili d'ambiente aggiuntive. In questo tutorial, abbiamo specificato la variabileMYSQL_DATABASEper contenere il nome del database per la nostra applicazione. Il nome del database può essere incluso nel filedocker-compose.yml.volumes: utilizzato per specificare le posizioni di montaggio. Nel nostro esempio, abbiamo montato un volume denominato dbdata nella directory/var/lib/mysqlsul container, che di solito è la directory dei dati standard per MySQL.command: questa direttiva specifica un comando che sovrascriverà l'istruzione CMD predefinita per l'immagine. Abbiamo aggiunto un'opzione al comando standardmysqlddell'immagine Docker che avvia il server MySQL all'interno del container. L'opzione che abbiamo aggiunto è--default-authentication-plugin=mysql_native_password, che aggiorna il plugin di autenticazione predefinito per MySQL per utilizzare l'autenticazione tramite password (mysql_native_password). Questo è necessario per il funzionamento di PHP (e dell'applicazione WordPress) perché utilizzano un nome utente e una password per accedere al database. Nelle versioni più recenti di MySQL, il plugin di autenticazione predefinito è cambiato. Tuttavia, la maggior parte delle applicazioni utilizza l'autenticazione tramite password. Pertanto, è necessario modificare questa impostazione affinché l'applicazione funzioni.networks: questa direttiva viene utilizzata per specificare che il serviziodbdeve unirsi alla reteapp-network, che definiremo nel corso del tutorial.
Successivamente, definiamo la configurazione del servizio per la nostra applicazione WordPress. Chiameremo il servizio e container_name app. Aggiungi il seguente frammento di codice sotto la db definizione del servizio, tenendo a mente la corretta indentazione:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#Servizio codice applicazione WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network |
Proprio come abbiamo fatto con il servizio db, abbiamo nominato il nostro container e definito la politica di riavvio. Alcune opzioni aggiuntive che abbiamo aggiunto sono definite di seguito:
depends_on: questa direttiva assicura che i container vengano avviati in ordine di dipendenza. Nel nostro caso, il containerappdipende dal containerdb. Pertanto, si avvierà dopo che il containerdbsi sarà avviato. Questo deve avvenire in questo ordine perché l'applicazione WordPress dipende dalla disponibilità di un database MySQL per funzionare.image: come si vede nel frammento di codice, utilizzeremo l'immagine WordPress versione 5.1.1 fpm alpine image. Avevamo spiegato il funzionamento del processorephp-fpmrichiesto da Nginx per l'elaborazione PHP. Questa immagine si occupa di questo. L'immagine alpine basata sul progetto Alpine Linux aiuta a mantenere ridotte le dimensioni dell'immagine. Se hai bisogno di ulteriori informazioni sulle varianti dell'immagine, puoi seguire questo link per le immagini WordPress su Docker Hub.env_file: specifica la posizione del file.envche contiene le credenziali del database.environment: questa direttiva definisce variabili d'ambiente aggiuntive. Nel nostro caso, stiamo definendo le variabili che WordPress si aspetta e assegnando loro i valori delle variabili del nostro file.env. Queste sonoWORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD, eWORDPRESS_DB_HOSTche si riferisce al server MySQL in esecuzione sul containerdb, accessibile dalla porta predefinita di MySQL3306. Infine, vediWORDPRESS_DB_NAMEche abbiamo impostato su WordPress. Lo stesso valore è specificato nella definizione del servizio MySQL nel container db:MYSQL_DATABASE=wordpress.volumes: questa direttiva monta un volume chiamato app sul punto di montaggio/var/www/html, creato dall'immagine WordPress. L'assegnazione dei nomi ai volumi consente la condivisione del codice dell'applicazione con altri container.networks: infine, aggiungiamo il container app alla reteapp-networkper garantire che comunichi con gli altri container sulla rete.
Questo è tutto per il container del servizio app per l'immagine WordPress. Ora definiamo il servizio webserver per l'immagine Nginx. Per prima cosa, aggiungi il seguente frammento di codice sotto la definizione del servizio app nel tuo file docker-compose.yml:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Servizio Webserver Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Abbiamo già spiegato l'opzione depends_on. Nel caso di questo servizio webserver, il container si avvierà dopo che il container app si sarà avviato. Il container del server web è basato sull'immagine Nginx alpine. Ha una politica di riavvio simile alle definizioni dei servizi precedenti. Le altre opzioni nella definizione del servizio webserver includono:
ports: associa le porte tra la macchina host e il container. Nel Passo 1, avevamo definito la porta80nel filenginx.conf. Questa porta è mappata sulla porta80sul container.volumes: abbiamo una combinazione di bind mount e volumi con nome sotto questa opzione:app:/var/www/html: questa definizione di volume monta l'applicazione WordPress nella directory/var/www/htmlche in precedenza avevamo impostato come root nel blocco server di Nginx../nginx-conf:/etc/nginx/conf.d: questa definizione esegue il bind mount della directory di configurazione di Nginx sulla macchina host alla directory di configurazione di Nginx definita per il container. Pertanto, qualsiasi modifica sulla macchina host si riflette automaticamente nel container.certbot-etc:/etc/letsencrypt: questa definizione monta i certificati e le chiavi di Let’s Encrypt per il dominio nella directory appropriata sul container.
networks: come nelle definizioni dei servizi precedenti, la direttivanetworksaggiunge il servizio webserver alla reteapp-networks.
Ora che abbiamo terminato con la definizione del webserver, aggiungiamo le istruzioni per il servizio Certbot. Questo gestirà l'ottenimento dei certificati TLS/SSL da Let’s Encrypt. Se desideri saperne di più sulla protezione di un server Nginx, questo tutorial su come proteggere Nginx con Let’s Encrypt è un'ottima risorsa.
Successivamente, aggiungi il seguente frammento di codice sotto il servizio webserver. Ricorda di impostare il nome di dominio e l'indirizzo email corretti:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com |
L'immagine certbot si avvierà solo dopo che il webserver si è avviato, a causa della direttiva depends_on directive. Docker Compose si occuperà di scaricare l'immagine Certbot da Docker Hub come definito.
Sotto la definizione dei volumi, il container Certbot condividerà i certificati e la chiave del dominio in certbot-etc con il container del webserver Nginx e il codice dell'applicazione con il container app.
Sotto la definizione command, abbiamo specificato un sottocomando per eseguire il comando predefinito di Certbot del container certonly con opzioni aggiuntive come elencato di seguito:
-
--webroot: specifica l'uso del plugin webroot che inserisce i file nella cartella webroot per l'autenticazione.--webroot-path: specifica il percorso della directory webroot.--agree-tos: specifica che accetti i Termini di servizio di ACME.--no-eff-email: specifica che non desideri condividere la tua email con la EFF. Puoi omettere questo parametro se desideri condividerla.--staging: indica a Certbot che desideri prima ottenere certificati di test dall'ambiente di staging di Let’s Encrypt per testare la tua configurazione prima di ottenere il certificato effettivo. Let’s Encrypt ha limiti di frequenza per le richieste di dominio. Pertanto, testare prima la configurazione ti aiuterà a evitare che il tuo dominio venga limitato.-d: questa opzione accetta i nomi di dominio per la richiesta del certificato. In questo tutorial, abbiamo inclusoexample.comewww.example.com. Specifica il tuo dominio effettivamente registrato.
Il nostro file docker-compose.yml è quasi completo. Tuttavia, devi anche aggiungere le definizioni di rete e volume sotto il servizio Certbot:
|
1 2 3 4 5 6 7 8 9 10 |
#Volumes volumes: certbot-etc: app: dbdata: #Networks networks: app-network: driver: bridge |
La chiave volumes definisce i volumi da condividere con tutti i servizi (container) definiti in questo file compose: certbot-etc, app, e dbdata. I contenuti dei volumi creati da Docker sono memorizzati in una directory gestita da Docker sul file system dell'host: /var/lib/docker/volumes/. I contenuti di ciascun volume vengono quindi montati su qualsiasi container che utilizzi il volume. Questo rende possibile la condivisione di dati e codice tra i container.
La chiave networks definisce la rete bridge che consente la comunicazione tra i container. I container sulla stessa rete bridge come webserver e db possono comunicare in modo sicuro attraverso le porte senza esporre il traffico alla rete esterna. Esponiamo solo la porta 80 per consentire l'accesso alle pagine del sito web front-end.
Il file completo docker-compose.yml sarà simile a questo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
version: '3' services: #MySQL Service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #WordPress application code Service app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Webserver Nginx service webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com #Volumes volumes: certbot-etc: app: dbdata: #Networks networks: app-network: driver: bridge |
Puoi salvare e chiudere il file. Nel passaggio successivo, avvieremo e testeremo il container e le richieste di certificato.
Passaggio 4: Esecuzione dei container e ottenimento dei certificati SSL
Il più grande vantaggio di Docker Compose è che, una volta definiti tutti i servizi nel docker-compose.yml file, puoi avviare tutti i container con un solo comando: docker-compose up. Il comando esegue ogni istruzione specificata. Se le richieste di dominio vanno a buon fine, dovresti essere in grado di vedere lo stato di uscita corretto nel tuo terminale. Inserisci il seguente comando per creare i container. Il -d flag serve per eseguire i container in background:
|
1 |
docker-compose up -d |
Se vedi l'output come nello screenshot qui sotto, allora i servizi sono stati creati con successo:
Per confermare lo stato dei servizi, esegui il comando docker-compose ps :
|
1 |
docker-compose ps |
L'output del comando è come mostrato di seguito se tutto è andato a buon fine. Lo stato dei container app, db, e webserver dovrebbe essere attivo (up), e il container certbot dovrebbe avere lo stato Exit0 :
Se vedi qualcosa di diverso da Up nella colonna dello stato per app, db o webserver, o uno stato di Exit che non sia 0 per il container certbot, allora qualcosa è andato storto. Puoi controllare i log di ciascun container usando il comando docker-compose logs, e specificare il service_name:
|
1 |
docker-compose logs service_name |
Ad esempio, puoi controllare i log del container certbot inserendo il seguente comando:
|
1 |
docker-compose logs certbot |
Per verificare se i certificati sono stati montati sul container webserver , usa il comando docker-compose exec :
|
1 |
docker-compose exec webserver ls -la /etc/letsencrypt/live |
Se hai utilizzato un nome di dominio effettivamente registrato diverso da example.com e le richieste di certificato sono andate a buon fine, dovresti vedere un output simile a questo:
Una volta confermato che la richiesta del certificato è andata a buon fine, puoi modificare il file docker-compose.yml e rimuovere il flag --staging . Apri il file con nano:
|
1 |
nano docker-compose.yml |
Scorri verso il basso fino alla sezione di definizione del servizio Certbot, nell'opzione command e sostituisci il flag --staging con il flag --force-renewal . Questo indica a Certbot che stai richiedendo il rinnovo di un certificato per lo stesso dominio. La definizione del servizio Certbot dovrebbe ora apparire così:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com |
Salva il file quando hai finito di modificarlo.
Inserisci il seguente comando per ricreare il container certbot . Il flag --no-deps incluso indica a Compose di saltare il riavvio del servizio del server web poiché è già in esecuzione:
|
1 |
docker-compose up --force-recreate --no-deps Certbot |
Il comando produce lo screenshot seguente, che mostra che la richiesta del certificato è andata a buon fine:
Questo è tutto per questo passaggio. Nel passaggio successivo, modificherai il file di configurazione di Nginx per includere il certificato SSL.
Passaggio 5: Abilitazione di SSL nella configurazione di Nginx e nella definizione del servizio
Per fare in modo che Nginx gestisca il traffico tramite SSL sicuro, modificherai prima il file di configurazione di Nginx per aggiungere un reindirizzamento da HTTP a HTTPS. Successivamente, dovrai specificare le posizioni del certificato e della chiave, e infine aggiungere parametri di sicurezza e intestazioni.
Prima di modificare il file di configurazione, dovresti ottenere i parametri di sicurezza consigliati per Nginx dal repository GitHub di Certbot usando curl con il seguente comando:
|
1 |
curl -sSLo nginx-conf/options-ssl-nginx.conf |
Il comando viene eseguito e salva i parametri estratti in un file chiamato options-ssl-nginx.conf, all'interno della nginx-conf directory. Rimuovi il file di configurazione di Nginx in modo da poterne creare uno nuovo con i seguenti comandi:
|
1 2 |
rm nginx-conf/nginx.conf nano nginx-conf/nginx.conf |
Nel file ora vuoto nginx.conf, aggiungi il seguente codice che include un reindirizzamento da HTTP a HTTPS, ai protocolli di credenziali SSL e alle intestazioni di sicurezza. Come hai fatto in precedenza, sostituisci il example.com con il tuo dominio registrato:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com www.example.com; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Sicurezza-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # abilita strict transport security solo se ne comprendi le implicazioni location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
Nel primo blocco server che gestisce le richieste non protette utilizzando la porta 80, specifichiamo la webroot per le richieste di rinnovo di Certbot. Includiamo anche una direttiva di reindirizzamento che reindirizza le richieste HTTP a HTTPS.
Il secondo blocco server gestisce il traffico sicuro HTTPS in arrivo sulla porta 443. Come puoi vedere, abilitiamo anche SSL e HTTP2. HTTP/2 migliora le prestazioni del tuo server. Puoi leggere di più a riguardo nella documentazione ufficiale di Nginx su HTTP/2.
In questo blocco abbiamo anche specificato che Nginx includa i percorsi del certificato SSL e della chiave, oltre ai parametri di sicurezza consigliati da Certbot che curl ha salvato in nginx-conf/options-ssl-nginx.conf directory.
Gli header di sicurezza aggiuntivi servono a migliorare le valutazioni del tuo sito web su siti di test di sicurezza come Security Headers e SSL Labs. Puoi seguire i link su questi header per saperne di più: X-Frame-Options, Referrer Policy, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy. Abbiamo commentato l'header HTTP Strict Transport Security (HSTS). Sei libero di leggere informazioni sulla sua funzionalità di preload e decidere se desideri abilitarla.
Il resto delle direttive come root, index, e i blocchi location specifici per WordPress rimangono come discusso nello Passo 1. Ora puoi salvare e chiudere il file quando hai terminato le modifiche.
Ora che abbiamo abilitato il traffico HTTPS che utilizza la porta 443,, dobbiamo anche abilitare la porta nella definizione del servizio del server web. Inserisci il seguente comando per aprire il file docker-compose.yml con nano:
|
1 |
nano docker-compose.yml |
Nella sezione web server sotto l'opzione ports, aggiungi una mappatura per la porta 443 come evidenziato di seguito:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Il file docker-compose.yml completo dovrebbe ora apparire così:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
version: '3' services: #Servizio MySQL db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #Servizio codice applicazione WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Servizio Webserver Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #Servizio certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com #Volumi volumes: certbot-etc: app: dbdata: #Reti networks: app-network: driver: bridge |
Una volta confermato che tutto sia corretto, salva e chiudi il file. Successivamente, esegui il seguente comando per ricreare il servizio webserver:
|
1 |
docker-compose up -d --force-recreate --no-deps webserver |
|
1 |
docker-compose ps |
Ora che tutti i tuoi container sono in esecuzione, è possibile procedere con la configurazione di WordPress dall'interfaccia web.
Passaggio 6: Completa la configurazione di WordPress dall'interfaccia web
Naviga sul nome di dominio del tuo server per continuare l'installazione. Dovresti vedere la pagina iniziale di configurazione di WordPress. Ti invita a scegliere la tua lingua prima di continuare:
Scegli la tua lingua e fai clic su Continua per passare alla pagina successiva:
In questa pagina, inserisci il titolo del tuo sito web, scegli un nome utente memorabile e una password sicura. Si consiglia di non utilizzare Admin come nome utente per motivi di sicurezza. Inserisci la tua email e fai clic sul pulsante Installa WordPress per avviare l'installazione di WordPress.
Una volta completata l'installazione, verrai reindirizzato alla schermata di accesso dove inserirai il nome utente e la password che hai impostato. Quando inserisci le credenziali valide, dovresti essere in grado di vedere la tua bacheca di WordPress:
Ora hai installato WordPress con successo! Successivamente, devi seguire i passaggi per assicurarti che i certificati SSL si rinnoveranno automaticamente.
Passo 7: Configurazione del rinnovo automatico del certificato SSL
I certificati TLS/SSL di Let’s Encrypt sono validi solo per 90 giorni. Sta a te creare una configurazione di rinnovo automatico per assicurarti che non scadano. Puoi ottenere questo risultato creando uno script e pianificandolo con l'utility cron job. In questo passaggio, ti mostreremo come creare uno script che rinnoverà i certificati. Lo pianificheremo poi con l'utility cron job per eseguirlo periodicamente e rinnovare i certificati se si stanno avvicinando alla data di scadenza.
All'interno della directory del progetto wordpress_docker, apri uno script chiamato ssl_renewer.sh con nano:
|
1 |
nano ssl_renewer.sh |
Aggiungi il seguente codice allo script per gestire il rinnovo automatico e il ricaricamento della configurazione di Nginx. Ricorda di sostituire il nome utente evidenziato con il tuo nome utente non root:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose –ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
In questo script, assegniamo il binario docker-compose a una variabile chiamata COMPOSE. Includiamo anche l'opzione –ansi never che indica allo script di eseguire i comandi docker-compose senza caratteri di controllo ANSI. Inoltre, assegniamo il binario Docker a una variabile chiamata DOCKER.
Lo script si sposta quindi nella directory del nostro progetto wordpress_docker ed esegue i seguenti comandi:
docker-compose run: avvia il container certbot e sovrascrive il comando che avevamo fornito nella definizione del servizio certbot. Invece di eseguire il sottocomando certonly, esegue il sottocomando renew che rinnoverà i certificati SSL/TLS di Let’s Encrypt se sono in procinto di scadere.docker-compose kill: invia un segnale SIGHUP al containerwebserverper ricaricare le configurazioni di Nginx. Potresti voler dare un'occhiata a questo tutorial di Docker su come utilizzare l'immagine Docker ufficiale di Nginx.docker system prune: questo comando rimuove tutti i container e le immagini non utilizzati.
Salva e chiudi il file quando hai finito di modificare. Quindi, esegui il seguente comando per renderlo eseguibile:
|
1 |
chmod +x ssl_renewer.sh |
Dopo averlo reso eseguibile, apri il tuo file crontab di root per eseguire lo script periodicamente agli intervalli che specificheremo:
|
1 |
sudo crontab -e |
Il crontab ti chiede di scegliere il tuo editor preferito se è la prima volta che lo usi:
Scegli il tuo editor preferito e premi Invio per aprire il file. In fondo al file, aggiungi la seguente riga:
|
1 |
*/5 * * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Questo imposta l'intervallo a cinque minuti per consentirci di verificare se il nostro script di rinnovo funziona o meno. Abbiamo anche specificato un file di log che conterrà l'output del job: cron_docker.log.
Attendi cinque minuti e controlla il cron.log per vedere se lo script ha avuto successo con la richiesta di rinnovo:
|
1 |
tail -f /var/log/cron_docker.log |
Dovresti vedere qualcosa di simile allo screenshot qui sotto se le richieste hanno avuto successo:
Ora che abbiamo testato e confermato che funziona, puoi modificare il file crontab per specificare un rinnovo giornaliero. Ad esempio, potresti voler specificare che lo script venga eseguito ogni giorno alle 18:00. Per farlo, modifica l'ultima riga del crontab in modo che appaia così:
|
1 |
0 18 * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Inoltre, devi rimuovere il flag –dry-run dallo script ssl_renewer.sh per assicurarti che il rinnovo effettivo avvenga quando viene eseguito. Dovrebbe apparire così:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
Successivamente, salva e chiudi il file. Fatto questo, il cron job manterrà validi i tuoi script, rinnovandoli prima della fine dei 90 giorni.
Conclusione
Se sei arrivato fin qui nel tutorial, puoi considerarti un passo più vicino a diventare un DevOps Engineer. Sei stato in grado di creare uno script di configurazione Nginx, hai creato un file docker-compose.yml e definito diversi servizi necessari per eseguire un'applicazione WordPress con Docker e Docker Compose. Hai ottenuto i certificati SSL/TLS da Let’s Encrypt per assicurarti che il tuo server web sia sicuro. Infine, hai creato un cron job per garantire che i certificati non scadano. Ottimo lavoro!
Se stai cercando di approfondire il DevOps, dai un'occhiata ad altre risorse sui container dal nostro blog:
- Conoscere Kubernetes
- Come distribuire un'app Node.js (Express.js) con Docker su Ubuntu 20.04
- Distribuire un'applicazione PHP su un cluster Kubernetes con Ubuntu 18.04.
- Distribuire Laravel, Nginx e MySQL con Docker Compose
Buona programmazione!










Commenti
Ancora nessun commento. Scrivi il primo.