Prima di avviare lo stack è necessario configurare i record DNS presso il proprio provider (OVH):
| Nome | Tipo | Valore |
|---|---|---|
example.com |
A | <IP del server> |
CNAME *.example.com → example.com.
⚠️ Attenzione: Il CNAME wildcard indirizza qualunque sottodominio (portainer.example.com,app.example.com, ecc.) alla zona principale. Su OVH, se la zona radice è un record A, il CNAME wildcard è supportato. In caso di problemi, creare singoli record A per ogni servizio:
Nome Tipo Valore portainerA <IP del server>appA <IP del server>
Lo stack usa la stessa codebase (docker-compose.yml) sia in locale che sul server: quello che cambia è solo il file .env passato a Compose, tramite Docker Compose profiles.
Locale (nessuna modifica necessaria, certificato NPM self-signed, VPN/CrowdSec/Bouncer spenti):
cd services
docker compose --env-file .env.local up -dI servizi con dominio (NPM, Portainer via proxy) sono raggiungibili su *.127.0.0.1.nip.io (wildcard DNS pubblico che risolve a 127.0.0.1).
Server (stack completo, certificati Let's Encrypt reali):
cd services
cp example.env .env # solo la prima volta: personalizzare dominio/credenziali
docker compose up -d # legge .env di default, con COMPOSE_PROFILES=serversetup.sh (vedi sotto) automatizza anche questo passaggio.
services/.env (con le credenziali reali del server) non è versionato: usare services/example.env come riferimento. services/.env.local invece è versionato con valori fittizi pensati solo per lo sviluppo in locale.
sudo apt update && sudo apt install -y git
git clone https://github.com/dima91/server-setup.git
cd server-setup
sudo bash setup.sh <new_user> <new_user_passw> <ssh_port>Il file setup.sh è uno script Bash pensato per automatizzare la configurazione iniziale di un server (tipicamente una VPS o un server dedicato) con sistema Debian/Ubuntu. Lo script viene eseguito in più fasi (stage), riavviando la macchina tra una fase e l’altra per applicare modifiche a basso livello (es. cambio di porta SSH, rimozione dell’utente predefinito). Ecco una descrizione dettagliata delle operazioni effettuate, fase per fase.
- Lo script deve essere eseguito come root.
- Accetta tre parametri:
<new_user>,<new_user_passw>,<ssh_port>. - Durante la prima esecuzione crea una cartella persistente
/etc/server_setup, vi copia l’intero script e genera un filesetup_infoche tiene traccia dei parametri e dello stage corrente. - Al termine di ogni stage viene aggiornato il file
setup_infoe viene riavviato il sistema. Dopo il reboot, l’utente indicato (prima l’old user, poi il nuovo) deve rilanciare lo scriptsetup.shper proseguire.
- Verifica che lo script sia eseguito come root.
- Controlla che la cartella
/etc/server_setupnon esista già (altrimenti salta questa fase e procede con lo stage successivo). - Acquisisce:
- OLD_USER = utente che ha lanciato
sudo(o$USERse non usato sudo). - NEW_USER, NEW_USER_PASSW, NEW_SSH_PORT dai parametri.
- I gruppi primari e secondari dell’utente corrente.
- OLD_USER = utente che ha lanciato
- Chiede conferma all’utente mostrando tutti i valori.
- Crea la cartella
SETUP_DATA_FOLDER(/etc/server_setup), vi copia l’intera directory contenente lo script, ne imposta i permessi e crea un symlink in/usr/local/bin/setup.sh. - Scrive il file
setup_infocon tutti i dati eNEXT_STAGE=1. - Riavvia il sistema.
- Esegue
apt update && apt upgrade. - Installa i pacchetti essenziali elencati in
ESSENTIAL_PACKAGES(strumenti come build-essential, curl, git, ufw, htop, net-tools, ecc.). - Crea il nuovo utente
NEW_USER, gli assegna gli stessi gruppi (aggiungendosudo), imposta la password e aggiunge l’aliasupdgnel file.bash_aliases. - Crea un file di swap eseguendo lo script
make_swap.sh(dettagli non mostrati, presumibilmente configura un file di swap di dimensioni adeguate). - Aggiorna il file
setup_infoconNEXT_STAGE=2. - Riavvia il sistema.
- Rimuove completamente l’utente originale
OLD_USER(utente di default di molte VPS, es.debian). - Modifica la porta SSH nel file
/etc/ssh/sshd_configimpostandola aNEW_SSH_PORT. Disabilita anche il login di root via SSH. - Riavvia il servizio
sshd. - Configura UFW:
- Abilita IPv6.
- Imposta policy: deny in ingresso, allow in uscita.
- Apre la nuova porta SSH.
- Abilita e ricarica UFW.
- Installa Docker:
- Rileva la distribuzione (Debian/Ubuntu) tramite
hostnamectl. - Rimuove eventuali vecchi pacchetti Docker.
- Aggiunge la repository ufficiale Docker.
- Installa
docker-ce,docker-ce-cli,containerd.ioe i plugin necessari. - Aggiunge il nuovo utente al gruppo
docker.
- Rileva la distribuzione (Debian/Ubuntu) tramite
- Aggiorna il file
setup_infoconNEXT_STAGE=3. - Riavvia il sistema.
- Ferma e disabilita Apache (se installato) per liberare le porte 80/443.
- Apre le porte firewall necessarie: 80, 443, 81 (Nginx Proxy Manager UI), 9443 (Portainer), 1195 (VPN personale), 3000 (Open WebUI).
- Copia la cartella
services(con i filedocker-compose.ymle.env) nella home del nuovo utente. - Si posiziona nella directory
servicese:- Carica le variabili d’ambiente da
.env. - Genera una password casuale per il database di NPM e la inserisce nel file
.env.
- Carica le variabili d’ambiente da
- Avvia tutti i container con
docker compose up -d. - Attende 200 secondi (con log intermedi ogni 20s) per dare il tempo ai servizi di inizializzarsi.
- Verifica che CrowdSec sia pronto: tenta di eseguire
cscli versionnel containercrowdsecper un massimo di 24 tentativi. - Genera la chiave API del bouncer per CrowdSec con il comando
cscli bouncers add npm-bouncer. - Scrive la chiave nel file
.env(sostituendo o aggiungendo la variabileCROWDSEC_BOUNCER_API_KEY). - Riavvia il container
cs-bouncerper applicare la nuova chiave. - Aggiorna il file
setup_infoconNEXT_STAGE=4. - Riavvia il sistema.
- La fase successiva (NEXT_STAGE diverso da 1,2,3) stampa semplicemente “Setup is finished. System ready!” e termina, perché tutto è stato configurato.
log(): scrive messaggi con timestamp su file/var/log/setup.loge su console.update_info_file(): riscrive il filesetup_infocon i parametri attuali e il prossimo stage.
Una volta completato lo script, il server avrà:
- Un nuovo utente con permessi sudo e gruppi ereditati dall’utente originale.
- Accesso SSH su una porta personalizzata (e root disabilitato).
- Firewall UFW attivo con sole porte necessarie aperte.
- Swap configurato.
- Docker installato e utente aggiunto al gruppo docker.
- Stack di servizi in esecuzione: Nginx Proxy Manager, CrowdSec, un CS bouncer per NPM, un database per NPM, probabilmente Portainer, un server VPN e Open WebUI (a giudicare dalle porte aperte).
- Integrazione automatica tra CrowdSec e NPM tramite la chiave bouncer generata.
Lo script è pensato per essere eseguito una sola volta e gestisce i riavvii in modo trasparente, richiedendo all’utente di rilanciare il comando setup.sh dopo ogni reboot.
Prima di procedere con il setup manuale o automatico, assicurarsi che i record DNS siano configurati correttamente.
| Record | Nome | Tipo | Target |
|---|---|---|---|
| Root | example.com |
A | <IP del server> |
| Wildcard | *.example.com |
CNAME | example.com. |
Il CNAME wildcard è obbligatorio per far funzionare tutti i sottodomini (Portainer, App, ecc.) senza dover creare un record A per ciascuno.
Nota per OVH: Se la zona DNS non accetta un CNAME sulla radice, creare record A espliciti per ogni servizio:
Nome Tipo Valore portainerA <IP del server>appA <IP del server>
- Configurare i record DNS (vedi sezione "DNS prerequisites" sopra)
- Create NPM certificates:
certbot certonly --config /etc/letsencrypt.ini --work-dir /tmp/letsencrypt-lib --logs-dir /data/logs --cert-name ${CERTIFICATE_NAME} --agree-tos --authenticator webroot -m ${ADMIN_EMAIL} --preferred-challenges http --domains ${FULL_DOMAIN} --key-type ecdsa
- Add NPM hosts via NPM UI
docker exec crowdsec cscli alerts list # IP bannati
docker exec crowdsec cscli decisions list # decisioni attive
docker exec crowdsec cscli metrics # statistiche