Introduzione

WordPress è un sistema di gestione dei contenuti (CMS) gratuito e open source basato su un database MySQL con elaborazione PHP.

L'esecuzione di WordPress comporta in genere l'installazione di uno stack LAMP (Linux, Apache, MySQL e PHP) o LEMP (Linux, Nginx, MySQL e PHP). Utilizzando strumenti come Docker e Docker Compose, è possibile semplificare il processo di impostazione dello stack preferito e l'installazione di WordPress. Invece di installare manualmente singoli componenti, è possibile utilizzare immagini che standardizzano elementi come librerie, file di configurazione e variabili di ambiente ed eseguono queste immagini in contenitori, processi isolati eseguiti su un sistema operativo condiviso. Inoltre, utilizzando Compose, è possibile coordinare più contenitori, ad esempio un'applicazione e un database, per comunicare tra loro.

In questo tutorial, creerai un'installazione WordPress multi-contenitore su Ubuntu 20.04 LTS. I contenitori includeranno un database MySQL, un server Web Nginx e lo stesso WordPress. Proteggerai anche la tua installazione ottenendo certificati TLS/SSL con Let's Encrypt per il dominio che vuoi associare al tuo sito. Infine, imposterai un cron per rinnovare i tuoi certificati in modo che il tuo dominio rimanga sicuro.

Prerequisiti

Per seguire questo tutorial, avrai bisogno di:

Configurazione di Nginx

Prima di eseguire qualsiasi container, il nostro primo passo sarà definire la configurazione per il nostro server Web Nginx. Il nostro file di configurazione includerà alcuni blocchi di posizione specifici di WordPress e per le richieste di verifica Let's Encrypt al client Certbot per il rinnovo automatico dei certificati.

Innanzitutto, crea una directory di progetto per la tua configurazione di WordPress con il comando mkdir chiamata wordpress e naviga verso di essa con il comando cd:

mkdir wordpress && cd wordpress

Quindi, crea una directory per il file di configurazione:

mkdir nginx-conf

Apri il file con nano o il tuo editor preferito:

nano nginx-conf/nginx.conf

In questo file, aggiungeremo un blocco server con direttive per il nome del nostro server e root del documento e blocchi posizione per indirizzare la richiesta del client Certbot per certificati, elaborazione PHP e richieste di risorse statiche.

Incolla il seguente codice nel file. Assicurati di sostituire example.com con il tuo nome di dominio:

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 wordpress: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;
        }
}
~/wordpress/nginx-conf/nginx.conf

Il nostro blocco server include le seguenti informazioni:

Direttive:

  • listen: Questo dice a Nginx di ascoltare sulla porta 80, il che ci permetterà di usare il plugin webroot di Certbot per le nostre richieste di certificati. Tieni presente che non stiamo ancora includendo la porta 443: aggiorneremo la nostra configurazione per includere SSL una volta ottenuti con successo i nostri certificati.
  • server_name: Definisce il nome del server e il blocco server che devono essere utilizzati per le richieste al server. Assicurati di sostituire example.com in questa riga con il tuo nome di dominio.
  • index: La direttiva index definisce i file che verranno utilizzati come indici durante l'elaborazione delle richieste al server.
  • root: La direttiva root nomina la directory principale per le richieste al nostro server. Questa directory, /var/www/html viene creata come punto di montaggio al momento della compilazione dalle istruzioni nel nostro Dockerfile di WordPress. Queste istruzioni di Dockerfile assicurano inoltre che i file della versione di WordPress siano montati su questo volume.

Blocchi Location:

  • location ~ /.well-known/acme-challenge: Questo blocco di posizione gestirà le richieste alla directory .well-known, dove Certbot inserirà un file temporaneo per convalidare la risoluzione del DNS per il nostro dominio sul nostro server.
  • location /: In questo blocco posizione, utilizzeremo una direttiva try_files per verificare la presenza di file che corrispondono alle singole richieste URI. Invece di restituire uno stato 404 Not Found come predefinito, passeremo il controllo al file index.php di WordPress con gli argomenti della richiesta.
  • location ~ \.php$: Questo blocco di posizione gestirà l'elaborazione PHP e inoltrerà queste richieste al nostro contenitore wordpress.
  • location ~ /\.ht: Questo blocco gestirà i file .htaccess poiché Nginx non li servirà. La direttiva deny_all garantisce che i file .htaccess non verranno mai utilizzati dagli utenti.
  • location = /favicon.ico, location = /robots.txt: Questi blocchi assicurano che le richieste da /favicon.ico e /robots.txt non verranno registrate.
  • location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: Questo blocco disattiva la registrazione per le richieste di risorse statiche e garantisce che queste risorse siano altamente memorizzabili nella cache.

