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>
This commit is contained in:
@@ -9,6 +9,7 @@ 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
|
||||
@@ -29,19 +30,18 @@ site-slavic-pulse-com/
|
||||
- `www.slavic-pulse.com` ← **wymagane** — 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
|
||||
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,
|
||||
ale **nie** zastępuje credentials dla `git clone` wewnątrz kontenera przy starcie.
|
||||
Dla prywatnego repo: ustaw repo jako Public **lub** dodaj `GITEA_REPO_URL` z Deploy Token w `.env`.
|
||||
**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. **Start kontenera** — `git clone` repozytorium z Gitea
|
||||
2. **`generate-from-env.sh`** — buduje `index.html` i `site.webmanifest` ze zmiennych `.env`
|
||||
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
|
||||
@@ -50,43 +50,61 @@ Dla prywatnego repo: ustaw repo jako Public **lub** dodaj `GITEA_REPO_URL` z Dep
|
||||
|
||||
| Zmienna | Opis |
|
||||
|---------|------|
|
||||
| `GITEA_REPO_URL` | Opcjonalnie — URL clone z tokenem dla prywatnego repo |
|
||||
| `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 |
|
||||
|
||||
## Rozwiązywanie problemów
|
||||
**Nie dodawaj do produkcyjnego `.env`:** `GITEA_REPO_URL`, `FRONTEND_PORT` — nie są używane w tym modelu deployu.
|
||||
|
||||
### Kontener `Restarting (128)`, brak portów w `docker ps`
|
||||
## Hardening bezpieczeństwa (wbudowany)
|
||||
|
||||
**Przyczyna:** `git clone` nie może pobrać repozytorium (najczęściej **prywatne repo** bez credentials).
|
||||
- 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
|
||||
|
||||
**Diagnostyka na serwerze:**
|
||||
```bash
|
||||
docker logs slavic-pulse-com-frontend --tail 50
|
||||
# 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
|
||||
```
|
||||
|
||||
Typowy błąd:
|
||||
```
|
||||
fatal: could not read Username for 'https://gitea.expert-it.agency-ai.dev': No such device or address
|
||||
```
|
||||
|
||||
**Rozwiązanie A (najprostsze):** ustaw repozytorium jako **Public** w Gitea → Settings → Repository → Make Repository Public → redeploy.
|
||||
|
||||
**Rozwiązanie B (repo prywatne):** w Gitea utwórz Deploy Token / PAT i dodaj do `.env` w Dokploy:
|
||||
```env
|
||||
GITEA_REPO_URL=https://oauth2:TWÓJ_TOKEN@gitea.expert-it.agency-ai.dev/tomasz-syn-grzegorza/site-slavic-pulse-com.git
|
||||
```
|
||||
## 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:**
|
||||
```bash
|
||||
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 (przy starcie ponownie klonuje repo i generuje HTML)
|
||||
2. Redeploy / restart kontenera (entrypoint regeneruje HTML z nowych zmiennych)
|
||||
|
||||
### Błąd certyfikatu SSL na telefonie („serwer nie potrafi udowodnić…”)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user