3 Commits
Author SHA1 Message Date
r.didato 69ab1c94b1 Fix env staging 2026-07-12 23:25:46 +02:00
r.didato b550cbda4a aggiornato docker compose v2 2026-07-12 23:15:36 +02:00
r.didato 2ef1efe1c9 Aggiunto letsencrypt 2026-07-12 23:00:46 +02:00
8 changed files with 245 additions and 14 deletions
+1 -1
View File
@@ -4,4 +4,4 @@ DDNINJA_IS_PRODUCTION=false
DDNINJA_MONGO_DBNAME=fdn2_test
DDNINJA_MONGO_LOCATION=mongo
DDNINJA_PUBLIC_URL=http://test.ifattidinapoli.it
DDNINJA_PUBLIC_URL=https://test.ifattidinapoli.it
+1 -1
View File
@@ -4,4 +4,4 @@ DDNINJA_IS_PRODUCTION=false
DDNINJA_MONGO_DBNAME=fdn2_test
DDNINJA_MONGO_LOCATION=mongo
DDNINJA_PUBLIC_URL=http://test.ifattidinapoli.it
DDNINJA_PUBLIC_URL=https://test.ifattidinapoli.it
+2
View File
@@ -0,0 +1,2 @@
# Dati Let's Encrypt gestiti da certbot: contengono chiavi private, NON committare.
certbot/
+63
View File
@@ -0,0 +1,63 @@
# Reverse proxy nginx + Let's Encrypt
Reverse proxy nginx davanti ad Apache per `ifattidinapoli.it`. I certificati SSL
sono gestiti automaticamente da Let's Encrypt tramite certbot (validazione
HTTP-01 via webroot), con **un unico certificato multi-dominio (SAN)** che copre
tutti gli host serviti da questo nginx.
## Domini coperti dal certificato
- `www.ifattidinapoli.it` (primario / CN)
- `ifattidinapoli.it`
- `preproduction.ifattidinapoli.it`
- `test.ifattidinapoli.it`
La lista si definisce nell'array `domains` di [init-letsencrypt.sh](init-letsencrypt.sh).
Il primo dominio e' il primario e da' il nome alla cartella
`/etc/letsencrypt/live/<primario>/` referenziata in [nginx.conf](nginx.conf).
## Primo setup
Prerequisiti:
- Docker con il plugin Compose v2 (comando `docker compose`, non `docker-compose`).
- La rete docker esterna `nginx-network` deve esistere (`docker network create nginx-network`).
- Le porte 80 e 443 dell'host devono essere pubblicamente raggiungibili per
tutti i domini (la validazione HTTP-01 passa dalla porta 80).
- I record DNS di tutti i domini devono puntare a questo server.
```bash
# 1. (consigliato) prova prima in staging: metti staging=1 in init-letsencrypt.sh
./init-letsencrypt.sh
# 2. verifica che tutto funzioni, poi rimetti staging=0 e rilancia
./init-letsencrypt.sh
```
Lo script:
1. scarica i parametri TLS raccomandati,
2. crea un certificato dummy self-signed cosi' nginx puo' partire,
3. avvia nginx,
4. cancella il dummy e richiede il certificato reale a Let's Encrypt,
5. ricarica nginx.
## Rinnovo
Il rinnovo e' automatico. [renew.sh](renew.sh) lancia `certbot renew` (che
rinnova solo se manca meno di 30 giorni alla scadenza) e ricarica nginx.
Schedularlo in crontab sull'host (`crontab -e`):
```
0 3 * * * cd /percorso/di/cicd/nginx && ./renew.sh > /tmp/renew.log 2>&1 || logger -t CRON_RENEW -f /tmp/renew.log
```
Se lo script fallisce, l'output finisce in syslog; altrimenti nessun output.
## Note sulla migrazione da Sectigo
- I vecchi certificati Sectigo sono in `ssl/`. Il mount `./ssl:/etc/ssl:ro` in
[docker-compose.yml](docker-compose.yml) e i file in `ssl/` possono essere
rimossi una volta verificato che Let's Encrypt funziona.
- La cartella `certbot/` (chiavi private incluse) e' in `.gitignore` e **non va
committata**. Le vecchie chiavi Sectigo sono invece presenti nella history git:
valutare con il fornitore se revocarle.
+7
View File
@@ -11,12 +11,19 @@ services:
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/ssl:ro
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
logging:
driver: "json-file"
options:
max-file: 4
max-size: 100m
compress: "true"
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
+114
View File
@@ -0,0 +1,114 @@
#!/bin/bash
# Bootstrap del certificato Let's Encrypt unico (multi-dominio / SAN) per il
# reverse proxy di ifattidinapoli.it.
#
# A differenza del progetto Gogs-Reverse (un certificato separato per dominio),
# qui si richiede UN SOLO certificato che copre tutti i domini serviti da questo
# nginx. Il primo dominio dell'array e' il primario (CN) e da' il nome alla
# cartella /etc/letsencrypt/live/<primario>/ referenziata in nginx.conf.
#
# Lanciarlo una volta sola, al primo setup. Per i rinnovi usare renew.sh.
#
# NB: usa il plugin "docker compose" (v2). Con questo plugin --entrypoint accetta
# solo un eseguibile: i comandi con piu' token o con && vanno wrappati in
# `--entrypoint sh <service> -c "..."`, altrimenti gli argomenti oltre il primo
# vengono scartati silenziosamente.
set -e
if ! docker compose version >/dev/null 2>&1; then
echo 'Error: "docker compose" (plugin v2) is not available.' >&2
exit 1
fi
# Domini coperti dal certificato. Il PRIMO e' il primario (CN) e da' il nome
# alla cartella live/. Se lo cambi, aggiorna anche i path in nginx.conf.
domains=(
"www.ifattidinapoli.it"
"ifattidinapoli.it"
"preproduction.ifattidinapoli.it"
"test.ifattidinapoli.it"
)
primary_domain="${domains[0]}"
rsa_key_size=4096
data_path="./certbot"
email="riccardo.didato@gmail.com"
# Metti a 1 per usare l'ambiente di STAGING di Let's Encrypt (test senza
# consumare i rate limit). Passato il test, rimetti a 0 e rilancia.
staging=0
# Costruisce la sequenza di argomenti -d per certbot
domain_args=()
for domain in "${domains[@]}"; do
domain_args+=(-d "$domain")
done
# ---------------------------------------------------------------------------
# FASE 0: parametri TLS raccomandati (una tantum)
# ---------------------------------------------------------------------------
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
# ---------------------------------------------------------------------------
# FASE 1: certificato dummy self-signed
# nginx non parte se i path ssl_certificate non esistono. Creiamo un cert
# temporaneo cosi' nginx si avvia e puo' servire la validazione ACME su :80.
# ---------------------------------------------------------------------------
if [ -d "$data_path/conf/live/$primary_domain" ]; then
echo "### Existing certificate found for $primary_domain. Skipping dummy generation."
else
echo "### Creating dummy certificate for $primary_domain ..."
path="/etc/letsencrypt/live/$primary_domain"
mkdir -p "$data_path/conf/live/$primary_domain"
docker compose run --rm --entrypoint sh certbot -c "\
openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1 \
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'"
echo
fi
echo "### Starting nginx ..."
docker compose up --force-recreate -d nginx
echo
# ---------------------------------------------------------------------------
# FASE 2: richiesta del certificato REALE
# ---------------------------------------------------------------------------
echo "### Deleting dummy certificate ..."
docker compose run --rm --entrypoint sh certbot -c "\
rm -Rf /etc/letsencrypt/live/$primary_domain && \
rm -Rf /etc/letsencrypt/archive/$primary_domain && \
rm -Rf /etc/letsencrypt/renewal/$primary_domain.conf"
echo
email_arg=()
case "$email" in
"") email_arg=(--register-unsafely-without-email) ;;
*) email_arg=(--email "$email") ;;
esac
staging_arg=()
if [ "$staging" != "0" ]; then staging_arg=(--staging); fi
echo "### Requesting Let's Encrypt certificate for: ${domains[*]} ..."
# L'immagine certbot/certbot ha gia' "certbot" come entrypoint: passiamo solo
# gli argomenti come comando (niente --entrypoint da sovrascrivere).
docker compose run --rm certbot certonly --webroot -w /var/www/certbot \
"${staging_arg[@]}" \
"${email_arg[@]}" \
"${domain_args[@]}" \
--rsa-key-size "$rsa_key_size" \
--agree-tos \
--force-renewal
echo
echo "### Reloading nginx ..."
docker compose exec nginx nginx -s reload
+40 -5
View File
@@ -5,34 +5,53 @@ events { worker_connections 1024; }
http {
client_max_body_size 5M;
# Path del certificato Let's Encrypt unico multi-dominio (SAN).
# Il nome della cartella live/ corrisponde al primo -d passato a certbot
# in init-letsencrypt.sh (dominio primario / CN).
# ssl_certificate /etc/letsencrypt/live/www.ifattidinapoli.it/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/www.ifattidinapoli.it/privkey.pem;
server {
listen 80;
server_name ifattidinapoli.it;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://www.ifattidinapoli.it$request_uri;
}
}
server {
listen 443 ssl;
server_name ifattidinapoli.it;
ssl_certificate /etc/ssl/2025/www_ifattidinapoli_it.chained.crt;
ssl_certificate_key /etc/ssl/2025/www_ifattidinapoli_it.key;
ssl_certificate /etc/letsencrypt/live/www.ifattidinapoli.it/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.ifattidinapoli.it/privkey.pem;
return 301 https://www.ifattidinapoli.it$request_uri;
}
server {
listen 80;
server_name www.ifattidinapoli.it preproduction.ifattidinapoli.it;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.ifattidinapoli.it preproduction.ifattidinapoli.it default_server;
ssl_certificate /etc/ssl/2025/www_ifattidinapoli_it.chained.crt;
ssl_certificate_key /etc/ssl/2025/www_ifattidinapoli_it.key;
ssl_certificate /etc/letsencrypt/live/www.ifattidinapoli.it/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.ifattidinapoli.it/privkey.pem;
location / {
proxy_pass http://fdn2.production.webserver/;
@@ -46,6 +65,22 @@ http {
listen 80;
server_name test.ifattidinapoli.it;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name test.ifattidinapoli.it;
ssl_certificate /etc/letsencrypt/live/www.ifattidinapoli.it/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.ifattidinapoli.it/privkey.pem;
location / {
proxy_pass http://fdn2.test.webserver/;
proxy_redirect off;
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
# Rinnova il certificato SSL e ricarica nginx.
# Schedulato via crontab sull'host (vedi README). certbot renew rinnova solo se
# il certificato scade entro 30 giorni, quindi e' sicuro lanciarlo ogni giorno.
#
# NB: usa il plugin "docker compose" (v2). L'immagine certbot/certbot ha gia'
# "certbot" come entrypoint, quindi passiamo "renew" come comando.
docker compose run --rm certbot renew
docker compose exec -T nginx nginx -s reload