Files
site-slavic-pulse-com/docker-compose-example
tomasz-syn-grzegorza f4775366ef Harden production security: Dockerfile build, nginx whitelist, and CSP.
Replace Dokploy runtime git clone with Dockerfile build to keep tokens out of the container, add nginx security headers and path whitelist, and scrub templates from the running image after HTML generation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-27 16:58:27 +02:00
..

Slavic Pulse - Frontend (Dokploy Deployment)

Statyczna strona z intro YouTube (short FHD 16:9 lub vertical 9:16 — wybór po formacie viewportu). Tło przed filmem to miniaturka z YouTube. Konfiguracja w .env, HTML generowany przy starcie kontenera.

Struktura projektu

site-slavic-pulse-com/
├── docker-compose.yml              # Lokalny dev (build z Dockerfile)
├── Dockerfile
├── default.conf
├── nginx.conf
├── index.html.template             # Szablon strony
├── generate-from-env.sh            # Generator HTML z .env
├── assets/imgs/favico/             # Favicony
├── site.webmanifest.template
└── docker-compose-example/         # Pliki deploymentowe Dokploy
    ├── docker-compose.yml
    ├── .env.example
    └── README.md

Dokploy deployment

Kroki w Dokploy UI:

  1. Nowa aplikacja (Compose) → wklej docker-compose-example/docker-compose.yml
  2. Wklej .env (na podstawie .env.example) — ustaw VIDEO_ID_*, opisy SEO
  3. Domains → dodaj oba hosty (Container Port = 80, HTTPS = Let's Encrypt):
    • slavic-pulse.com
    • www.slavic-pulse.comwymagane — bez tego www dostaje domyślny cert Traefika (CN=*, self-signed) i telefony pokazują „serwer nie potrafi udowodnić tożsamości”
  4. (Opcjonalnie) Advanced → Redirects → preset www → non-www, żeby www przekierowywało na apex
  5. Traefik routuje ruch HTTPS → port 80 kontenera (bez mapowania portu na hosta)
  6. Deploy — Dokploy klonuje repo na hoście i buduje obraz z Dockerfile (brak git clone w kontenerze)

Porty: nie używaj ports: w compose — Traefik/Dokploy łączy się z wewnętrznym :80. W docker ps kolumna PORTS może być pusta — to normalne przy routingu przez Traefik.

Gitea Provider w Dokploy (OAuth) — autoryzuje Dokploy do listowania repo i deployu z UI. Repo klonowane jest na hoście przez Dokploy; kontener nie potrzebuje tokena GITEA ani git clone w runtime.

Jak to działa

  1. Build — Dokploy buduje obraz z Dockerfile (nginx + assets + szablony)
  2. Start kontenera — entrypoint generuje index.html i site.webmanifest ze zmiennych .env, usuwa szablony z dysku
  3. Tło — miniaturka YouTube (img.youtube.com) dopasowana do FHD/vertical
  4. Intro wideo — YouTube IFrame API, autoplay
  5. Po filmie — przekierowanie (jeśli POST_VIDEO_REDIRECT_ENABLED=true) lub tło z miniaturki

Konfiguracja (.env)

Zmienna Opis
VIDEO_ID_FHD / VIDEO_ID_VERTICAL ID shortów YouTube
POST_VIDEO_REDIRECT_URL_* URL po zakończeniu filmu
POST_VIDEO_REDIRECT_ENABLED true = redirect, false = zostaje tło

Nie dodawaj do produkcyjnego .env: GITEA_REPO_URL, FRONTEND_PORT — nie są używane w tym modelu deployu.

Hardening bezpieczeństwa (wbudowany)

  • Build z Dockerfile zamiast runtime git clone — brak tokenów w kontenerze
  • nginx: whitelist ścieżek, blokada .env/.sh/.template, nagłówki CSP/Referrer-Policy
  • Szablony i generator usuwane z kontenera po wygenerowaniu HTML
  • server_tokens off — ukryta wersja nginx

Weryfikacja po deployu

# Strona działa
curl -sI https://slavic-pulse.com/ | head -5

# Wrażliwe pliki niedostępne (404)
curl -sI https://slavic-pulse.com/.env | grep HTTP
curl -sI https://slavic-pulse.com/generate-from-env.sh | grep HTTP
curl -sI https://slavic-pulse.com/random-path | grep HTTP

# Nagłówki bezpieczeństwa
curl -sI https://slavic-pulse.com/ | grep -iE 'content-security-policy|referrer-policy|permissions-policy'

# Brak wersji nginx w Server
curl -sI https://slavic-pulse.com/ | grep -i server

# W kontenerze (na serwerze)
docker exec slavic-pulse-com-frontend ls /opt/slavic-pulse 2>&1   # powinno: No such file
docker inspect slavic-pulse-com-frontend --format '{{range .Config.Env}}{{println .}}{{end}}' | grep -i gitea  # brak wyniku

Rozwiązywanie problemów

Brak portów w docker ps (kolumna PORTS pusta)

Przy Traefik/Dokploy bez ports: w compose — to oczekiwane. Sprawdź w Dokploy UI: domena → Container Port = 80, kontener Up (healthy).

Kontener nie startuje / unhealthy

Diagnostyka na serwerze:

docker logs slavic-pulse-com-frontend --tail 50

Typowe przyczyny: błąd builda Dockerfile, brak .env, błąd w generate-from-env.sh.

Zmiana konfiguracji po deployu

  1. Edytuj .env w Dokploy
  2. Redeploy / restart kontenera (entrypoint regeneruje HTML z nowych zmiennych)

Błąd certyfikatu SSL na telefonie („serwer nie potrafi udowodnić…”)

Diagnoza (stan typowy):

  • https://slavic-pulse.com — certyfikat Let's Encrypt OK
  • https://www.slavic-pulse.comself-signed (Traefik default, CN=*) → błąd na Androidzie / iPhone / WebView Facebooka

Strona wysyła Strict-Transport-Security: includeSubDomains, więc po wizycie na działającym apexie przeglądarka wymusza HTTPS także na www — a tam cert jest zły → twardy błąd.

Naprawa w Dokploy (zalecane):

  1. DomainsAdd Domain
  2. Host: www.slavic-pulse.com, Port: 80, HTTPS: włączone, Certificate: letsencrypt
  3. Deploy / poczekaj ~30 s na wystawienie certyfikatu
  4. Sprawdź: curl -I https://www.slavic-pulse.com (powinno być HTTP 200 lub 301, bez błędu SSL)
  5. (Opcjonalnie) Advanced → Redirectswww to non-www

Alternatywa w DNS (OVH): zamiast rekordu A dla www ustaw przekierowanie HTTP na https://slavic-pulse.com w panelu domeny — wtedy ruch www nie trafia na serwer bez certyfikatu.

Facebook / in-app browser: linki w postach powinny wskazywać https://slavic-pulse.com (bez www). Po naprawie www problem znika także dla użytkowników, którzy wpiszą www ręcznie.

Odnowienie certyfikatu: Let's Encrypt odnawia cert automatycznie przez Traefik. Jeśli cert wygasa, w Dokploy sprawdź logi Traefik i czy port 80 jest dostępny z internetu (HTTP-01 challenge).