Ops-dashboard/docs/runbooks/tailscale-setup.md
Janpeter Visser 2b746af1a3 docs(runbook): tailscale-setup plan + uitvoering-addendum
Legt het plan voor de zelf-gehoste Scrum4Me-omgeving (Postgres + app
via Tailscale bereikbaar) versioned vast in de repo, i.p.v. los in
~/Downloads. Bevat:

- Origineel plan (Deel A/B/C/D) zoals opgesteld — host-Postgres +
  host-nginx/Caddy aannames
- Addendum met de feitelijke uitvoering 2026-05-14: de server bleek
  een Docker-stack, dus per stap de Docker-variant (port-mapping i.p.v.
  listen_addresses, docker.service boot-order i.p.v. postgresql.service,
  Caddy al op 0.0.0.0:80, etc.)
- Twee bugs onderweg: stale single-file bind-mount en de http://<IP>
  rode haring
- Verificatie-status en lijst gewijzigde bestanden op scrum4me-srv

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:47:49 +02:00

21 KiB

Ubuntu-omgeving (Postgres + app) via Tailscale bereikbaar maken vanaf de Mac

Context

Er zijn twee Scrum4Me-omgevingen:

  • Omgeving 1 — productie: Vercel + Neon (managed Postgres).
  • Omgeving 2 — nieuw: een eigen Ubuntu-server (scrum4me-srv) die de volledige Scrum4Me-app (Next.js achter een reverse proxy) + zelf-gehoste Postgres gaat draaien.

Het doel: vanaf de Mac (janpeters-macbook-pro) omgeving 2 kunnen gebruiken — voor (1) een DB-client (psql/GUI), (2) de scrum4me-docker runner lokaal in Docker, en (3) lokale dev van de hoofd-Scrum4Me-app.

Tailscale is al geïnstalleerd en verbonden op beide machines:

  • janpeters-macbook-pro100.73.234.116
  • scrum4me-srv100.118.195.120 (Linux, SSH aan)

Wat nog ontbreekt: zowel Postgres als de Next.js-app op de Ubuntu-server luisteren standaard alleen op localhost en zijn nog niet bereikbaar over de Tailscale-interface. De database zelf is al volledig ingericht (schema + data) — er is geen migratie- of seed-werk nodig, alleen netwerk-, auth- en connectie-configuratie.

Beslissingen (van de gebruiker):

  • App-deploy op Ubuntu: reverse proxy (nginx/Caddy) vóór Next.js.
  • DB-toegang: hele tailnet mag erbij (100.64.0.0/10) — bewuste keuze; later eventueel te versmallen via Tailscale ACLs/groups.
  • Postgres-rol: nog onzeker — het plan voegt een controle toe en adviseert een dedicated rol.

Canonieke SCRUM4ME_BASE_URL: http://100.118.195.120 (reverse proxy op poort 80 op de Tailscale-interface, plain HTTP). Tailscale (WireGuard) verzorgt de transportencryptie binnen de tailnet, dus een tweede TLS-laag is hier niet nodig. Dit raw-IP-adres resolvet ook vanuit een Docker-container (geen MagicDNS-afhankelijkheid). HTTPS op de proxy is optionele hardening — zie de noot onderaan; kies je daarvoor, gebruik dan een hostnaam die óók vanuit Docker oplost en pas álle URL's hieronder consistent aan.

Bevinding uit de codebase: in scrum4me-docker is de DB-koppeling puur config. Zowel bin/run-one-job.ts (regel 30, 115) als de MCP-server (mcp-config.json regel 9-10) lezen DATABASE_URL / DIRECT_URL uit de omgeving. bin/check-tokens.sh (regel 35-38) doet bovendien een harde curl ${SCRUM4ME_BASE_URL}/api/products — onbereikbaarheid is fataal (regel 52-57). Er zijn geen code-wijzigingen nodig — alleen .env.

Voorwaarden (aantoonbaar voldaan vóór uitvoering)

  • Tailscale actief op beide machines (tailscale status toont beide nodes)
  • SSH naar scrum4me-srv werkt (ssh scrum4me-srv echo ok)
  • DB-schema aanwezig (tabellen + data) — géén migratie nodig

