Am făcut accesibile toate serviciile self-hosted prin Tailscale
În articolul anterior am documentat cum am mutat serviciile self-hosted de pe Linux Mint pe un Intel NUC cu Ubuntu Server. La final, Vaultwarden mergea deja prin HTTPS via Tailscale și Caddy, dar celelalte șapte servicii - FreshRSS, Wallabag, Linkding, Booktracker, Paperless-ngx, Domain Locker și Scrutiny - rămăseseră accesibile doar în rețeaua locală.
Voiam să le accesez de pe orice dispozitiv, fără să fiu legat de rețeaua de acasă. Așa că am făcut următorii pași:
Pasul 1 - Crearea unei rețele Docker comune
Caddy ajungea la Vaultwarden prin numele containerului (vaultwarden:80) pentru că erau în aceeași rețea Docker. Celelalte servicii rulau în stacks separate, deci Caddy nu le vedea deloc. Soluția a fost să creez o rețea externă comună:
docker network create caddy-proxy
Apoi am editat fiecare docker-compose.yml să includă rețeaua. De exemplu pentru FreshRSS:
services:
freshrss:
...
networks:
- caddy-proxy
networks:
caddy-proxy:
external: true
Am făcut același lucru pentru wallabag, linkding, booktracker, paperless, domain-locker și scrutiny, apoi am repornit fiecare stack:
for svc in freshrss wallabag linkding booktracker paperless domain-locker scrutiny; do
cd /opt/services/$svc && docker compose up -d
done
Pasul 2 - Actualizarea docker-compose.yml al Caddy
Caddy trebuia să fie în ambele rețele și să expună porturile noi. Am editat /opt/services/caddy/docker-compose.yml:
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8443:8443"
- "6543:6543"
- "9443:9443"
- "2443:2443"
- "8019:8019"
- "3443:3443"
- "8889:8889"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./certs:/certs
- caddy_data:/data
- caddy_config:/config
networks:
- vaultwarden_default
- caddy-proxy
volumes:
caddy_data:
caddy_config:
networks:
vaultwarden_default:
external: true
caddy-proxy:
external: true
Câteva observații despre porturi: portul 8010 era deja ocupat de Paperless pe host, iar 8888 de Scrutiny, deci am ales 8019 și 8889 ca să evit conflictele.
Pasul 3 - Configurarea Caddyfile
Certificatul existent de la Tailscale era valabil doar pentru hostname-ul exact thinkserver.tailxxxx.ts.net, fără subdomenii. Soluția a fost să folosesc porturi diferite pentru fiecare serviciu, toate cu același certificat. Am editat /opt/services/caddy/Caddyfile:
thinkserver.tailxxxx.ts.net {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy vaultwarden:80
}
thinkserver.tailxxxx.ts.net:8443 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy freshrss:80
}
thinkserver.tailxxxx.ts.net:6543 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy wallabag:80
}
thinkserver.tailxxxx.ts.net:9443 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy linkding:9090
}
thinkserver.tailxxxx.ts.net:2443 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy booktracker:5000
}
thinkserver.tailxxxx.ts.net:8019 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy paperless:8000
}
thinkserver.tailxxxx.ts.net:3443 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy domain-locker-app:3000
}
thinkserver.tailxxxx.ts.net:8889 {
tls /certs/thinkserver.tailxxxx.ts.net.crt /certs/thinkserver.tailxxxx.ts.net.key
reverse_proxy scrutiny:8080
}
Un detaliu important: în reverse_proxy trebuie folosit numele containerului, nu cel al serviciului din Compose. De exemplu, Domain Locker are containerul domain-locker-app, nu domain-locker. L-am verificat cu:
grep "container_name" /opt/services/*/docker-compose.yml
Porturile din reverse_proxy sunt cele interne ale containerului, nu cele de pe host. Le-am verificat cu:
grep -A3 "ports:" /opt/services/*/docker-compose.yml
Pasul 4 - Pornirea Caddy și reîncărcarea configurației
cd /opt/services/caddy && docker compose up -d
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
Pasul 5 - Wallabag: actualizarea domeniului
Wallabag generează URL-uri absolute pentru CSS și JavaScript pe baza variabilei SYMFONY__ENV__DOMAIN_NAME. Era setată pe IP-ul local vechi, ceea ce făcea ca grafica să nu se încarce când accesam din afara rețelei. Am actualizat în /opt/services/wallabag/docker-compose.yml:
environment:
- SYMFONY__ENV__DOMAIN_NAME=https://thinkserver.tailxxxx.ts.net:6543
Apoi:
cd /opt/services/wallabag && docker compose up -d
Rezultatul final
Toate serviciile sunt acum accesibile prin HTTPS de pe orice dispozitiv cu Tailscale conectat.