Simone Foschi, socio del RiminiLUG, ha pubblicato sul suo blog un interessante articolo intitolato

Come ho creato un reverse proxy nginx per wordpress con docker

Come creare un Reverse Proxy Nginx con configurazione automatizzata con docker
Simo 2020/4/19

updated 2020/4/19

Era un bel po’ di tempo che stavo pensando a come configurare il mio server web in maniera da rimanere su una mia VPS in sicurezza e con le tecnologie più moderne.

Pensa che ti ripensa, mumble mumble, tramite le considerazioni qui sotto, sono arrivato a realizzare ad un progetto moderno e facile da gestire.

Le considerazioni che mi hanno portato all’ideazione del sistema

Un Reverse Proxy Nginx è una particolare configurazione di Nginx per permettere ad un server di rispondere tramite un solo componente alle richieste esterne, appunto Nginx.

Questo garantisce che i componenti sottostanti del web server non siano interfacciati direttamente su internet e che quindi un attaccante abbia un superfice d’attacco molto minore rispetto all’interfacciarsi direttamente con il web server dei rispettivi siti su internet.

Docker invece è un moderno sistema di containerizzazione che permette di creare dei servizi atomici dentro a dei container senza aver bisogno di modificare la configurazione e le librerie della macchina host.

Docker è inoltre facilmente trasportabile da una macchina ad un’altra e nel caso di carichi elevati è possibile tramite kubernetes distribuire il carico aggiungendo macchine, il che fa di esso un sistema scalabile in maniera abbastanza semplice.

Fatte queste considerazioni ho fatto qualche ricerca su internet in maniera da trovare qualcosa che mi aiutasse a chiarire i miei dubbi e perché no, qualcosa di pronto all’uso dato che non avevo idea di come gestire il tutto.

Considerazioni su docker tra i soci

È molto tempo che coi soci del RiminiLUG si parla di Docker e ci siamo posti questioni di sicurezza, come al solito, trovando e condividendo tra noi articoli con diverse opinioni.

Alla fine quello che è venuto fuori è che ci sono alcune configurazioni sicure ed altre con più vulnerabilità.

Ad esempio in questo articolo che Roberto ci ha girato, si fa riferimento alle vulnerabilità delle singole immagini di base, ma fa anche notare che con alcune immagini base ci sono molte vulnerabilita, mentre con l’immagine base di Nodejs Alpine Linux ce ne sono 0.

Io quindi mi sono basato su queste considerazioni per creare un sistema con base Nginx su Alpine Linux in maniera da avere una superfice d’attacco molto più ridotta rispetto ad un sistema che comprendesse distribuzioni più complesse e affette da vulnerabilità come Ubuntu o Debian.

Per chi non lo sapesse Alpine Linux è una distribuzione minimale che pesa solo 5 MB, creata tenendo ben presente il problema della sicurezza e di conseguenza riduce al minimo la superfice d’attacco avendo meno componenti di altre distribuzioni.

Si parte

Ho trovato quasi subito questo articolo dove appunto si parla di come creare una configurazione di docker-compose per istanziare un Reverse Proxy Nginx per dei siti WordPress.

La particolarità di questo sistema è che aggiungendo container con siti web, crea in automatico la configurazione e a me non rimane che istanziare con i parametri corretti un docker compose e il sistema mi crea in automatico oltre che la configurazione, anche i certificati https.

Ma nel cercare di farlo simile alla mia idea, ad un certo punto non partiva più.

Quindi ho chiesto aiuto a Matteo ed una sera che ci siamo ritrovati al consueto appuntamento settimanale del martedì all’associazione, mi ha fatto procedere dall’inizio seguendo questa guida sul wiki ufficiale di Nginx Let’s Encrypt Proxy Companion.

Tra l’altro ho chiesto anche su stackoverflow ed il mio errore era quello di istanziare due volte docker-gen.

Una volta istanziando direttamente il container docker-gen, l’altra istanziando il container nginx-proxy che al suo interno contiene docker-gen, quando invece dovevo istanziare l’immagine nginx:alpine, come riportato nella configurazione sottostante.

Configurare il server

Come server, su consiglio di Giuseppe che l’ha scoperto e Matteo ho usato contabo.com, che oltre ad essere economico è anche un buonissimo hosting.

Per la cifra ridicola di 3 euro e 99 al mese — al momento attuale –, offre un VPS con 4 Gb di RAM e 300 Gb di hard disk SSD boosted.

Come sistema di base ho usato Ubuntu 18.04 LTS.

Per iniziare mi sono creato le chiavi ssh con ssh-keygen sul mio computer locale e una volta che ho avuto accesso al VPS creato su contabo ho caricato la cartella ~/.ssh tramite filezilla nella cartella principale dell’utente root.

Poi sempre come root, una dopo aver acceduto tramite ssh al server, l’ho configurato in questa maniera:

1  adduser TUO-USERNAME
2  usermod -aG sudo TUO-USERNAME
3  rsync --archive --chown=TUO-USERNAME:TUO-USERNAME ~/.ssh /home/TUO-USERNAME
4  # Aggiorno il sistema
5  apt update && apt upgrade && apt dist-upgrade && apt autoremove && apt autoclean
6  apt install --install-recommends linux-generic-hwe-18.04
7  # Installo fail2ban
8  apt install fail2ban
9  # Aggiorno il sistema
10 apt update && apt upgrade && apt dist-upgrade && apt autoremove && apt autoclean
11 # Installo docker e docker-compose
12 curl -fsSL https://get.docker.com -o get-docker.sh
13 sh get-docker.sh
14 usermod -aG docker TUO-USERNAME
15 apt install docker-compose -y

