Skip to content
Q
QuoteNode

Konfiguracja

Instalacja

Jak wdrożyć QuoteNode na własnej infrastrukturze za pomocą Docker Compose.

Instalacja

QuoteNode działa jako zestaw kontenerów Docker. Nie musisz instalować Java, Node.js ani PostgreSQL na swoim komputerze — Docker zajmuje się wszystkim.

Wymagania wstępne

  • Docker Engine 24.0 lub nowszy (zainstaluj Dockera)
  • Docker Compose v2 (dołączony do nowoczesnego Docker Desktop i Docker Engine)
  • Maszyna z co najmniej 2 GB RAM i 10 GB wolnego miejsca na dysku

Aby zweryfikować konfigurację:

docker --version        # Powinno pokazać 24.0+
docker compose version  # Powinno pokazać v2.x

Szybki start (5 minut)

Poniższe kroki uruchamiają QuoteNode na Twoim lokalnym komputerze do testów. Nie jest to konfiguracja produkcyjna — zobacz niżej.

Krok 1 — Utwórz katalog projektu

mkdir quotenode && cd quotenode

Krok 2 — Utwórz plik konfiguracyjny

Utwórz plik o nazwie .env z minimalnymi wymaganymi ustawieniami:

# Baza danych
DB_URL=jdbc:postgresql://postgres:5432/quotenode
DB_USERNAME=quotenode
DB_PASSWORD=zmien-mnie-na-cos-losowego-min-32-znaki
DB_NAME=quotenode

# ============================================================
# SEKRETY BEZPIECZEŃSTWA — PRZECZYTAJ ZANIM PRZEJDZIESZ DALEJ
# Te wartości są UNIKALNE dla Twojej instalacji.
# Jeśli stracisz ten plik, NIE możesz wygenerować tych samych sekretów.
# ZAPISZ TEN PLIK i przechowuj bezpieczną kopię (lub nawet wydruk).
# ============================================================
DB_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
TIMING_TOKEN_SECRET=zmien-mnie-timing-secret-min-32-znakow
PUBLIC_LINK_PASSWORD_SESSION_SECRET=zmien-mnie-session-secret-min-32

# Domena (dla CORS i Caddy)
CORS_ALLOWED_ORIGINS=http://localhost
DOMAIN=localhost

# Logowanie
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod

Zapisz plik .env natychmiast. Powyższe sekrety zostały losowo wygenerowane i są unikalne dla tej instalacji. Jeśli stracisz ten plik, nie możesz odtworzyć tych samych wartości. Bez oryginalnego DB_ENCRYPTION_KEY zaszyfrowane dane (kody MFA, hasło SMTP, klucze API) stają się trwale nieczytelne. Skopiuj ten plik w bezpieczne miejsce — dla systemów produkcyjnych rozważ wydrukowanie sekretów i przechowywanie ich w fizycznym sejfie.

Krok 3 — Utwórz plik Docker Compose

Utwórz plik o nazwie docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    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
    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
    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
    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

Docker pobierze obrazy kontenerów (przy pierwszym uruchomieniu zajmie to kilka minut) i uruchomi wszystkie usługi. Możesz obserwować postęp startu:

docker compose logs -f backend

Poczekaj, aż zobaczysz linię Started QuoteNodeApplication — oznacza to, że backend jest gotowy.

Krok 5 — Otwórz QuoteNode

Przejdź do http://localhost w przeglądarce.

Domyślne dane logowania:

PoleWartość
Email[email protected]
HasłoAdmin123!

Zmień domyślne hasło natychmiast po zalogowaniu (Ustawienia > Mój profil > Zmień hasło).

Co właśnie uruchomiłeś?

Po docker compose up masz 4 kontenery:

KontenerCo robiZużycie RAM
postgresPrzechowuje wszystkie dane~256 MB
backendSerwer API Java, logika biznesowa~512 MB – 1.5 GB
gotenbergKonwertuje HTML na PDF (Chromium)~200 MB
frontendSerwuje interfejs web + reverse proxy~20 MB

Łącznie: około 1.5 – 2.5 GB RAM.

Przydatne komendy

# Sprawdź czy wszystkie usługi działają
docker compose ps

# Pokaż logi (wszystkie usługi)
docker compose logs -f

# Pokaż logi (tylko backend)
docker compose logs -f backend

# Zatrzymaj QuoteNode
docker compose down

# Zaktualizuj do najnowszej wersji
docker compose pull && docker compose up -d

Bezpieczeństwo sekretów

Twój plik .env zawiera kryptograficzne sekrety, które są unikalne dla Twojej instalacji. Zrozumienie, co chroni każdy sekret, pomoże Ci zaplanować strategię backupu:

SekretCo chroniJeśli zgubiony
DB_PASSWORDDostęp do bazy danychOdzyskiwalny — reset przez narzędzia administracyjne PostgreSQL
DB_ENCRYPTION_KEYKody MFA (TOTP), hasło SMTP, klucz API FX — oraz wszystkie pola PII gdy ENCRYPT_PII=trueTrwale nieczytelne — tych pól nie da się odszyfrować bez oryginalnego klucza
TIMING_TOKEN_SECRETTokeny anty-timing-attackWygeneruj nowy — istniejące tokeny unieważnione, użytkownicy logują się ponownie
PUBLIC_LINK_PASSWORD_SESSION_SECRETSesje publicznych linkówWygeneruj nowy — aktywne sesje wygasają, linki nadal działają