Salvare e chiudere il file al termine della modifica. Se è stato utilizzato nano, fare premendo CTRL+X, Y, quindi ENTER.

Definire le variabili di ambiente

Il tuo database e i contenitori di applicazioni WordPress dovranno accedere a determinate variabili di ambiente in fase di esecuzione affinché i dati dell'applicazione persistano e siano accessibili alla tua applicazione.

Invece di impostare tutti i valori nel nostro file Compose Docker (il file principale che contiene informazioni su come verranno eseguiti i nostri contenitori) possiamo impostare i valori sensibili in un file .env. Ciò impedirà a questi valori di essere copiati nei repository dei nostri progetti e di essere esposti pubblicamente.

Nella directory principale del progetto ~/wordpress, crea un file chiamato .env:

nano .env

I valori che imposteremo in questo file includono una password per il nostro utente root MySQL, un nome utente e una password che WordPress utilizzerà per accedere al database.

Aggiungi i seguenti nomi e valori di variabili al file. Ricorda di fornire qui i tuoi valori per ogni variabile:

MYSQL_ROOT_PASSWORD=root_password
MYSQL_USER=wp_user
MYSQL_PASSWORD=wp_db_password
~/wordpress/.env

Abbiamo incluso una password per l'account amministrativo di root , nonché il nostro nome utente e la password preferiti per il nostro database dell'applicazione.

Salvare e chiudere il file al termine della modifica.

Poiché il tuo file .env contiene informazioni riservate, dovrai assicurarti che sia incluso nei tuoi progetti all'interno dei file file .gitignore e .dockerignore, che indicano a Git e Docker quali file non copiare rispettivamente nei tuoi repository Git e nelle immagini Docker.

Se hai intenzione di lavorare con Git per il controllo della versione, inizializza la tua directory di lavoro corrente come repository con git init:

git init

Quindi apri un file .gitignore:

nano .gitignore

Aggiungi .env all'interno del file:

.env
~/wordpress/.gitignore

Salvare e chiudere il file al termine della modifica.

Allo stesso modo, è una buona precauzione aggiungere .env a un file .dockerignore, in modo che non finisca nei contenitori quando si utilizza questa directory come contesto di compilazione.

Apri il file:

nano .dockerignore

Aggiungi .env all'interno del file:

.env
~/wordpress/.dockerignore

Puoi facoltativamente aggiungere file e directory associati allo sviluppo della tua applicazione:

.env
.git
docker-compose.yml
.dockerignore
~/wordpress/.dockerignore

Salva e chiudi il file al termine.

Definire i servizi con Docker Compose

Il file docker-compose.yml conterrà le definizioni di servizio per la configurazione. Un servizio in Compose è un contenitore in esecuzione e le definizioni del servizio specificano le informazioni su come verrà eseguito ciascun contenitore.

Utilizzando Compose, è possibile definire diversi servizi per eseguire applicazioni multi-contenitore.

Per iniziare, apri il file docker-compose.yml:

nano docker-compose.yml

Aggiungi il seguente codice per definire la versione del tuo file Compose e il servizio database db:

version: '3'

services:
  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/docker-compose.yml

La definizione db del servizio contiene le seguenti opzioni:

  • image: Questo dice a Compose quale immagine utilizzare per creare il contenitore.
  • container_name: Specifica un nome per il contenitore.
  • restart: Definisce il criterio di riavvio del contenitore. L'impostazione predefinita è no, ma abbiamo impostato il riavvio del contenitore a meno che non venga arrestato manualmente.
  • env_file: Questa opzione dice a Compose che vorremmo aggiungere variabili d'ambiente da un file chiamato .env, situato nel nostro contesto di compilazione. In questo caso, il contesto di compilazione è la nostra directory corrente.
  • environment: Questa opzione consente di aggiungere ulteriori variabili di ambiente, oltre a quelle definite nel file .env. Imposteremo la variabile MYSQL_DATABASE uguale a wordpress per fornire un nome per il nostro database dell'applicazione. Poiché si tratta di informazioni non sensibili, possiamo includerle direttamente nel file docker-compose.yml.
  • volumes: Qui, stiamo montando un volume con nome chiamato dbdata nella directory /var/lib/mysql sul contenitore. Questa è la directory di dati standard per MySQL sulla maggior parte delle distribuzioni.
  • command: Questa opzione specifica un comando per sovrascrivere l'istruzione CMD predefinita per l'immagine. Nel nostro caso, aggiungeremo un'opzione al comando mysqld standard dell'immagine Docker , che avvia il server MySQL sul contenitore. Questa opzione, --default-authentication-plugin=mysql_native_password imposta la variabile di sistema --default-authentication-plugin su mysql_native_password, specificando quale meccanismo di autenticazione dovrebbe usare le nuove richieste di autenticazione al server.
  • networks: Questo specifica che il nostro servizio applicativo si unirà alla rete app-network, che definiremo in fondo al file.

