Installation
Installare su un server pubblico Ubuntu
Distribuisci QuoteNode su un server Ubuntu pubblico con dominio, HTTPS, SMTP, backup e firewall di base.
Installare su un server pubblico Ubuntu
Usa questo percorso per un deployment in produzione raggiungibile dai clienti tramite un dominio pubblico.
Quando usarlo
- I clienti esterni devono aprire i link pubblici delle offerte.
- I messaggi email dovrebbero contenere link funzionanti.
- Vuoi il controllo diretto sul server invece di un layer PaaS.
Cosa non funzionerà senza la corretta configurazione
- I link pubblici falliscono se il DNS non punta al server.
- I link pubblici falliscono se l’URL del browser differisce dalla configurazione CORS.
- L’emissione del certificato HTTPS fallisce se le porte 80/443 sono bloccate.
- I link email falliscono se SMTP manca o se i messaggi sono rifiutati dal provider di posta del destinatario.
- I deployment con IP domestico dinamico necessitano DDNS e port forwarding del router; un VPS è solitamente più semplice.
Prerequisiti
- Server Ubuntu LTS o VPS.
- Record DNS pubblico, ad esempio
crm.example.com, che punta al server. - Porte 80 e 443 aperte da internet.
- Docker Engine 24.0+ e Docker Compose v2.
- Account SMTP per la consegna email.
- Almeno 4 GB di RAM e 20 GB di spazio libero su disco (raccomandati per la produzione).
- Destinazione backup e una procedura di restore.
Controlla Docker:
docker --version # Should show 24.0+
docker compose version # Should show v2.x
Passo 1 — Creare una directory di progetto
mkdir quotenode && cd quotenode
Passo 2 — Creare il file di configurazione
Crea un file chiamato .env. Sostituisci crm.example.com con il tuo dominio reale:
# Database
DB_URL=jdbc:postgresql://postgres:5432/quotenode
DB_USERNAME=quotenode
DB_PASSWORD=change-me-to-something-random-32-chars
DB_NAME=quotenode
# ============================================================
# SECURITY SECRETS — UNIQUE to this installation.
# SAVE THIS FILE and keep a secure backup.
# ============================================================
DB_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
TIMING_TOKEN_SECRET=change-me-timing-secret-min-32-chars
PUBLIC_LINK_PASSWORD_SESSION_SECRET=change-me-session-secret-min-32
# Public domain — replace with your real domain
CORS_ALLOWED_ORIGINS=https://crm.example.com
DOMAIN=crm.example.com
# Email delivery
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME[email protected]
SMTP_PASSWORD=your-smtp-password
SMTP_AUTH=true
SMTP_STARTTLS=true
# Notification preference links (must match your public domain)
NOTIFICATIONS_PUBLIC_PREFERENCES_URL=https://crm.example.com/notifications/preferences
# L'IP del client viene rilevato automaticamente dietro proxy interni e CDN (incluso Cloudflare) — lascia vuoto.
# Imposta solo per un proxy insolito il cui peer di trasporto è un indirizzo PUBBLICO da considerare attendibile (IP/CIDR o hostname).
SECURITY_TRUSTED_PROXIES=
# Application
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod
Esegui il backup del tuo file
.envprima del primo uso in produzione. Conservalo in un password manager o in una cassaforte fisica. IlDB_ENCRYPTION_KEYè critico — perderlo significa che i dati cifrati sono persi per sempre.
Alternativa SMTP: Puoi omettere le variabili SMTP_* da .env e configurare l’email in seguito in Impostazioni > SMTP email dentro QuoteNode. Il pannello admin conserva la password SMTP cifrata con DB_ENCRYPTION_KEY, mantenendola fuori dal file .env.
Passo 3 — Creare il file Docker Compose
Crea un file chiamato docker-compose.yml:
services:
postgres:
image: postgres:18-alpine
cpus: 4.0
mem_limit: 512m
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
PGDATA: /var/lib/postgresql/data # required for the postgres:18 image
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME}"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
gotenberg:
image: gotenberg/gotenberg:8
cpus: 2.0
mem_limit: 448m
environment:
LOG_LEVEL: info
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
backend:
image: ghcr.io/lesisty7/quotenode/quotenode-api:latest
cpus: 4.0
mem_limit: 1792m
depends_on:
postgres: { condition: service_healthy }
gotenberg: { condition: service_healthy }
env_file: .env
environment:
SPRING_PROFILES_ACTIVE: prod
JOBS_MODE: web
PDF_ENABLED: "true"
PDF_GOTENBERG_URL: http://gotenberg:3000
volumes:
- backend_uploads:/app/data/uploads
- backend_pdfs:/app/data/pdfs
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 15s
timeout: 10s
retries: 5
start_period: 45s
restart: unless-stopped
frontend:
image: ghcr.io/lesisty7/quotenode/quotenode-frontend:latest
cpus: 2.0
mem_limit: 192m
depends_on:
backend: { condition: service_healthy }
ports:
- "80:80"
- "443:443"
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:80/"]
interval: 15s
timeout: 5s
retries: 3
restart: unless-stopped
volumes:
postgres_data:
backend_uploads:
backend_pdfs:
Passo 4 — Configurare il firewall
Apri solo ciò che serve:
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Non esporre PostgreSQL pubblicamente. Resta sulla rete Docker.
Passo 5 — Avviare QuoteNode
docker compose up -d
Monitora l’avvio:
docker compose logs -f backend
Attendi di vedere Started QuoteNodeApplication. Il container frontend (Caddy) otterrà automaticamente un certificato Let’s Encrypt per il tuo dominio.
Passo 6 — Aprire QuoteNode
Naviga su https://crm.example.com nel tuo browser.
Credenziali di accesso predefinite:
| Campo | Valore |
|---|---|
[email protected] | |
| Password | Admin123! |
Cambia la password predefinita immediatamente dopo aver effettuato l’accesso.
Verifiche post-deployment
- Accedere e cambiare la password admin.
- Creare un’offerta di test.
- Generare un PDF.
- Creare e aprire un link pubblico da un altro dispositivo.
- Se SMTP è configurato, inviare una notifica di test e verificare che i link email funzionino.
Cosa è in esecuzione?
| Container | Cosa fa | Utilizzo RAM |
|---|---|---|
postgres | Archivia tutti i tuoi dati | ~256 MB |
backend | Server API Java, logica di business | ~512 MB – 1,5 GB |
gotenberg | Converte HTML in PDF (basato su Chromium) | ~200 MB |
frontend | Serve l’interfaccia web + reverse proxy (Caddy con auto-HTTPS) | ~20 MB |
Totale: circa 1,5 – 2,5 GB di RAM.
Comandi comuni
# Check service status
docker compose ps
# View logs
docker compose logs -f backend
# Stop QuoteNode
docker compose down
# Update to the latest version
docker compose pull && docker compose up -d
Checklist di aggiornamento
Prima di ogni aggiornamento:
- Conferma la versione app attuale nell’area admin.
- Esegui il backup di
.env. - Esegui o verifica un backup fresco del database.
- Esegui il pull delle nuove immagini e riavvia.
- Controlla health backend, login, generazione PDF e un link offerta pubblico.
Mantenere al sicuro i tuoi segreti
| Segreto | Cosa protegge | Se perso |
|---|---|---|
DB_PASSWORD | Accesso al database | Recuperabile — reimposta tramite strumenti di amministrazione PostgreSQL |
DB_ENCRYPTION_KEY | Codici MFA, password SMTP, chiave API FX, campi PII | Permanentemente illeggibile |
TIMING_TOKEN_SECRET | Token anti-timing-attack | Rigenera — gli utenti si ri-autenticano |
PUBLIC_LINK_PASSWORD_SESSION_SECRET | Sessioni dei link pubblici | Rigenera — le sessioni attive scadono |
Conserva
.envin un password manager (1Password, Bitwarden). Per massima sicurezza, stampa i segreti e conserva la stampa in una cassaforte fisica. Non committare mai.envnel controllo versione.
Ripristino se .env è perso
Se perdi il tuo file .env ma hai un backup del database non cifrato (il modo predefinito):
- Crea un nuovo
.envcon nuovi segreti. - Ripristina il database dal tuo backup.
- Tutti i dati di business saranno accessibili.
- Persi: codici MFA (gli utenti si re-iscrivono), password SMTP (reinserire), chiave API FX (reinserire). Se
ENCRYPT_PII=trueera abilitato, anche i dati cliente cifrati vengono persi.