Voorwaarden (input van de gebruiker nodig)

  • Postgres-rol + wachtwoord + databasenaam op de Ubuntu-server (de "USER", "PASS", "DBNAME" hieronder). Niet in de chat delen — alleen lokaal invullen.
  • De reverse proxy biedt de app aan op http://100.118.195.120 (poort 80). Wijkt dit af, pas dan overal de canonieke URL consistent aan.

Deel A — Ubuntu: Postgres openstellen op de Tailscale-interface

Uit te voeren op scrum4me-srv (via ssh scrum4me-srv of tailscale ssh).

  1. Tailscale-IP bevestigen

    tailscale status
    tailscale ip -4        # verwacht: 100.118.195.120
    
  2. listen_addresses uitbreiden — Postgres bindt standaard alleen aan localhost. Vind het configbestand en pas aan:

    sudo -u postgres psql -c 'SHOW config_file;'   # bv. /etc/postgresql/16/main/postgresql.conf
    

    Zet in dat bestand:

    listen_addresses = 'localhost,100.118.195.120'
    

    Bewust niet '*' — zo bindt Postgres alleen aan localhost + het Tailscale-adres, nooit aan de publieke interface.

    ⚠️ Boot-order: door aan 100.118.195.120 te binden moet tailscale0 al bestaan bij boot. Stap A6 maakt de systemd-ordering verplicht — sla A6 niet over, anders faalt Postgres na een reboot.

  3. Rol, auth-methode en grants controleren/instellen (voorkomt een login- of permission-fout ná goede netwerkconfig). De rol is nog onzeker, dus eerst inventariseren:

    sudo -u postgres psql -c '\du'
    sudo -u postgres psql -c 'SHOW password_encryption;'
    

    Advies: gebruik (of maak) een dedicated runtime-rol die alleen de rechten heeft die de app/runner nodig heeft — geen superuser:

    CREATE ROLE scrum4me_app LOGIN PASSWORD 'lokaal-wachtwoord';
    GRANT CONNECT ON DATABASE DBNAME TO scrum4me_app;
    
    -- runtime-rechten op het bestaande (gevulde) public-schema:
    GRANT USAGE ON SCHEMA public TO scrum4me_app;
    GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO scrum4me_app;
    GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO scrum4me_app;
    
    -- zodat ook later toegevoegde tabellen/sequences werken:
    ALTER DEFAULT PRIVILEGES IN SCHEMA public
      GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO scrum4me_app;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public
      GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO scrum4me_app;
    

    Migraties: deze runtime-rol krijgt bewust géén DDL-rechten. De DB is al ingericht, dus in normale operatie draaien er geen migraties via deze rol. Moet je later vanaf de Mac toch een Prisma-migratie draaien, gebruik dan de DB-owner-rol (apart wachtwoord), niet scrum4me_app.

    SCRAM-verifier: stap A4 kiest scram-sha-256. Een rol waarvan het wachtwoord nog als md5 is opgeslagen kan dan niet inloggen. Forceer een SCRAM-verifier door het wachtwoord opnieuw te zetten (alleen lokaal op de server, niet in chat/docs delen):

    ALTER ROLE scrum4me_app WITH PASSWORD 'lokaal-wachtwoord';
    
  4. pg_hba.conf — toegang vanaf de tailnet toestaan

    sudo -u postgres psql -c 'SHOW hba_file;'
    

    Voeg een regel toe (boven de bestaande host-regels). De gebruiker koos bewust voor toegang vanaf de hele tailnet; maak rol en database wel expliciet i.p.v. all all:

    # Scrum4Me clients via Tailscale
    host    DBNAME    scrum4me_app    100.64.0.0/10    scram-sha-256
    

    Let op: hiermee mag elke tailnet-node mét geldige credentials verbinden. Wil je dat later inperken, doe dat via Tailscale ACLs/groups of versmal het CIDR naar specifieke node-IP's.

  5. Firewall (defense-in-depth) — alleen relevant als ufw actief is:

    sudo ufw status
    sudo ufw allow in on tailscale0 to any port 5432 proto tcp
    

    Open 5432 nooit generiek (sudo ufw allow 5432 zonder interface) — dat zou de DB internet-breed openstellen.

  6. Boot-order — VERPLICHT. Postgres bindt aan 100.118.195.120, een adres dat pas bestaat nadat tailscaled tailscale0 heeft opgezet. Zonder deze override faalt Postgres bij reboot ("cannot assign requested address"). Voeg een systemd-override toe:

    sudo systemctl edit postgresql        # of postgresql@<versie>-main
    
    [Unit]
    After=tailscaled.service
    Requires=tailscaled.service
    
  7. Postgres herstarten en verifiëren

    sudo systemctl restart postgresql
    sudo ss -tlnp | grep 5432      # moet 127.0.0.1:5432 én 100.118.195.120:5432 tonen
    

