Installation
Instalacja na serwerze Linux w sieci LAN
Uruchom QuoteNode na wewnętrznym serwerze Linux dla biura lub zespołu z dostępem tylko przez VPN.
Instalacja na serwerze Linux w sieci LAN
Wybierz tę ścieżkę, gdy QuoteNode ma działać na wewnętrznym serwerze Linux, maszynie wirtualnej lub mini-PC dostępnym w sieci biurowej lub przez VPN.
Kiedy użyć
- Kilku wewnętrznych użytkowników potrzebuje stabilnej wspólnej instancji.
- Publiczny dostęp klientów nie jest wymagany.
- Preferujesz hosta Linux zamiast Docker Desktop.
Co nie zadziała
- Publiczne linki do ofert działają tylko dla użytkowników, którzy mogą dotrzeć do adresu serwera.
- Wysyłka e-mail może działać z SMTP, ale odbiorcy spoza LAN nie otworzą wewnętrznych linków.
- Wewnętrzny HTTPS z self-signed certyfikatem może wyświetlać ostrzeżenia przeglądarki.
Wymagania
- Ubuntu, Debian lub inna utrzymywana dystrybucja Linux.
- Docker Engine 24.0+ i Docker Compose v2.
- Statyczne IP lub rezerwacja DHCP dla serwera.
- Dostęp SSH dla operatorów.
- Co najmniej 2 GB RAM i 10 GB wolnego miejsca na dysku.
- Miejsce na kopie zapasowe poza głównym wolumenem Docker.
Sprawdź konfigurację:
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 .env. Zamień 192.168.1.20 na rzeczywisty adres IP serwera lub wewnętrzną nazwę DNS (np. crm.internal):
# 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
# LAN URL — replace with your server IP or internal DNS name
CORS_ALLOWED_ORIGINS=http://192.168.1.20
DOMAIN=192.168.1.20
# 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
Jeśli wdrażasz za wewnętrznym reverse proxy z HTTPS, użyj adresu HTTPS:
CORS_ALLOWED_ORIGINS=https://crm.internal.example
DOMAIN=crm.internal.example
Zapisz plik
.envnatychmiast. Przechowuj kopię poza tym serwerem. UtrataDB_ENCRYPTION_KEYoznacza trwałą utratę zaszyfrowanych pól.
Krok 3 — Utwórz plik Docker Compose
Utwórz plik 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 — Uruchom QuoteNode
docker compose up -d
Obserwuj postęp uruchamiania:
docker compose logs -f backend
Poczekaj aż zobaczysz Started QuoteNodeApplication.
Krok 5 — Otwórz QuoteNode
Przejdź do http://192.168.1.20 (lub adresu Twojego serwera) z dowolnego urządzenia w sieci LAN.
Domyślne dane logowania:
| Pole | Wartość |
|---|---|
[email protected] | |
| Hasło | Admin123! |
Zmień domyślne hasło natychmiast po zalogowaniu.
Co działa?
| Kontener | Funkcja | Użycie RAM |
|---|---|---|
postgres | Przechowuje wszystkie dane | ~256 MB |
backend | Serwer API Java, logika biznesowa | ~512 MB – 1,5 GB |
gotenberg | Konwersja HTML do PDF (oparty na Chromium) | ~200 MB |
frontend | Serwuje UI + reverse proxy | ~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
Bezpieczeństwo sekretów
| Sekret | Co chroni | Jeśli utracony |
|---|---|---|
DB_PASSWORD | Dostęp do bazy danych | Odzyskiwalny — reset przez narzędzia admin PostgreSQL |
DB_ENCRYPTION_KEY | Kody MFA, hasło SMTP, klucz API FX, pola PII | Trwale nieczytelny |
TIMING_TOKEN_SECRET | Tokeny anty-timing-attack | Regenerowalny — użytkownicy logują się ponownie |
PUBLIC_LINK_PASSWORD_SESSION_SECRET | Sesje linków publicznych | Regenerowalny — aktywne sesje wygasają |
Krytyczny sekret to
DB_ENCRYPTION_KEY. Przechowuj kopie.envpoza tym serwerem. Szczegóły odzyskiwania: Rozwiązywanie problemów z instalacją.
Zalecane kolejne kroki
- Skonfiguruj zaplanowane kopie zapasowe i przetestuj przywracanie.
- Przetestuj generowanie PDF po pierwszym wdrożeniu.
- Użyj publicznego serwera Ubuntu lub Coolify, gdy publiczne linki do ofert muszą działać dla klientów.