Quindi mi sono preoccupato di creare i domini di test su duckdns e sul server li ho abilitati così:

1  mkdir duckdns
2  cd duckdns
3  nano TUO-DOMINIO.sh
4  # ci ho incollato dentro questa stringa
5  echo url="https://www.duckdns.org/update?domains=TUO-DOMINIO&token=xxxx-xxxx-xxxx-xxxx&ip=" | curl -k -o ~/duckdns/TUO-DOMINIO.log -K -
6  # CTRL-X INVIO
7  chmod 700 TUO-DOMINIO.sh
8  crontab -e
9  # ci ho incollato dentro questa stringa
10 */5 * * * * ~/duckdns/TUO-DOMINIO.sh >/dev/null 2>&1
11 # CTRL-X INVIO
12 ./TUO-DOMINIO.sh

Voi dovete sostituire TUO-DOMINIO con i vostri domini duckdns.org e la stringa xxxx…. con il vostro token. Comunque la procedura corretta è visibile nella parte install del sito di duckdns

Quando ho messo in produzione i siti ho puntato i dns dei domini all’IP della macchina di produzione.

La configurazione sopra serve per fare i test che tutto funzioni a dovere prima di mandare in produzione i siti.

Configurare docker

Per iniziare ho creato un network nel quale far girare i container docker con questo comando:

docker network create nginx-proxy

Quindi ho creato la struttura delle cartelle e siccome erano da trasferire avevo i miei due siti WordPress da trasferire, all’interno delle rispettive cartelle ho caricato la cartella wp-content dei due siti:

- /home/TUO-USERNAME/
  - nginx-proxy/
    - wordpress1/
      - wp-content/
    - wordpress2/
      - wp-content/

Poi ho seguito il wiki di nginx-proxy-letsencrypt-companion, ho usato il three-container setup creando un file docker-compose.yml nella directory nginx-proxy:

version: '2'
services:
nginx-proxy:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs:ro
    network_mode: bridge
  docker-gen:
    image: jwilder/docker-gen
    container_name: nginx-proxy-gen
    command: -notify-sighup nginx-proxy -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    volumes_from:
      - nginx-proxy
    volumes:
      - /path/to/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.docker_gen"
    network_mode: bridge
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-proxy-le
    volumes_from:
      - nginx-proxy
    volumes:
      - certs:/etc/nginx/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    network_mode: bridge
volumes:
  conf:
  vhost:
  html:
  certs:

Quindi dentro le cartelle wordpress1 e wordpress2 ho creato un docker-compose.yml in ogni cartella con questo contenuto:

version: "3"
services:
  db_node_domain:
    image: mariadb:10.4
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: MY-SECRET-PASSWORD
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: MY-SECRET-PASSWORD
    container_name: example_db
  example:
    depends_on:
      - db_node_domain
    image: wordpress:latest
    expose:
      - 443
    restart: always
    environment:
      VIRTUAL_HOST: www.example.com,example.com
      WORDPRESS_DB_HOST: db_node_domain:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: MY-SECRET-PASSWORD
      LETSENCRYPT_HOST: www.example.com,example.com
      LETSENCRYPT_EMAIL: myemail@example.com
    container_name: example
    volumes:
      - data_volume:/var/www/html
      - ./home/wp:/home/wp
      - ./wp-content:/var/www/html/wp-content
volumes:
  db_data:
  data_volume:
networks:
  default:
    external:
      name: nginx-proxy

Voi dovete cambiare rispettivamente “example” con il nome del vostro sito, “MY-SECRET-PASSWOWRD” con password sicure, una per root e una per l’utente di mariadb e l’email con cui richiedere il certificato https.

Quindi dentro le cartelle dove ho creato i file docker-compose.yml ho eseguito:

docker-compose up

Importante

docker-compose up vi permette di vedere i log ma vi occupa un terminale e quindi dovrete aprire tre termninali in ssh sul server per lanciare i vostri siti di test.
Una volta che avrete completato i test sui log e che tutto funziona dovrete fare ctrl-c su ogni terminale per terminare i container e lanciare il comando

docker-compose up -d

nelle rispettive cartelle.
Per stoppare i container per la manutenzione basterà dare il seguente comando sempre nelle rispettive cartelle:

docker-compose stop

e rilanciare successivamente sempre con

docker-compose up -d

Per finire

Quindi, dopo i test che tutto funzionasse a dovere, ho dovuto fare la procedura del trasferimento dei db dal vecchio MySQL al server attuale tramite un plugin WordPress che si chiama UpdraftPlus in modalità gratuita, modificare i docker-compose.yml dei due siti WordPress per inserire i domini corretti e puntare il DNS dei domini di produzione.

Ringraziamenti

Grazie per l’ennesima volta al RiminiLUG per tutto il supporto che mi hanno dato i soci e per avermi fatto risparmiare molti soldi grazie al consiglio di creare un VPS su contabo.

— Buona vita —

Più siti in un solo dispositivo, Simone e la sua sfida con Docker