Successivamente, sotto la definizione del servizio db, aggiungere la definizione per il servizio dell'applicazione wordpress:

...
  wordpress:
    depends_on: 
      - db
    image: wordpress:5.4.2-fpm-alpine
    container_name: wordpress
    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:
      - wordpress:/var/www/html
    networks:
      - app-network
~/wordpress/docker-compose.yml

Qui stiamo definendo il servizio wordpress. Stiamo anche aggiungendo alcune opzioni specifiche per questo contenitore:

  • depends_on: Questa opzione garantisce che i nostri contenitori inizieranno in ordine di dipendenza, con il contenitore wordpress che inizia dopo il contenitore db.
  • image: Per questa configurazione, stiamo usando l'immagine di WordPress 5.4.2-fpm-alpine. L'utilizzo di questa immagine garantisce che la nostra applicazione disponga del processore php-fpm richiesto da Nginx per gestire l'elaborazione PHP.
  • env_file e environment: Ancora una volta, specifichiamo che vogliamo estrarre i valori dal nostro file .env, poiché è qui che abbiamo definito l'utente e la password del nostro database dell'applicazione.
  • volumes: Stiamo montando un volume chiamato wordpress sul mountpoint /var/www/html creato dall'immagine WordPress. L'uso di un volume con nome ci consentirà di condividere il nostro codice dell'applicazione con altri contenitori.
  • networks: Stiamo anche aggiungendo il contenitore wordpress alla rete app-network.

Successivamente, sotto la definizione del servizio applicazione wordpress, aggiungi la seguente definizione per il tuo servizio Nginx webserver:

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.19.1-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network
~/wordpress/docker-compose.yml

Qui stiamo definendo il servizio webserver per Nginx.

Questa definizione di servizio include anche le seguenti opzioni:

  • ports: Questo espone la porta 80 per abilitare le opzioni di configurazione che abbiamo definito nel nostro file nginx.conf.
  • volumes: Qui, stiamo definendo una combinazione di volumi con nome e montaggi di bind.
  • certbot-etc:/etc/letsencrypt: In questo modo i certificati e le chiavi Let's Encrypt pertinenti per il nostro dominio verranno montati nella directory appropriata sul contenitore.

Abbiamo aggiunto anche questo contenitore alla rete app-network.

Infine, sotto la tua definizione webserver, aggiungi l'ultima definizione di servizio per il servizio certbot. Assicurati di sostituire l'indirizzo email e i nomi di dominio elencati qui con le tue informazioni:

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com
~/wordpress/docker-compose.yml

Questa definizione dice a Compose di estrarre l'immagine certbot/certbot dall'hub Docker. Utilizza anche i volumi con nome per condividere le risorse con il contenitore Nginx, inclusi i certificati di dominio, la chiave certbot-etc e il codice dell'applicazione wordpress.

Ancora una volta, abbiamo usato depends_on per specificare che il contenitore certbot dovrebbe essere avviato una volta che il servizio webserver è in esecuzione.