Deel B — Ubuntu: de Scrum4Me-app (reverse proxy) bereikbaar maken op Tailscale

De runner-tokencheck (check-tokens.sh) cURL't ${SCRUM4ME_BASE_URL}/api/products en faalt hard als die URL onbereikbaar is. De Next.js-app draait achter een reverse proxy, dus de proxy moet op het Tailscale-adres luisteren — niet alleen op localhost. Canoniek: http://100.118.195.120 (poort 80, plain HTTP).

  1. Reverse proxy op de Tailscale-interface laten luisteren (poort 80)

    • nginx: in het server-block het listen-adres aan het Tailscale-IP binden:
      listen 100.118.195.120:80;
      
      sudo nginx -tsudo systemctl reload nginx.
    • Caddy: site-adres http://100.118.195.120:80 in de Caddyfile.
    • Next.js zelf mag op 127.0.0.1:<intern> blijven; alleen de proxy is extern bereikbaar.
  2. Boot-order — VERPLICHT. Net als Postgres bindt de proxy aan een adres dat tailscaled eerst moet aanmaken. Zonder deze override faalt nginx/Caddy bij reboot.

    sudo systemctl edit nginx        # of caddy
    
    [Unit]
    After=tailscaled.service
    Requires=tailscaled.service
    
  3. Firewall voor poort 80 — alleen bij actieve ufw:

    sudo ufw allow in on tailscale0 to any port 80 proto tcp
    
  4. Lokaal op de server verifiëren

    curl -fsS -H "Authorization: Bearer $SCRUM4ME_TOKEN" \
      http://100.118.195.120/api/products >/dev/null && echo OK
    

Deel C — Mac: connectiviteit verifiëren (DB én app)

  1. Tailscale-bereik (al bevestigd: scrum4me-srv zichtbaar op 100.118.195.120):

    tailscale status
    tailscale ping scrum4me-srv
    
  2. MagicDNS check — kan de Mac de server op hostnaam bereiken?

    ping -c1 scrum4me-srv
    

    Zo ja: native macOS-clients mogen scrum4me-srv als host gebruiken.

  3. Postgres — TCP- en psql-test

    nc -vz 100.118.195.120 5432
    psql "postgresql://USER:PASS@100.118.195.120:5432/DBNAME?sslmode=disable" -c '\dt'
    
  4. App — vanaf de Mac én vanuit een Docker-container (Docker Desktop heeft geen Tailscale-MagicDNS; daarom de canonieke raw-IP-URL):

    # vanaf de Mac
    curl -fsS -H "Authorization: Bearer $SCRUM4ME_TOKEN" \
      http://100.118.195.120/api/products >/dev/null && echo "mac OK"
    
    # vanuit een container (simuleert de runner)
    docker run --rm --env SCRUM4ME_TOKEN alpine sh -lc \
      'wget -qO- --header "Authorization: Bearer $SCRUM4ME_TOKEN" \
       http://100.118.195.120/api/products >/dev/null && echo "docker OK"'
    

    Slaagt de container-test niet (geen route naar de tailnet vanuit Docker Desktop), dan moet Tailscale in/naast de runner-container draaien — apart uit te zoeken; eerst de directe route testen.


Deel D — De drie consumenten koppelen

Welke host elke consument gebruikt verschilt — MagicDNS werkt wél native op macOS, maar niet binnen een Docker-container:

Consumer Host Reden
DB-client (psql/TablePlus) native scrum4me-srv MagicDNS werkt op macOS
scrum4me-docker runner (Docker) 100.118.195.120 Docker Desktop heeft geen MagicDNS
Hoofd-app lokale dev scrum4me-srv MagicDNS werkt op macOS

1. DB-client (psql / TablePlus / DBeaver) — native op macOS

Connection-string:

postgresql://USER:PASS@scrum4me-srv:5432/DBNAME?sslmode=disable

GUI-clients: host scrum4me-srv (of 100.118.195.120), poort 5432, SSL uit.

2. scrum4me-docker runner — bewerk /Users/janpetervisser/Development/scrum4me-docker/.env

DATABASE_URL=postgresql://USER:PASS@100.118.195.120:5432/DBNAME?sslmode=disable
DIRECT_URL=postgresql://USER:PASS@100.118.195.120:5432/DBNAME?sslmode=disable
SCRUM4ME_BASE_URL=http://100.118.195.120

Belangrijk:

  • Gebruik het rauwe Tailscale-IP, niet scrum4me-srv. Docker Desktop- containers krijgen geen Tailscale-MagicDNS; de hostnaam resolvet niet binnen de container.
  • Laat de Neon-specifieke params (channel_binding=require, sslmode=verify-full) weg — die gelden niet voor zelf-gehoste Postgres.
  • Zorg dat SCRUM4ME_TOKEN een token van omgeving 2 is — de tokencheck loopt tegen de Ubuntu-app, niet meer tegen Vercel.

SCRUM4ME_TOKEN haal je op via de Ubuntu-app: Settings → API Tokens → nieuw token aanmaken. Een bestaand Vercel-token werkt niet tegen de Ubuntu-omgeving.

3. Hoofd-Scrum4Me-app (lokale dev) — bewerk /Users/janpetervisser/Development/Scrum4Me

Dit is een andere repo dan scrum4me-docker. In die repo de .env.local (of .env) aanpassen. De app draait native op macOS, dus de MagicDNS-hostnaam scrum4me-srv mag hier wél:

DATABASE_URL=postgresql://USER:PASS@scrum4me-srv:5432/DBNAME?sslmode=disable
DIRECT_URL=postgresql://USER:PASS@scrum4me-srv:5432/DBNAME?sslmode=disable

SSL-keuze

Aanbeveling: sslmode=disable voor Postgres en plain HTTP voor de app- URL. Tailscale (WireGuard) versleutelt het transport al end-to-end binnen de tailnet; een tweede TLS-laag op een zelf-gehoste Postgres of op de proxy levert hier vooral configuratie-gedoe op.

Optionele hardening (later, samenhangend uit te voeren):

  • TLS-certs op Postgres + sslmode=require.
  • HTTPS op de reverse proxy. Doe dit dan met een DNS-naam die ook vanuit Docker oplost (raw-IP + cert geeft validatiefouten), en pas SCRUM4ME_BASE_URL én alle verificatie-curls consistent aan naar die https://-hostnaam.

Twee omgevingen naast elkaar houden

Omdat omgeving 1 (Neon) blijft bestaan: bewaar twee env-varianten, bv. .env.neon en .env.ubuntu, en symlink de actieve naar .env:

ln -sf .env.ubuntu .env   # activeer Ubuntu-omgeving
ln -sf .env.neon .env     # activeer Neon-omgeving

Lichtgewicht en voorkomt dat je per ongeluk de verkeerde DB raakt.

Te wijzigen bestanden

Op scrum4me-srv:

  • postgresql.conflisten_addresses.
  • pg_hba.conf — tailnet-regel voor DBNAME + dedicated rol.
  • Postgres-rol — dedicated scrum4me_app-rol + grants + ALTER ROLE ... PASSWORD.
  • nginx/Caddy-config — listen op 100.118.195.120:80.
  • systemd-overrides — After=/Requires=tailscaled.service voor postgresql en de proxy.
  • evt. ufw-regels voor poort 5432 en 80 op tailscale0.

Op de Mac:

  • /Users/janpetervisser/Development/scrum4me-docker/.envDATABASE_URL, DIRECT_URL, SCRUM4ME_BASE_URL, SCRUM4ME_TOKEN.
  • /Users/janpetervisser/Development/Scrum4Me/.env.localDATABASE_URL, DIRECT_URL (andere repo).
  • Géén codewijzigingen in scrum4me-docker.

