Files
infra/docs/runbooks/10-nowa-usluga.md
T
kacperor 6ed7a7f4d2 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
2026-08-20 15:53:51 +00:00

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:

  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

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