Installation
Instalar com Portainer, QNAP ou NAS
Coloca o QuoteNode num NAS ou num host Docker gerido por Portainer com instruções de configuração completas.
Instalar com Portainer, QNAP ou NAS
Usa este caminho se executares o Docker através do Portainer, QNAP Container Station, Synology ou uma plataforma semelhante. A interface exata difere por fornecedor, mas o stack Docker Compose subjacente é idêntico.
Quando usar
- Já operas stacks Docker através de uma interface de gestão de containers.
- Percebes como a plataforma mapeia volumes e portos.
- Consegues verificar backups fora da interface do NAS.
O que pode não funcionar
- Links públicos não funcionam fora da LAN a menos que NAT, DNS, proxy e HTTPS estejam configurados.
- Modos de suspensão do NAS podem interromper o serviço.
- Algumas UIs Docker de NAS reescrevem ficheiros compose ou variáveis de ambiente; verifica a stack renderizada antes de confiar nela.
- Backups armazenados apenas no mesmo NAS não protegem contra falha do NAS.
Pré-requisitos
- Suporte a Docker Compose v2 na tua plataforma.
- Suporte a volumes persistentes para dados PostgreSQL, uploads, PDFs e backups.
- Pelo menos 2 GB de RAM disponíveis e 10 GB de espaço livre em disco.
- Um URL estável: IP de LAN para uso interno, ou domínio público atrás de um proxy reverso para links de clientes.
Passo 1 — Criar o ficheiro de configuração
Cria um ficheiro .env (ou define variáveis através da interface de ambiente da tua plataforma). Substitui o URL pelo teu endereço NAS real ou domínio público:
Para um deployment só NAS interno:
# 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
# Internal NAS URL
CORS_ALLOWED_ORIGINS=http://nas.local
DOMAIN=nas.local
# O IP do cliente é detetado automaticamente atrás de proxies internos e CDNs (incluindo Cloudflare) — deixe vazio.
# Defina apenas para um proxy invulgar cujo par de transporte seja um endereço PÚBLICO a confiar (IP/CIDR ou nome de host).
SECURITY_TRUSTED_PROXIES=
# Application
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod
Para um domínio público atrás de um proxy reverso:
CORS_ALLOWED_ORIGINS=https://crm.example.com
DOMAIN=crm.example.com
Guarda o teu
.envimediatamente. Se perderes oDB_ENCRYPTION_KEY, os campos cifrados tornam-se permanentemente ilegíveis.
Passo 2 — Criar o stack Docker Compose
Usa o editor de stacks no Portainer ou na tua interface Docker do NAS, ou cria um ficheiro 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:
Conflitos de portos: Se o teu NAS já usa o porto 80 ou 443, muda o lado esquerdo do mapping
ports(ex."8080:80") e atualizaCORS_ALLOWED_ORIGINSem conformidade (ex.http://nas.local:8080).
Passo 3 — Fazer deploy e verificar
Inicia o stack através da interface da tua plataforma ou via SSH:
docker compose up -d
docker compose logs -f backend
Aguarda até ver Started QuoteNodeApplication.
Passo 4 — Abrir o QuoteNode
Navega para o URL do teu NAS (ex. http://nas.local ou https://crm.example.com).
Credenciais de acesso predefinidas:
| Campo | Valor |
|---|---|
[email protected] | |
| Password | Admin123! |
Altera a password predefinida imediatamente após iniciar sessão.
Checklist de persistência
Verifica que estes elementos estão mapeados a volumes persistentes (não a armazenamento efémero do container):
| Dados | Porque importa |
|---|---|
| PostgreSQL data | Base de dados principal da aplicação |
| Uploads | Imagens de produtos, logos, anexos |
| Generated PDFs | Ficheiros de propostas e documentos |
| Backups | Arquivos locais de backup (se o worker de backup estiver ativo) |
| GeoIP database | Dados opcionais de controlo de acesso |
O que está a correr?
| Container | O que faz | Uso de RAM |
|---|---|---|
postgres | Armazena todos os teus dados | ~256 MB |
backend | Servidor API Java, lógica de negócio | ~512 MB – 1,5 GB |
gotenberg | Converte HTML para PDF (baseado em Chromium) | ~200 MB |
frontend | Serve a interface web + reverse proxy | ~20 MB |
Total: aproximadamente 1,5 – 2,5 GB de RAM.
Manter os teus segredos seguros
| Segredo | O que protege | Se perdido |
|---|---|---|
DB_PASSWORD | Acesso à base de dados | Recuperável — reiniciar via ferramentas de administração PostgreSQL |
DB_ENCRYPTION_KEY | Códigos MFA, password SMTP, chave API FX, campos PII | Permanentemente ilegível |
TIMING_TOKEN_SECRET | Tokens anti-timing-attack | Regenerar — utilizadores re-autenticam-se |
PUBLIC_LINK_PASSWORD_SESSION_SECRET | Sessões de links públicos | Regenerar — as sessões ativas expiram |
Guarda backups do
.envfora do NAS. Uma falha do NAS que destrua a tua única cópia doDB_ENCRYPTION_KEYtorna os dados cifrados irrecuperáveis.
Próximos passos recomendados
- Configura backups numa localização fora do NAS.
- Testa a geração de PDF após o primeiro deployment.
- Se quiseres um caminho de deployment público mais suave, considera o Coolify num VPS.