Verificatie (end-to-end)

  1. Netwerk: nc -vz 100.118.195.120 5432 vanaf de Mac slaagt.
  2. DB-client: psql ".../DBNAME?sslmode=disable" -c '\dt' toont de Scrum4Me-tabellen; een test-INSERT/SELECT bevestigt dat de scrum4me_app-grants kloppen.
  3. App-bereik: de curl/docker run-tests uit Deel C-4 geven beide OK.
  4. Reboot-test: herstart scrum4me-srv; controleer daarna met sudo ss -tlnp dat Postgres én de proxy weer op 100.118.195.120 luisteren, en herhaal de Mac/Docker-connectiviteitstests.
  5. Runner: na .env-update docker compose up -d --force-recreate, dan docker compose logs -fcheck-tokens.sh moet "OK: 100.118.195.120:5432 reachable" én "OK: SCRUM4ME_TOKEN works" loggen, en de daemon-loop moet een job kunnen claimen uit de Ubuntu-DB.
  6. Hoofd-app: lokale dev-server in /Users/janpetervisser/Development/Scrum4Me start en leest data uit de Ubuntu-DB.

Veelvoorkomende fouten

Fout Oorzaak Fix
could not translate host name "scrum4me-srv" MagicDNS niet actief (Docker) Gebruik raw IP 100.118.195.120
cannot assign requested address bij Postgres-start tailscale0 bestaat nog niet A6 systemd-override toevoegen
FATAL: password authentication failed SCRAM-verifier niet bijgewerkt ALTER ROLE scrum4me_app WITH PASSWORD '...' herhalen

Addendum — uitvoering Ubuntu-kant 2026-05-14

Deel A + B zijn uitgevoerd. De server bleek een andere topologie te hebben dan dit plan aannam: Postgres én de reverse proxy draaien als Docker containers, niet host-geïnstalleerd. Dit addendum beschrijft wat er feitelijk is gebeurd. Deel C + D (Mac-kant) staan nog open.

Vastgestelde topologie (wijkt af van de aannames)

Plan nam aan Werkelijkheid op scrum4me-srv
Host-Postgres (/etc/postgresql/..., systemctl postgresql) Docker container scrum4me-postgres (postgres:17), data-volume /srv/scrum4me/postgres
Host nginx/Caddy Docker container scrum4me-caddy (caddy:2), al luisterend op 0.0.0.0:80 + :443
Migratie/seed mogelijk nodig Bevestigd niet nodig — db scrum4me was gevuld

Concrete waarden die het plan openliet:

  • Host = dit ís scrum4me-srv (100.118.195.120) — Deel A/B dus direct uitgevoerd, niet via SSH.
  • DBNAME = scrum4me
  • Rol = scrum4me_app aangemaakt (non-superuser, DML-only), wachtwoord lokaal gegenereerd via openssl rand -hex 24.

Deel A — zoals feitelijk uitgevoerd (Docker-variant)

Plan-stap Aanpassing
A2 listen_addresses in postgresql.conf N.v.t. — de container luistert intern al op 0.0.0.0. Host-exposure = Docker port-mapping. In /srv/scrum4me/compose/docker-compose.yml toegevoegd: - "100.118.195.120:5432:5432" náást de bestaande 127.0.0.1:5432:5432. Specifiek IP i.p.v. 0.0.0.0 — Docker's iptables-DNAT scoped dan op dat IP, publiek blijft dicht.
A3 rol + grants Identiek SQL, maar uitgevoerd via docker exec -i scrum4me-postgres psql -U scrum4me -d scrum4me. Idempotent script (CREATE ROLE of ALTER ROLE ... PASSWORD). De ALTER ROLE ... PASSWORD zet meteen een SCRAM-verifier. Let op: CREATE ROLE op de gedeelde productie-DB wordt door de auto-mode classifier geblokkeerd — moet via een script dat de gebruiker zelf draait.
A4 pg_hba.conf Bestand zit in het data-volume: host-pad /srv/scrum4me/postgres/pg_hba.conf (root-owned, sudo nodig). Regel toegevoegd onderaan (append is veilig — first-match, geen conflict). Bevinding: de postgres-image heeft al een catch-all host all all all scram-sha-256 — onze scoped regel is dáárdoor strikt genomen redundant. Echte bescherming = IP-scoped port-binding + ufw. Catch-all strakker maken = aparte taak (hij draagt de docker-netwerk-clients).
A5 ufw Identiek: ufw allow in on tailscale0 to any port 5432 proto tcp.
A6 boot-order Niet postgresql.service (bestaat niet) maar docker.service. Drop-in /etc/systemd/system/docker.service.d/tailscale-order.conf. Bewust After=tailscaled.service + Wants= i.p.v. het door het plan voorgestelde Requires=Requires op docker.service is fragiel (faalt tailscaled ooit, dan start de hele docker-stack niet). After= lost de race op; Wants= trekt tailscaled mee zonder hard-fail.
A7 restart + verify docker compose up -d postgres (recreate — restart pakt port-wijzigingen niet). ss -tln toont nu 127.0.0.1:5432 én 100.118.195.120:5432. Verificatie met een wegwerp-container: docker run --rm --network host postgres:17 psql "postgresql://scrum4me_app:...@100.118.195.120:5432/scrum4me?sslmode=disable" -c '\dt'--network host simuleert exact hoe de Mac het ziet.