Krytycznym sekretem jest DB_ENCRYPTION_KEY. Wszystkie inne sekrety można wygenerować ponownie z niewielką niedogodnością. Ale DB_ENCRYPTION_KEY szyfruje dane w bazie — jego utrata oznacza, że te pola przepadają bezpowrotnie. Jeśli ENCRYPT_PII=true, dotyczy to również wszystkich danych osobowych klientów, kontaktów, dostawców i użytkowników (imiona, e-maile, telefony, NIP-y). Bez włączonego szyfrowania PII dane biznesowe są przechowywane bez szyfrowania i pozostają w pełni dostępne.

Dla systemów produkcyjnych zalecamy:

  • Przechowuj kopię .env w menedżerze haseł (1Password, Bitwarden itp.)
  • Dla maksymalnego bezpieczeństwa wydrukuj sekrety i przechowuj wydruk w fizycznym sejfie
  • Nigdy nie commituj .env do repozytorium

Odzyskiwanie po utracie .env

Jeśli stracisz plik .env, ale masz niezaszyfrowany backup bazy danych (domyślny tryb backupu), możesz odzyskać swoje dane:

  1. Utwórz nowy plik .env z nowymi sekretami
  2. Przywróć bazę danych z backupu (pg_dump / pg_restore)
  3. Wszystkie dane biznesowe (klienci, oferty, produkty, użytkownicy) będą w pełni dostępne
  4. Tylko kilka pól jest utraconych: kody MFA (użytkownicy muszą ponownie skonfigurować), hasło SMTP (wprowadź ponownie w ustawieniach), klucz API FX (wprowadź ponownie w ustawieniach). Jeśli ENCRYPT_PII=true było włączone, wszystkie dane osobowe (imiona, e-maile, telefony, NIP-y) są również utracone — rozważ to przed włączeniem szyfrowania PII

Jeśli Twoje backupy są zaszyfrowane GPG (przez BACKUP_GPG_RECIPIENT), musisz najpierw odszyfrować je kluczem prywatnym GPG.

Wdrożenie produkcyjne

Do użytku produkcyjnego musisz:

  1. Wygenerować właściwe sekrety — nigdy nie używaj przykładowych wartości z powyżej na produkcji:
# Wygeneruj 64-znakowy klucz hex do szyfrowania bazy
openssl rand -hex 32

# Wygeneruj losowe sekrety dla tokenów
openssl rand -base64 32
  1. Skonfigurować domenę z HTTPS — ustaw DOMAIN i CORS_ALLOWED_ORIGINS na swoją prawdziwą domenę. Kontener frontend (Caddy) automatycznie uzyskuje certyfikaty Let’s Encrypt.

  2. Skonfigurować e-mail — dodaj ustawienia SMTP do .env, aby włączyć wysyłkę ofert:

SMTP_HOST=smtp.twojdostawca.com
SMTP_PORT=587
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=twoje-haslo-smtp
SMTP_AUTH=true
SMTP_STARTTLS=true
  1. Wykonać kopię zapasową pliku .env — przechowuj go bezpiecznie, zanim zrobisz cokolwiek innego. Zobacz Bezpieczeństwo sekretów powyżej.

  2. Włączyć kopie zapasowe bazy — zobacz przewodnik Backup & Recovery.

  3. Przejrzeć wszystkie ustawienia — pobierz pełny .env.prod.example z repozytorium, aby zobaczyć wszystkie dostępne zmienne konfiguracyjne.

Zaawansowane opcje wdrożenia (Coolify PaaS, worker backupów, GeoIP) opisane są na stronie wiki Deployment Options.

Aktualizacja QuoteNode

Aby zaktualizować do najnowszej wersji:

docker compose pull && docker compose up -d

Plik .env nigdy nie jest modyfikowany przez aktualizacje. Docker pobiera nowe obrazy kontenerów, ale Twoja konfiguracja i dane pozostają nienaruszone. Nie usuwaj ani nie twórz ponownie pliku .env podczas aktualizacji — te same sekrety muszą być używane przez cały czas życia instalacji.

Migracje schematu bazy danych uruchamiają się automatycznie przy starcie backendu — żaden ręczny krok nie jest potrzebny.

Rozwiązywanie problemów

Backend nie startuje

Sprawdź logi: docker compose logs backend. Częste problemy:

  • Baza danych nie gotowa — backend czeka na PostgreSQL. Jeśli PostgreSQL wolno startuje, backend ponawia próby automatycznie.
  • Nieprawidłowe sekretyDB_ENCRYPTION_KEY musi mieć dokładnie 64 znaki hex. DB_PASSWORD musi być zgodne między kontenerami backend i PostgreSQL.
  • Konflikt portów — jeśli port 80 lub 443 jest już zajęty, zmień mapowanie ports w docker-compose.yml.

Nie mogę połączyć się z QuoteNode

  • Sprawdź, czy wszystkie kontenery działają: docker compose ps
  • Sprawdź, czy kontener frontend pokazuje status “healthy”
  • Spróbuj http://localhost (nie https:// przy testach lokalnych bez prawdziwej domeny)

Zapomniałem hasła admina

Zatrzymaj stack, usuń wolumen PostgreSQL i uruchom ponownie — konto admina zostanie odtworzone przy pierwszym starcie:

docker compose down -v   # UWAGA: usuwa wszystkie dane!
docker compose up -d

Na produkcji użyj zamiast tego funkcji resetu hasła w panelu administracyjnym.

Następne kroki

Last reviewed: Recently