- 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
3.6 KiB
3.6 KiB
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
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
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:
- Brak sekcji
ports:— ruch wchodzi wyłącznie przez Traefika. Opublikowany port omija ufw i jest widoczny z internetu. dbjest tylko winternal. Kontener w sieciedgejest osiągalny dla każdej innej usługi wedge— baza nie ma tam czego szukać.- Wersja obrazu przypięta.
:latestoznacza, że przyszłypullmoże podmienić działającą aplikację na wersję z breaking changes.
4. Sekrety
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
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
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:
# 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