Compare commits

...
11 Commits
Author SHA1 Message Date
kacperor 05fe953c7f Mirror repo infra: Gitea + GitHub push mirror skonfigurowane i zweryfikowane 2026-08-20 20:27:50 +02:00
kacperor ed353be05d Krok 13 (2/3): Gitea uruchomiona pod git.dfkk.cloud
- gitea/gitea:1.27.2 + postgres:18.6 (najnowsze stabilne tagi)
- rejestracja wyłączona od startu (DISABLE_REGISTRATION=true),
  bezpieczniej niż wyłączanie ręcznie po pierwszym logowaniu
- baza tylko w sieci gitea-internal, bez edge
- postgres 18+: poprawiony mount na /var/lib/postgresql (zmiana
  konwencji względem starszych wersji, image inaczej nie startował)
- dane w /srv/data/gitea/{gitea,postgres}, .env poza repo
- dodano DNS wildcard *.dfkk.cloud -> 54.38.159.156
- zweryfikowane: HTTPS 200, cert Let's Encrypt ważny, rejestracja
  faktycznie zablokowana, SSH kontenera nieopublikowany na hosta
2026-08-20 19:28:14 +02:00
kacperor afaafe8910 Krok 13 (1/3): Traefik uruchomiony, TLS DNS-01 przez OVH
- traefik:v3.7.11 (najnowszy stabilny tag, sprawdzony w Docker Hub)
- DNS-01 challenge, provider ovh, endpoint ovh-ca (region panelu)
- dashboard tylko na 127.0.0.1:8080, dostęp przez tunel SSH
- docker.sock zamontowany read-only
- .env z kluczami API OVH poza repo (chmod 600), .env.example w repo
- zweryfikowane: redirect 80->443, dashboard 200 lokalnie, czyste logi
2026-08-20 18:58:26 +02:00
kacperor 8e8b7e636e Krok 11 bootstrapu: snapshot OVH zapisany w dzienniku 2026-08-20 18:27:03 +02:00
kacperor c678013750 Krok 10 bootstrapu: struktura /srv/apps i /srv/data utworzona 2026-08-20 18:26:31 +02:00
kacperor 5eed89ebb4 Krok 9 bootstrapu: konfiguracja tmux dopisana i przeładowana 2026-08-20 18:24:53 +02:00
kacperor 8532e2694d Krok 8 bootstrapu: Docker CE zainstalowany, limity logów, sieć edge 2026-08-20 18:23:57 +02:00
kacperor 0458c20bb0 Krok 7 bootstrapu: swap 2G aktywny, swappiness=10 2026-08-20 18:22:56 +02:00
kacperor 799242962a Krok 6 bootstrapu: unattended-upgrades aktywne, Automatic-Reboot=false jawnie ustawiony 2026-08-20 18:22:21 +02:00
kacperor 0ce7b204cf Krok 5 bootstrapu: fail2ban aktywny, jail sshd 2026-08-20 18:21:11 +02:00
kacperor 743b5bdd7d Krok 4 bootstrapu: ufw aktywny, deny incoming, dozwolone 22/80/443 2026-08-20 18:20:30 +02:00
5 changed files with 128 additions and 5 deletions
+21 -5
View File
@@ -20,7 +20,7 @@ Ostatnia aktualizacja: _(uzupełnić przy pierwszym bootstrapie)_
| IPv4 | `54.38.159.156` | | IPv4 | `54.38.159.156` |
| IPv6 | _(uzupełnić)_ | | IPv6 | _(uzupełnić)_ |
| Snapshot OVH | włączony, 1 slot, ręczny | | Snapshot OVH | włączony, 1 slot, ręczny |
| Data ostatniego snapshota | _(uzupełniać przy każdym)_ | | Data ostatniego snapshota | 2026-08-20 — po Kroku 10 (system utwardzony: SSH, ufw, fail2ban, unattended-upgrades, swap, Docker), przed Krokiem 13 (Traefik/Gitea) |
--- ---
@@ -39,10 +39,15 @@ Klucze API OVH: przechowywane w `/srv/infra/stacks/traefik/.env` (poza repo).
| Subdomena | Usługa | Publiczna? | Uwagi | | Subdomena | Usługa | Publiczna? | Uwagi |
|---|---|---|---| |---|---|---|---|
| `git.dfkk.cloud` | Gitea | tak | rejestracja wyłączona | | `git.dfkk.cloud` | Gitea | tak | rejestracja wyłączona od startu (`DISABLE_REGISTRATION=true`), zweryfikowana |
| `status.dfkk.cloud` | Uptime Kuma | tak | za basic auth | | `status.dfkk.cloud` | Uptime Kuma | tak | za basic auth |
| `traefik.dfkk.cloud` | Traefik dashboard | nie | tylko przez tunel SSH | | `traefik.dfkk.cloud` | Traefik dashboard | nie | tylko przez tunel SSH |
**Uwaga:** w strefie DNS znaleziono rekordy `n8n.dfkk.cloud`, `portainer.dfkk.cloud`,
`code.dfkk.cloud`, `biznesai.dfkk.cloud` — pozostałość po wcześniejszych eksperymentach,
nic za nimi nie stoi. Do posprzątania przy okazji (usunięcie rekordów w panelu OVH,
runbook `30-usuwanie.md`), nie pilne.
--- ---
## 3. Użytkownicy systemowi ## 3. Użytkownicy systemowi
@@ -85,8 +90,8 @@ Pamiętaj: opublikowany port kontenera omija ufw — patrz `CLAUDE.md`, sekcja 3
| Stack | Ścieżka | Status | Opis | | Stack | Ścieżka | Status | Opis |
|---|---|---|---| |---|---|---|---|
| Traefik | `/srv/infra/stacks/traefik` | _(planowany)_ | reverse proxy, TLS, wejście do wszystkiego | | Traefik | `/srv/infra/stacks/traefik` | **działa** (od 2026-08-20) | reverse proxy, TLS DNS-01 przez OVH (`ovh-ca`), image `traefik:v3.7.11`, dashboard tylko przez tunel SSH (`127.0.0.1:8080`) |
| Gitea | `/srv/infra/stacks/gitea` | _(planowany)_ | repozytoria kodu, mirror na GitHub | | Gitea | `/srv/infra/stacks/gitea` | **działa** (od 2026-08-20) | `gitea/gitea:1.27.2` + `postgres:18.6`, dane w `/srv/data/gitea/{gitea,postgres}`, mirror na GitHub — **do zrobienia** |
| Monitoring | `/srv/infra/stacks/monitoring` | _(planowany)_ | Uptime Kuma, alerty na maila | | Monitoring | `/srv/infra/stacks/monitoring` | _(planowany)_ | Uptime Kuma, alerty na maila |
--- ---
@@ -116,7 +121,7 @@ i czyszczona przy usuwaniu (runbook `30-usuwanie.md`).
| Usługa | Do czego | Gdzie klucz/token | | Usługa | Do czego | Gdzie klucz/token |
|---|---|---| |---|---|---|
| OVH API | DNS-01 dla Traefika | `/srv/infra/stacks/traefik/.env` | | OVH API | DNS-01 dla Traefika | `/srv/infra/stacks/traefik/.env` |
| GitHub | mirror repo `infra` | token w Gitei, ustawienia push mirror | | GitHub | mirror repo `infra` (`github.com/4nalconda/infra`, prywatne) | classic PAT (`repo`, no expiration) w ustawieniach Push Mirror w Gitei |
| SMTP (Resend/Brevo) | wysyłka maili z aplikacji | `.env` danego projektu | | SMTP (Resend/Brevo) | wysyłka maili z aplikacji | `.env` danego projektu |
--- ---
@@ -128,6 +133,17 @@ odtworzyć, co się działo — nie o pełny changelog.
| Data | Co się zmieniło | Kto | | Data | Co się zmieniło | Kto |
|---|---|---| |---|---|---|
| 2026-08-20 | Repo `infra` wypchnięte do Gitei (`kacperor/infra`) i podpięty Push Mirror na GitHub (`4nalconda/infra`, prywatne, sync przy pushu + co 8h). Skonfigurowany `git credential.helper store` na koncie `ubuntu`, żeby Claude mógł pushować bez pytania o token za każdym razem. Warunek z HANDOFF.md (mirror przed dalszą pracą) spełniony | Claude + Kacper |
| 2026-08-20 | Krok 13 bootstrapu (część 2/3 — Gitea): stack `gitea/gitea:1.27.2` + `postgres:18.6` uruchomiony pod `git.dfkk.cloud`, rejestracja wyłączona od startu, konto admina utworzone przez Kacpra w kreatorze instalacji. Napotkano i naprawiono: postgres 18+ wymaga mountu na `/var/lib/postgresql` (nie `/var/lib/postgresql/data`). Dodano rekord DNS wildcard `*.dfkk.cloud → 54.38.159.156`. Zweryfikowane: HTTPS 200, certyfikat Let's Encrypt ważny, rejestracja faktycznie zablokowana, port SSH kontenera nieopublikowany na hosta | Claude + Kacper |
| 2026-08-20 | Krok 13 bootstrapu (część 1/3 — Traefik): stack `traefik:v3.7.11` uruchomiony, DNS-01 przez OVH (endpoint `ovh-ca`), klucze API w `.env` (poza repo, `chmod 600`), dashboard na `127.0.0.1:8080` (tylko tunel SSH). Zweryfikowane: redirect 80→443, dashboard odpowiada lokalnie, logi czyste. Certyfikat wildcard wystawi się przy podpięciu pierwszej usługi (Gitea) | Claude + Kacper |
| 2026-08-20 | Krok 11 bootstrapu: snapshot OVH zrobiony — czysty, utwardzony system przed postawieniem usług | Kacper |
| 2026-08-20 | Krok 10 bootstrapu: `/srv/apps`, `/srv/data` utworzone (`/srv/infra` już istniało), właściciel `ubuntu:ubuntu` | Claude |
| 2026-08-20 | Krok 9 bootstrapu: `~/.tmux.conf` skonfigurowany (mouse, vi keys, `focus-events on`), przeładowany w sesji `bootstrap` bez restartu | Claude |
| 2026-08-20 | Krok 8 bootstrapu: Docker CE (oficjalne repo), `ubuntu` w grupie `docker` (wymaga ponownego logowania), limity logów kontenerów (`max-size 10m`, `max-file 3`), `live-restore`, sieć `edge` utworzona. `hello-world` przeszedł | Claude |
| 2026-08-20 | Krok 7 bootstrapu: swap 2G (`/swapfile`) aktywny, wpis w `fstab`, `vm.swappiness=10` | Claude |
| 2026-08-20 | Krok 6 bootstrapu: unattended-upgrades aktywne (Periodic Update-Package-Lists i Unattended-Upgrade włączone), `Automatic-Reboot` jawnie ustawiony na `false` w `50unattended-upgrades` | Claude |
| 2026-08-20 | Krok 5 bootstrapu: fail2ban aktywny, jail `sshd` (bantime 1h, findtime 10m, maxretry 5). Od razu zbanował ruch skanujący port 22 (normalny szum) | Claude |
| 2026-08-20 | Krok 4 bootstrapu: ufw aktywny, `default deny incoming`, dozwolone 22/80/443 (IPv4+IPv6). Zweryfikowane: SSH nadal dostępny | Claude + Kacper |
| 2026-08-20 | Krok 3 bootstrapu: `PasswordAuthentication no`, `PermitRootLogin no`, `AllowUsers ubuntu` w `sshd_config.d/99-hardening.conf`. Napotkano i naprawiono konflikt: `sshd_config.d/50-cloud-init.conf` nadpisywał hasła z powrotem na `yes` (kolejność alfabetyczna plików Include) — poprawiono plik i dodano `ssh_pwauth: false` w `cloud.cfg.d/`, żeby nie wróciło po reboocie. Zweryfikowane: logowanie kluczem działa, logowanie hasłem zablokowane. **macOS wciąż bez klucza — dostęp z Maca możliwy dopiero po dodaniu klucza przez już uwierzytelnione urządzenie** | Claude + Kacper | | 2026-08-20 | Krok 3 bootstrapu: `PasswordAuthentication no`, `PermitRootLogin no`, `AllowUsers ubuntu` w `sshd_config.d/99-hardening.conf`. Napotkano i naprawiono konflikt: `sshd_config.d/50-cloud-init.conf` nadpisywał hasła z powrotem na `yes` (kolejność alfabetyczna plików Include) — poprawiono plik i dodano `ssh_pwauth: false` w `cloud.cfg.d/`, żeby nie wróciło po reboocie. Zweryfikowane: logowanie kluczem działa, logowanie hasłem zablokowane. **macOS wciąż bez klucza — dostęp z Maca możliwy dopiero po dodaniu klucza przez już uwierzytelnione urządzenie** | Claude + Kacper |
| 2026-08-20 | Krok 1 bootstrapu: timezone Europe/Warsaw, hostname `dfkk`, pakiety bazowe, uporządkowany `/etc/hosts` | Claude | | 2026-08-20 | Krok 1 bootstrapu: timezone Europe/Warsaw, hostname `dfkk`, pakiety bazowe, uporządkowany `/etc/hosts` | Claude |
| 2026-08-20 | Krok 2 bootstrapu: dodane klucze SSH `kacper@KK_HOME_PC` (Windows) i `kacper@iphone` (Termius), zweryfikowane logowaniem. macOS jeszcze do zrobienia | Claude + Kacper | | 2026-08-20 | Krok 2 bootstrapu: dodane klucze SSH `kacper@KK_HOME_PC` (Windows) i `kacper@iphone` (Termius), zweryfikowane logowaniem. macOS jeszcze do zrobienia | Claude + Kacper |
+3
View File
@@ -0,0 +1,3 @@
# Hasło do bazy danych Gitei (postgres)
# Generuj: openssl rand -base64 32
GITEA_DB_PASSWORD=
+55
View File
@@ -0,0 +1,55 @@
services:
gitea:
image: gitea/gitea:1.27.2
container_name: gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
- GITEA__server__DOMAIN=git.dfkk.cloud
- GITEA__server__ROOT_URL=https://git.dfkk.cloud/
- GITEA__server__HTTP_PORT=3000
# Wewnątrz obrazu działa systemowy openssh-server (s6), niezależny od
# wbudowanego SSH Gitei — GITEA__server__DISABLE_SSH go nie wyłącza.
# Nieszkodliwe: port 22 kontenera nie jest publikowany na hosta (brak
# "ports:" w tym serwisie), więc jest nieosiągalny z zewnątrz. Realne
# bezpieczeństwo daje brak publikacji portu, nie ustawienie w app.ini.
- GITEA__service__DISABLE_REGISTRATION=true
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
volumes:
- /srv/data/gitea/gitea:/data
networks:
- edge
- gitea-internal
labels:
- traefik.enable=true
- traefik.http.routers.gitea.rule=Host(`git.dfkk.cloud`)
- traefik.http.routers.gitea.entrypoints=websecure
- traefik.http.routers.gitea.tls.certresolver=ovh
- traefik.http.services.gitea.loadbalancer.server.port=3000
depends_on:
- gitea-db
gitea-db:
image: postgres:18.6
container_name: gitea-db
restart: unless-stopped
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=${GITEA_DB_PASSWORD}
- POSTGRES_DB=gitea
volumes:
- /srv/data/gitea/postgres:/var/lib/postgresql # postgres 18+: mount na /var/lib/postgresql, nie /data
networks:
- gitea-internal # bez edge — baza niewidoczna z zewnątrz
networks:
edge:
external: true
gitea-internal:
name: gitea-internal
+6
View File
@@ -0,0 +1,6 @@
# Klucze API OVH — DNS-01 dla wildcard *.dfkk.cloud
# Panel OVH regionu CA: https://ca.api.ovh.com/createToken/
# Uprawnienia: GET/PUT/POST/DELETE na /domain/zone/*
OVH_APPLICATION_KEY=
OVH_APPLICATION_SECRET=
OVH_CONSUMER_KEY=
+43
View File
@@ -0,0 +1,43 @@
services:
traefik:
image: traefik:v3.7.11
container_name: traefik
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --providers.docker.network=edge
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --entrypoints.traefik.address=:8080
- --api.dashboard=true
- --certificatesresolvers.ovh.acme.dnschallenge=true
- --certificatesresolvers.ovh.acme.dnschallenge.provider=ovh
- --certificatesresolvers.ovh.acme.email=k.kruszka@hotmail.com
- --certificatesresolvers.ovh.acme.storage=/letsencrypt/acme.json
- --log.level=INFO
environment:
- OVH_ENDPOINT=ovh-ca
- OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
- OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
- OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
ports:
- "80:80"
- "443:443"
- "127.0.0.1:8080:8080" # dashboard, wyłącznie przez tunel SSH
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- edge
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.dfkk.cloud`)
- traefik.http.routers.dashboard.entrypoints=traefik
- traefik.http.routers.dashboard.service=api@internal
networks:
edge:
external: true