Abbiamo anche incluso command un'opzione che specifica un sottocomando da eseguire con il comando certbot predefinito del contenitore . Il sottocomando certonly otterrà un certificato con le seguenti opzioni:

  • --webroot: Questo dice a Certbot di usare il plugin webroot per posizionare i file nella cartella webroot per l'autenticazione.
  • --webroot-path: Specifica il percorso della directory webroot.
  • --email: La tua email preferita per la registrazione e il recupero.
  • --agree-tos: Specifica che si accetta il Contratto di abbonamento ACME.
  • --no-eff-email: Questo dice a Certbot che non desideri condividere la tua e-mail con Electronic Frontier Foundation (EFF). Sentiti libero di ometterlo se preferisci.
  • --staging: Questo indica a Certbot che si desidera utilizzare l'ambiente di gestione temporanea Let's Encrypt per ottenere certificati di prova. L'utilizzo di questa opzione consente di testare le opzioni di configurazione ed evitare possibili limiti di richiesta del dominio.
  • -d: Questo ti consente di specificare i nomi di dominio che desideri applicare alla tua richiesta. In questo caso, abbiamo incluso example.com e www.example.com. Assicurati di sostituirli con il tuo dominio.

Sotto la definizione del servizio certbot, aggiungi le definizioni di rete e volume:

...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  
~/wordpress/docker-compose.yml

Il nostro primo livello volumes definisce i volumi certbot-etc, wordpress e dbdata. Quando Docker crea volumi, i contenuti del volume vengono archiviati in una directory sul filesystem host, /var/lib/docker/volumes/ gestita da Docker. Il contenuto di ciascun volume viene quindi montato da questa directory a qualsiasi contenitore che utilizza il volume. In questo modo, è possibile condividere codice e dati tra contenitori.

La rete bridge definita dall'utente app-network consente la comunicazione tra i nostri container poiché si trovano sullo stesso host daemon Docker. Ciò semplifica il traffico e la comunicazione all'interno dell'applicazione, in quanto apre tutte le porte tra i contenitori sulla stessa rete bridge senza esporre alcuna porta al mondo esterno. Così, i nostri contenitori db, wordpresse webserver possono comunicare tra loro, e abbiamo solo bisogno di esporre la porta 80 di accesso front-end per l'applicazione.

Il file docker-compose.yml finito sarà simile al seguente:

version: '3'

services:
  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:
    depends_on: 
      - db
    image: wordpress:5.4.2-fpm-alpine
    container_name: wordpress
    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:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.19.1-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  
~/wordpress/docker-compose.yml

Salvare e chiudere il file al termine della modifica.

Ottenere certificati e credenziali SSL

Possiamo avviare i nostri contenitori con il comando docker-compose up, che creerà ed eseguirà i nostri contenitori nell'ordine specificato. Se le richieste del nostro dominio hanno esito positivo, vedremo lo stato di uscita corretto nel nostro output e i certificati corretti montati nella cartella /etc/letsencrypt/live sul contenitore webserver.

Creare i contenitori con il comando docker-compose up e il flag -d, verranno eseguiti in background i contenitori db, wordpress e webserver:

docker-compose up -d

Vedrai un output che conferma che i tuoi servizi sono stati creati:

Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot   ... done

Utilizzando il comando docker-compose ps, controlla lo stato dei tuoi servizi:

docker-compose ps

Dovresti visualizzare un output simile al seguente, con i servizi db, wordpress e webserver con stato Up e il container certbot con un messaggio di stato 0:

  Name                 Command               State           Ports
-------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp
webserver   /docker-entrypoint.sh ngin ...   Up       0.0.0.0:80->80/tcp
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp

Se vedete qualcosa di diverso da Up nella colonna State per i servizi db, wordpress o webserver, o uno stato di uscita diverso da quello 0 per il contenitore certbot, assicurati di controllare i registri di servizio con il comando docker-compose logs:

docker-compose logs service_name

Ora puoi verificare che i tuoi certificati siano stati montati sul contenitore webserver con il comando docker-compose exec:

docker-compose exec webserver ls -la /etc/letsencrypt/live

Se le richieste di certificato hanno avuto esito positivo, vedrai un output in questo modo:

drwx------    3 root     root          4096 Jul 23 14:34 .
drwxr-xr-x    9 root     root          4096 Jul 23 14:34 ..
-rw-r--r--    1 root     root           740 Jul 23 14:34 README
drwxr-xr-x    2 root     root          4096 Jul 23 14:34 example.com

Ora che sai che la tua richiesta avrà esito positivo, puoi modificare la definizione del servizio certbot rimuovendo il flag --staging.

Aperto docker-compose.yml:

nano docker-compose.yml

Trova la sezione del file con la definizione del servizio certbot e sostituisci il flag --staging con il flag --force-renewal, che dirà a Certbot che vuoi richiedere un nuovo certificato con gli stessi domini di un certificato esistente. Il risultato sarà il seguente:

