Init repo infra + poprawki runbooka bootstrap i HANDOFF

- Krok 9 (tmux): tee -> tee -a (nie nadpisuj configu), dodano
  focus-events on, poprawiono nazwę sesji na "bootstrap"
- Krok 10: struktura katalogów odzwierciedla stan faktyczny
  (/srv i /srv/infra już istnieją, brakuje apps i data)
- Krok 12: Claude Code oznaczony jako wykonany 20-08-2026,
  instalator natywny bez Node.js
- Nowy Krok 14: audyt po bootstrapie (SSH, ufw, fail2ban,
  unattended-upgrades, swap, Docker, porty, klucze)
- HANDOFF.md: poprawiona numeracja sekcji 6
This commit is contained in:
2026-08-20 15:53:51 +00:00
commit 6ed7a7f4d2
13 changed files with 1733 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
# Runbook 10 — nowa usługa
Od pustego katalogu do działającej aplikacji na własnej subdomenie z HTTPS.
---
## 1. Ustalenia przed startem
| Pytanie | Po co |
|---|---|
| Nazwa projektu (małe litery, myślnik) | katalog, kontenery, sieć, subdomena |
| Publiczna czy wewnętrzna? | czy w ogóle wchodzi do sieci `edge` |
| Baza danych? Jaka? | osobny kontener w sieci wewnętrznej + wpis do backupu |
| Dane trwałe? Gdzie? | bind-mount w `/srv/data/<projekt>` |
| Wysyłka maili? | zewnętrzny SMTP, nigdy lokalny |
| Szacowane zużycie dysku | 100 GB to nasz limit |
---
## 2. Struktura
```bash
mkdir -p /srv/apps/<projekt>
mkdir -p /srv/data/<projekt>
cd /srv/apps/<projekt>
git init
```
Minimum plików: `compose.yaml`, `.env.example`, `.gitignore` (z `.env`), `README.md`.
---
## 3. Wzorzec compose
```yaml
services:
web:
image: <obraz>:<KONKRETNA-WERSJA> # nigdy :latest
container_name: <projekt>-web
restart: unless-stopped
env_file: .env
networks:
- edge
- internal
volumes:
- /srv/data/<projekt>/web:/app/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.<projekt>.rule=Host(`<projekt>.dfkk.cloud`)"
- "traefik.http.routers.<projekt>.entrypoints=websecure"
- "traefik.http.routers.<projekt>.tls.certresolver=ovh"
- "traefik.http.services.<projekt>.loadbalancer.server.port=<PORT-WEWNĘTRZNY>"
db:
image: postgres:16.4
container_name: <projekt>-db
restart: unless-stopped
env_file: .env
networks:
- internal # BEZ edge — baza nie widzi świata
volumes:
- /srv/data/<projekt>/db:/var/lib/postgresql/data
networks:
edge:
external: true
internal:
name: <projekt>-internal
```
**Trzy rzeczy, na które patrzysz w tym pliku:**
1. Brak sekcji `ports:` — ruch wchodzi wyłącznie przez Traefika.
Opublikowany port omija ufw i jest widoczny z internetu.
2. `db` jest tylko w `internal`. Kontener w sieci `edge` jest osiągalny
dla każdej innej usługi w `edge` — baza nie ma tam czego szukać.
3. Wersja obrazu przypięta. `:latest` oznacza, że przyszły `pull` może
podmienić działającą aplikację na wersję z breaking changes.
---
## 4. Sekrety
```bash
cp .env.example .env
chmod 600 .env
openssl rand -base64 32 # tak generujemy hasła, nie wymyślamy ich
```
Sprawdź, że `.env` jest w `.gitignore`, **zanim** zrobisz pierwszy commit.
Sekret raz wypchnięty do repo trzeba unieważnić, nie usunąć.
---
## 5. DNS
Rekord A dla `<projekt>.dfkk.cloud` na IP serwera — panel OVH.
Certyfikat leci z wildcardu `*.dfkk.cloud`, więc **nic dodatkowo nie robisz**.
Szczegóły: `20-domena.md`.
---
## 6. Uruchomienie
```bash
docker compose config # walidacja składni i podstawionych zmiennych
docker compose up -d
docker compose ps
docker compose logs -f --tail=50
```
---
## 7. Weryfikacja — sprawdzasz, nie zakładasz
```bash
curl -I https://<projekt>.dfkk.cloud # 200 lub 3xx, certyfikat ważny
docker compose ps # wszystko "Up", nic w restart loop
docker stats --no-stream # zużycie w granicach rozsądku
```
Test negatywny — potwierdzenie, że baza **nie** jest wystawiona:
```bash
# z lokalnej maszyny, nie z serwera:
nc -zv <IP-serwera> 5432 # ma odmówić połączenia
```
---
## 8. Domknięcie
- [ ] Commit w repo projektu, push do Gitei
- [ ] Wpis w `SERVER.md`: projekt, katalog, repo, domena, wolumeny, baza
- [ ] Wpis w `SERVER.md`, sekcja 2: zajęta subdomena
- [ ] Jeśli są dane trwałe — dopisanie ścieżki do listy backupu
- [ ] Monitor w Uptime Kuma
- [ ] `df -h` — kontrola, ile dysku ubyło