docs(security): update Hetzner guide with all security hardening for rebuild
Some checks failed
CI / ruff (push) Successful in 11s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

- Fix Gitea docker-compose in Step 7 to bind port 3000 to 127.0.0.1
- Add REDIS_PASSWORD to Step 10 critical production values
- Replace misleading UFW rules with Docker port binding instructions
- Add warning about Docker bypassing UFW in Step 14
- Add initial setup note for temporary Gitea port exposure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 23:33:53 +01:00
parent b68d542258
commit 2268f32f51

View File

@@ -330,8 +330,8 @@ services:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
- "127.0.0.1:3000:3000" # Localhost only — Caddy proxies git.wizard.lu
- "2222:22" # SSH must stay public (Caddy can't proxy SSH)
depends_on:
gitea-db:
condition: service_healthy
@@ -359,14 +359,16 @@ volumes:
Generate the database password with `openssl rand -hex 16` and replace `<GENERATED_PASSWORD>` in both places.
Open the firewall for Gitea and start:
Start Gitea:
```bash
sudo ufw allow 3000/tcp
docker compose up -d
docker compose ps
```
!!! note "Initial setup only"
For initial setup, temporarily change the Gitea port to `"3000:3000"` (without `127.0.0.1`) so you can access the web UI from your browser at `http://91.99.65.229:3000`. After Caddy is configured (Step 14), change it back to `"127.0.0.1:3000:3000"` and access via `https://git.wizard.lu` instead.
Visit `http://91.99.65.229:3000` and complete the setup wizard. Create an admin account (e.g. `sboulahtit`).
Then create a repository (e.g. `orion`).
@@ -435,6 +437,7 @@ Generate secrets:
```bash
openssl rand -hex 32 # For JWT_SECRET_KEY
openssl rand -hex 16 # For database password
openssl rand -hex 16 # For Redis password
```
| Variable | How to Generate / What to Set |
@@ -444,7 +447,8 @@ openssl rand -hex 16 # For database password
| `JWT_SECRET_KEY` | Output of `openssl rand -hex 32` |
| `ADMIN_PASSWORD` | Strong password |
| `USE_CELERY` | `true` |
| `REDIS_URL` | `redis://redis:6379/0` |
| `REDIS_PASSWORD` | Output of `openssl rand -hex 16` |
| `REDIS_URL` | `redis://redis:6379/0` (docker-compose handles auth via `REDIS_PASSWORD`) |
| `STRIPE_SECRET_KEY` | Your Stripe secret key (configure later) |
| `STRIPE_PUBLISHABLE_KEY` | Your Stripe publishable key (configure later) |
| `STRIPE_WEBHOOK_SECRET` | Your Stripe webhook secret (configure later) |
@@ -452,6 +456,9 @@ openssl rand -hex 16 # For database password
Also update the PostgreSQL password in `docker-compose.yml` (lines 9 and 40) to match.
!!! danger "Docker bypasses UFW"
Docker manipulates iptables directly. Never use bare port mappings like `"5432:5432"` in docker-compose — they expose services to the internet regardless of UFW rules. See [Step 20.0](#200-docker-port-binding-critical-docker-bypasses-ufw) for details.
## Step 11: Deploy with Docker Compose
```bash
@@ -721,13 +728,19 @@ curl -I https://api.wizard.lu/health
curl -I https://git.wizard.lu
```
After Caddy is working, remove the temporary firewall rules:
After Caddy is working, lock down Gitea's port to localhost in `~/gitea/docker-compose.yml`:
```bash
sudo ufw delete allow 3000/tcp
sudo ufw delete allow 8001/tcp
```yaml
ports:
- "127.0.0.1:3000:3000" # Localhost only — Caddy proxies git.wizard.lu
- "2222:22" # SSH must stay public (Caddy can't proxy SSH)
```
Then restart Gitea: `cd ~/gitea && docker compose up -d gitea`
!!! warning "Do NOT rely on UFW for Docker ports"
Docker bypasses UFW entirely. The only way to restrict Docker port access is to bind to `127.0.0.1` in the port mapping. See [Step 20.0](#200-docker-port-binding-critical-docker-bypasses-ufw).
Update Gitea's configuration to use its new domain. In `~/gitea/docker-compose.yml`, change:
```yaml