...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email noviell[email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
~/wordpress/docker-compose.yml

Ora puoi eseguire docker-compose up per ricreare il contenitore certbot. Includeremo anche l'opzione --no-deps per dire a Compose che può saltare l'avvio del servizio webserver, poiché è già in esecuzione:

docker-compose up --force-recreate --no-deps certbot

Verrà visualizzato un output che indica che la richiesta di certificato è stata eseguita correttamente:

Recreating certbot ... done
Attaching to certbot
certbot      | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot      | Plugins selected: Authenticator webroot, Installer None
certbot      | Renewing an existing certificate
certbot      | Performing the following challenges:
certbot      | http-01 challenge for example.com
certbot      | http-01 challenge for www.example.com
certbot      | Using the webroot path /var/www/html for all unmatched domains.
certbot      | Waiting for verification...
certbot      | Cleaning up challenges
certbot      | IMPORTANT NOTES:
certbot      |  - Congratulations! Your certificate and chain have been saved at:
certbot      |    /etc/letsencrypt/live/example.com/fullchain.pem
certbot      |    Your key file has been saved at:
certbot      |    /etc/letsencrypt/live/example.com/privkey.pem
certbot      |    Your cert will expire on 2020-10-21. To obtain a new or tweaked
certbot      |    version of this certificate in the future, simply run certbot
certbot      |    again. To non-interactively renew *all* of your certificates, run
certbot      |    "certbot renew"
certbot      |  - Your account credentials have been saved in your Certbot
certbot      |    configuration directory at /etc/letsencrypt. You should make a
certbot      |    secure backup of this folder now. This configuration directory will
certbot      |    also contain certificates and private keys obtained by Certbot so
certbot      |    making regular backups of this folder is ideal.
certbot      |  - If you like Certbot, please consider supporting our work by:
certbot      |
certbot      |    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
certbot      |    Donating to EFF:                    https://eff.org/donate-le
certbot      |
certbot exited with code 0

Con i certificati in atto, puoi passare alla modifica della configurazione di Nginx per includere SSL.

Modificare la configurazione del server Web e della definizione del servizio

L'abilitazione di SSL nella nostra configurazione Nginx implica l'aggiunta di un reindirizzamento HTTP a HTTPS, la specifica del nostro certificato SSL e le posizioni delle chiavi e l'aggiunta di parametri e intestazioni di sicurezza.

Interrompere il servizio webserver per includere queste aggiunte:

docker-compose stop webserver

Prima di modificare il file di configurazione stesso, otteniamo innanzitutto i parametri di sicurezza Nginx consigliati da Certbot usando il comando curl:

curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf

Questo comando salverà questi parametri in un file chiamato options-ssl-nginx.conf, situato nella directory nginx-conf.

Quindi, rimuovere il file di configurazione Nginx creato in precedenza:

rm nginx-conf/nginx.conf

Apri un'altra versione del file:

nano nginx-conf/nginx.conf

Aggiungi il seguente codice al file per reindirizzare HTTP a HTTPS e per aggiungere credenziali SSL, protocolli e intestazioni di sicurezza. Ricorda di sostituire example.com con il tuo dominio:

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-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
        # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        # enable strict transport security only if you understand the implications

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress: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;
        }
}
~/wordpress/nginx-conf/nginx.conf

Il blocco del server HTTP specifica il webroot per le richieste di rinnovo di Certbot nella directory .well-known/acme-challenge. Include anche una direttiva di riscrittura che indirizza le richieste HTTP alla directory principale su HTTPS.

Il blocco server HTTPS abilita ssl e http2.

Questo blocco include anche il nostro certificato SSL e le posizioni delle chiavi, insieme ai parametri di sicurezza Certbot consigliati che abbiamo salvato nel file nginx-conf/options-ssl-nginx.conf.

Inoltre, abbiamo incluso alcune intestazioni di sicurezza che ci consentiranno di ottenere classificazioni A su siti test di sicurezza.

Anche la nostra root e le direttive index si trovano in questo blocco, così come il resto dei blocchi di posizione specifici di WordPress.

Al termine della modifica, salva e chiudi il file.

Prima di ricreare il servizio webserver, sarà necessario aggiungere la porta 443 alla definizione del servizio webserver.

Apri il tuo file docker-compose.yml:

nano docker-compose.yml

Nella definizione del servizio webserver, aggiungere il seguente mapping delle porte:

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.19.1-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network
~/wordpress/docker-compose.yml