Deel B — zoals feitelijk uitgevoerd (Docker-variant)

Plan-stap Aanpassing
B1 proxy op tailscale-interface Grotendeels al gedaan — de Caddy-container publiceert al 0.0.0.0:80, dus luistert al op tailscale0. Alleen een site-block toegevoegd aan /srv/scrum4me/caddy/Caddyfile: 100.118.195.120:80 { reverse_proxy 172.18.0.1:3000 }.
B2 boot-order proxy Niet nodig. Caddy bindt aan 0.0.0.0:80, niet aan een IP-specifiek adres — er is geen tailscale0-race. (Alleen Postgres had de IP-specifieke binding, vandaar dat A6 wél nodig was.)
B3 ufw poort 80 Niet nodig. Poort 80 stond al op ALLOW IN Anywhere.
B4 verifiëren curl -sI http://100.118.195.120/200 OK, geen redirect. /api/products → 401 (bereikbaar, auth vereist).

Bugs / valkuilen tegengekomen tijdens uitvoering

  1. Caddy single-file bind-mount wordt stale na een atomic-rename edit. /srv/scrum4me/caddy/Caddyfile is als enkel bestand ge-bind-mount. Editors (en de Edit-tooling) schrijven vaak via write-temp + rename = nieuwe inode. De container blijft naar de oude inode wijzen → caddy reload leest de oude content, schijnbaar zonder fout. Symptoom hier: het nieuwe site-block leek "stil gedropt" door Caddy's adapter, maar de container zág het block simpelweg niet. Fix / regel: na een Caddyfile-edit docker compose up -d --force-recreate caddy (of restart) — niet caddy reload. De recreate her-bindt de mount op de nieuwe inode. (Eerder in het project werkte een Caddyfile-edit wél, juist omdat daar toevallig een restart op volgde.)

  2. http://<IP> vs <IP>:80 syntax — bleek een rode haring. Aanvankelijk leek Caddy's Caddyfile-adapter http://100.118.195.120 te droppen. Geïsoleerd getest werkte beide syntaxen prima; het echte probleem was bug #1 (stale mount). De definitieve regel gebruikt 100.118.195.120:80 — ondubbelzinnig plain-HTTP-op-poort-80.

Verificatie-status

Plan verificatie-stap Status
1. nc/TCP naar 5432 psql als scrum4me_app via 100.118.195.120:5432 werkt, ziet tabellen
2. DB-client grants SELECT op idea_products werkt onder scrum4me_app
3. App-bereik http://100.118.195.120/ → 200, /api/products → 401
4. Reboot-test Nog niet gedaan — productie-server niet herstart. Handmatig uitvoeren op rustig moment; check daarna ss -tlnp | grep 5432.
5. Runner — Mac-kant (Deel C/D), nog open
6. Hoofd-app lokale dev — Mac-kant, nog open

Gewijzigde bestanden op scrum4me-srv

  • /srv/scrum4me/compose/docker-compose.yml — postgres ports: extra 100.118.195.120:5432:5432
  • /srv/scrum4me/caddy/Caddyfile — site-block 100.118.195.120:80
  • /srv/scrum4me/postgres/pg_hba.conf — tailnet-regel (+ .bak-<timestamp>)
  • /etc/systemd/system/docker.service.d/tailscale-order.conf — boot-order drop-in (nieuw)
  • ufw — regel 5432/tcp on tailscale0
  • Postgres-rol scrum4me_app — aangemaakt met grants op db scrum4me