Instalacja
Instalacja na publicznym serwerze Ubuntu
Wdrożenie QuoteNode na publicznym serwerze Ubuntu z domeną, HTTPS, SMTP, kopiami zapasowymi i podstawami zapory sieciowej.
Instalacja na publicznym serwerze Ubuntu
Użyj tej ścieżki dla wdrożenia produkcyjnego dostępnego przez publiczną domenę dla klientów.
Kiedy warto zastosować
- Zewnętrzni klienci muszą otwierać publiczne linki do ofert.
- Wiadomości e-mail powinny zawierać działające linki.
- Chcesz mieć bezpośrednią kontrolę nad serwerem zamiast korzystać z warstwy PaaS.
Co nie będzie działać bez odpowiedniej konfiguracji
- Publiczne linki nie działają, jeśli DNS nie wskazuje na serwer.
- Publiczne linki nie działają, jeśli adres URL przeglądarki różni się od konfiguracji CORS.
- Wydanie certyfikatu HTTPS nie powiedzie się, jeśli porty 80/443 są zablokowane.
- Linki e-mail nie działają, jeśli brakuje SMTP lub jeśli wiadomości są odrzucane przez dostawcę poczty odbiorcy.
- Wdrożenia z dynamicznym domowym IP wymagają DDNS i przekierowania portów w routerze; VPS jest zazwyczaj prostszy.
Wymagania wstępne
- Serwer Ubuntu LTS lub VPS.
- Publiczny rekord DNS, na przykład
crm.example.com, wskazujący na serwer. - Porty 80 i 443 otwarte z internetu.
- Docker Engine 24.0+ i Docker Compose v2.
- Konto SMTP do dostarczania poczty e-mail.
- Co najmniej 4 GB RAM i 20 GB wolnego miejsca na dysku (zalecane dla produkcji).
- Miejsce docelowe kopii zapasowych i procedura przywracania.
Sprawdź Docker:
docker --version # Should show 24.0+
docker compose version # Should show v2.x
Krok 1 — Utwórz katalog projektu
mkdir quotenode && cd quotenode
Krok 2 — Utwórz plik konfiguracyjny
Utwórz plik o nazwie .env. Zastąp crm.example.com swoją prawdziwą domeną:
# 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
# IP klienta jest wykrywane automatycznie za wewnętrznymi proxy i CDN (w tym Cloudflare) — zostaw puste.
# Ustaw tylko dla nietypowego proxy, którego peer transportowy ma adres PUBLICZNY do zaufania (IP/CIDR lub nazwa hosta).
SECURITY_TRUSTED_PROXIES=
# Application
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod
Wykonaj kopię zapasową pliku
.envprzed pierwszym użyciem produkcyjnym. Przechowaj go w menedżerze haseł lub fizycznym sejfie.DB_ENCRYPTION_KEYjest kluczowy — jego utrata oznacza trwałą utratę zaszyfrowanych danych.
Alternatywa dla SMTP: Możesz pominąć zmienne SMTP_* z .env i skonfigurować pocztę e-mail później w Ustawienia > Email SMTP w QuoteNode. Panel administratora przechowuje hasło SMTP zaszyfrowane za pomocą DB_ENCRYPTION_KEY, co eliminuje potrzebę umieszczania go w pliku .env.
Krok 3 — Utwórz plik Docker Compose
Utwórz plik o nazwie 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:
Krok 4 — Skonfiguruj zaporę sieciową
Otwórz tylko to, co jest potrzebne:
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Nie eksponuj PostgreSQL publicznie. Powinien pozostać w sieci Docker.
Krok 5 — Uruchom QuoteNode
docker compose up -d
Obserwuj start:
docker compose logs -f backend
Poczekaj, aż zobaczysz Started QuoteNodeApplication. Kontener frontend (Caddy) automatycznie uzyska certyfikat Let’s Encrypt dla Twojej domeny.
Krok 6 — Otwórz QuoteNode
Przejdź do https://crm.example.com w przeglądarce.
Domyślne dane logowania:
| Pole | Wartość |
|---|---|
[email protected] | |
| Hasło | Admin123! |
Zmień domyślne hasło natychmiast po zalogowaniu.
Sprawdzenie po wdrożeniu
- Zaloguj się i zmień hasło administratora.
- Utwórz testową ofertę.
- Wygeneruj PDF.
- Utwórz i otwórz publiczny link z innego urządzenia.
- Jeśli SMTP jest skonfigurowany, wyślij testowe powiadomienie i sprawdź, czy linki w wiadomości e-mail działają.
Co działa w tle?
| Kontener | Co robi | Zużycie RAM |
|---|---|---|
postgres | Przechowuje wszystkie dane | ~256 MB |
backend | Serwer API Java, logika biznesowa | ~512 MB – 1,5 GB |
gotenberg | Konwertuje HTML do PDF (oparty na Chromium) | ~200 MB |
frontend | Serwuje interfejs + reverse proxy (Caddy z auto-HTTPS) | ~20 MB |
Łącznie: około 1,5 – 2,5 GB RAM.
Przydatne polecenia
# 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
Lista kontrolna aktualizacji
Przed każdą aktualizacją:
- Potwierdź bieżącą wersję aplikacji w panelu administracyjnym.
- Wykonaj kopię zapasową
.env. - Uruchom lub zweryfikuj świeżą kopię zapasową bazy danych.
- Pobierz nowe obrazy i uruchom ponownie.
- Sprawdź stan backendu, logowanie, generowanie PDF i publiczny link do oferty.
Bezpieczeństwo sekretów
| Sekret | Co chroni | W przypadku utraty |
|---|---|---|
DB_PASSWORD | Dostęp do bazy danych | Możliwy do odzyskania — zresetuj przez narzędzia admin PostgreSQL |
DB_ENCRYPTION_KEY | Kody MFA, hasło SMTP, klucz FX API, pola PII | Trwale nieczytelne |
TIMING_TOKEN_SECRET | Tokeny anty-timing-attack | Zregeneruj — użytkownicy ponownie się uwierzytelniają |
PUBLIC_LINK_PASSWORD_SESSION_SECRET | Sesje publicznych linków | Zregeneruj — aktywne sesje wygasają |
Przechowuj
.envw menedżerze haseł (1Password, Bitwarden). Dla maksymalnego bezpieczeństwa wydrukuj sekrety i przechowuj wydruk w fizycznym sejfie. Nigdy nie commituj.envdo systemu kontroli wersji.
Odzyskiwanie po utracie .env
Jeśli utracisz plik .env, ale masz niezaszyfrowaną kopię zapasową bazy danych (tryb domyślny):
- Utwórz nowy
.envz nowymi sekretami. - Przywróć bazę danych z kopii zapasowej.
- Wszystkie dane biznesowe będą dostępne.
- Utracone: kody MFA (użytkownicy ponownie się rejestrują), hasło SMTP (wpisz ponownie), klucz FX API (wpisz ponownie). Jeśli
ENCRYPT_PII=truebyło włączone, zaszyfrowane dane klientów również przepadają.