Il file docker-compose.yml apparirà così al termine:

version: '3'

services:
  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:
    depends_on: 
      - db
    image: wordpress:5.4.2-fpm-alpine
    container_name: wordpress
    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:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.19.1-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  
~/wordpress/docker-compose.yml

Salvare e chiudere il file al termine della modifica.

Ricrea il servizio webserver:

docker-compose up -d --force-recreate --no-deps webserver

Controlla i tuoi servizi con il comando docker-compose ps:

docker-compose ps

Si dovrebbe vedere un messaggio di output che indica che i tuoi servizi db, wordpress e webserver sono in esecuzione:

  Name                 Command               State                     Ports
----------------------------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp
webserver   /docker-entrypoint.sh ngin ...   Up       0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp

Con i container in esecuzione, ora puoi completare l'installazione di WordPress attraverso l'interfaccia web.

Completare l'installazione tramite l'interfaccia Web

Con i nostri container in esecuzione, possiamo completare l'installazione tramite l'interfaccia web di WordPress.

Nel tuo browser, collegati al dominio del tuo server. Ricorda di sostituire example.com qui con il tuo nome di dominio:

https://example.com

Seleziona la lingua che desideri utilizzare.

Dopo aver fatto clic su Continua , accederai alla pagina di configurazione principale, dove dovrai scegliere un nome per il tuo sito e un nome utente.

Infine, dovrai inserire il tuo indirizzo e-mail e decidere se vuoi scoraggiare o meno i motori di ricerca dall'indicizzazione del tuo sito.

Fai clic su Installa WordPress nella parte inferiore della pagina per accedere.

Una volta effettuato l'accesso, avrai accesso alla dashboard di amministrazione di WordPress.

Rinnovare i certificati

I certificati di Let's Encrypt sono validi per 90 giorni, quindi ti consigliamo di impostare un processo di rinnovo automatico per garantire che non scadano. Un modo per farlo è quello di creare un cronjob l'utilità di pianificazione cron. In questo caso, creeremo un cron per eseguire periodicamente uno script che rinnoverà i nostri certificati e ricaricherà la nostra configurazione Nginx.

Innanzitutto, apri uno script chiamato ssl_renew.sh:

nano ssl_renew.sh

Aggiungi il seguente codice allo script per rinnovare i certificati e ricaricare la configurazione del tuo server web. Ricorda di sostituire il nome utente di esempio qui con il tuo nome utente non root:

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/noviello/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
~/wordpress/ssl_renew.sh

Chiudi il file al termine della modifica. Rendilo eseguibile con il comando chmod:

chmod +x ssl_renew.sh

Quindi, apri il tuo file crontab per eseguire lo script di rinnovo a un intervallo specificato:

sudo crontab -e 

Se è la prima volta che modifichi questo file, ti verrà chiesto di scegliere un editor:

no crontab for root - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]:
...

Nella parte inferiore del file, aggiungi la seguente riga:

*/5 * * * * /home/noviello/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
crontab

Ciò imposterà l'intervallo del cron ogni cinque minuti, in modo da poter verificare se la richiesta di rinnovo ha funzionato o meno come previsto. Abbiamo anche creato un file di registro cron.log per registrare l'output pertinente dal lavoro.

Dopo cinque minuti, controlla cron.log se la richiesta di rinnovo è riuscita o meno:

tail -f /var/log/cron.log

Dovresti vedere l'output che conferma un rinnovo riuscito:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Ora puoi modificare il file crontab per impostare un intervallo giornaliero. Per eseguire lo script ogni giorno a mezzogiorno, ad esempio, è necessario modificare l'ultima riga del file in questo modo:

0 12 * * * /home/noviello/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
crontab

Dovrai anche rimuovere l'opzione --dry-run dal tuo script ssl_renew.sh:

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/noviello/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
~/wordpress/ssl_renew.sh

Il tuo cron assicurerà che i tuoi certificati Let's Encrypt non scadano rinnovandoli quando sono idonei.

Conclusione

In questo tutorial, è stato utilizzato Docker Compose per creare un'installazione WordPress con un server Web Nginx su Ubuntu 20.04 LTS Focal Fossa. Abbiamo anche visto come ottnere i certificati TLS/SSL per il dominio che desideri associare al tuo sito WordPress. Inoltre, è stato creato un cron per rinnovare questi certificati quando necessario.