Compare commits

..

10 Commits

Author SHA1 Message Date
Nils-Johan Gynther 76933d21c1 feat(caddy): integrate Bunny.net DNS and dynamic IP support
- Replace Bazarr with NZBGet in Caddyfile routes
- Add global DNS provider configuration for ACME DNS-01 challenges
- Implement dynamic DNS updater with Bunny.net provider
- Add comprehensive security headers and authentication
- Update documentation with new requirements and setup instructions
- Add .env.example, Dockerfile, cron jobs, and scripts
- Modify compose.yml to use local build and add environment variables

BREAKING CHANGE: Requires Bunny.net API key and updated Caddyfile configuration
2026-06-04 17:23:35 +02:00
nilsjohan d553094a88 Update Caddyfile routes and auth import 2026-05-30 14:01:19 +02:00
Nils-Johan Gynther a2119d3f9d Update Caddyfile to replace bazarr with nzbget and adjust reverse proxy settings 2026-05-30 13:54:48 +02:00
Nils-Johan Gynther 04c6129efd Add UFW rules to README for Docker Caddy configuration 2026-05-01 20:44:30 +02:00
Nils-Johan Gynther 24b76309dd Add README and technical description for Caddy reverse proxy configuration 2026-05-01 13:30:48 +02:00
nilsjohan 5263d9a206 Uppdaterade Caddyfile utifrån flutter 2026-05-01 12:59:17 +02:00
nilsjohan 80883da0be Update Caddy to 2.4.6. Websockets works 2026-04-15 19:08:07 +02:00
nilsjohan 988999c474 Updatdet Caddyfile 2026-04-15 12:39:46 +02:00
nilsjohan b5a3c3fe21 Updatede [common] to handle cookies
Websocket support on Wetty
2026-04-14 15:50:07 +02:00
nilsjohan 7c7cf1bd02 Changed wettys port to 3001, gave recept.gynter.se basic_auth and updated basic_auth handling 2026-04-13 14:34:02 +02:00
11 changed files with 969 additions and 73 deletions
+8
View File
@@ -0,0 +1,8 @@
# .env.example - Example environment variables for Caddy Bunny
# Copy this file to .env and fill in your actual values
# Bunny.net API Key (required for DNS management)
BUNNY_API_KEY=your_bunny_api_key_here
# Email for Let's Encrypt account (required for TLS certificates)
CADDY_EMAIL=your_email@example.com
+15
View File
@@ -0,0 +1,15 @@
# Custom Caddy Dockerfile with Bunny DNS and Dynamic DNS modules
# Based on official Caddy Alpine image
FROM caddy:2.7.6-alpine
# Install xcaddy for custom builds
RUN apk add --no-cache xcaddy
# Build Caddy with required modules
RUN xcaddy build \
--output /usr/bin/caddy \
--with github.com/caddy-dns/bunny \
--with github.com/mholt/caddy-dynamicdns
# Verify modules are loaded
RUN caddy list-modules | grep -E "dns.providers.bunny|dynamic_dns" && echo "Modules loaded successfully" || exit 1
+137
View File
@@ -0,0 +1,137 @@
# Caddy Reverse Proxy med Bunny.net DNS och Dynamisk IP
Detta projekt innehåller konfigurationen för en **Docker-installation** av Caddy som fungerar som en reverse proxy för olika tjänster, med stöd för **Bunny.net DNS** och **automatisk IP-uppdatering**.
## Beskrivning
Caddy används för att dirigera trafik till olika tjänster som körs i Docker-containrar. Denna konfiguration inkluderar:
- Säkerhetsrubriker och autentisering för vissa tjänster.
- **Bunny.net DNS-integration** för ACME DNS-01 challenges (Let's Encrypt-certifikat).
- **Dynamisk DNS-uppdatering** när den publika IP:n ändras.
- **Cron-script** för att övervaka IP-förändringar och säkerställa TLS-funktion.
## Tjänster
Följande domäner och tjänster hanteras av Caddy:
- `test.gynther.se``recipe-flutter:5000`
- `bazarr.gynther.se``bazarr:6767`
- `prowlarr.gynther.se``prowlarr:9696`
- `radarr.gynther.se``radarr:7878`
- `sonarr.gynther.se``sonarr:8989`
- `jellyfin.gynther.se``jellyfin:8096`
- `qbittorrent.gynther.se``192.168.50.4:8080`
- `wetty.gynther.se``wetty:3001` (med autentisering)
- `portainer.gynther.se``portainer:9000`
- `gitea.gynther.se``192.168.50.2:3002`
- `import.gynther.se``recipe-import-service:3000`
- `recept.gynther.se` → Kombinerar flera tjänster:
- `recipe-import-service:3000`
- `recipe-frontend:3000`
- `recipe-api:8080`
## Säkerhet
- **Autentisering**: Vissa tjänster, som `wetty.gynther.se`, kräver basautentisering.
- **Säkerhetsrubriker**: Caddy lägger till säkerhetsrubriker för att skydda mot vanliga webbsårbarheter.
- **TLS**: Automatisk certifikatshantering via Let's Encrypt med Bunny.net DNS-01 challenge.
## Installation och Körning
### Förutsättningar
- Docker och Docker Compose installerade.
- Bunny.net API-nyckel (för DNS-hantering).
- Miljövariabler konfigurerade (se `.env.example`).
### Steg
1. **Klona repot och navigera till katalogen:**
```bash
git clone ssh://git@gitea.gynther.se:2222/nilsjohan/caddy-bunny.git
cd caddy-bunny
```
2. **Skapa en `.env`-fil med nödvändiga variabler:**
```bash
cp .env.example .env
# Redigera .env och lägg till din Bunny.net API-nyckel och e-post
```
3. **Bygg och starta containrar:**
```bash
docker-compose build
docker-compose up -d
```
4. **Verifiera att Caddy körs korrekt:**
```bash
docker-compose logs caddy
docker-compose exec caddy caddy list-modules | grep -E "dns.providers.bunny|dynamic_dns"
```
## Konfiguration
### Caddyfile
- **Globala inställningar**:
- `acme_dns bunny {env.BUNNY_API_KEY}`: Aktiverar ACME DNS-01 challenge med Bunny.net.
- `dynamic_dns`: Konfigurerar automatisk uppdatering av DNS-records när IP:n ändras.
- **Site-specifika regler**: Se `conf/Caddyfile` för detaljerad routing.
### Miljövariabler
- `BUNNY_API_KEY`: Bunny.net API-nyckel (för DNS-hantering).
- `CADDY_EMAIL`: E-postadress för Let's Encrypt-kontot.
## Dynamisk DNS och IP-övervakning
### Cron-script
Ett script (`scripts/ddns-cert-sync.sh`) körs periodiskt (var 5:e minut) för att:
1. Kontrollera den publika IP:n.
2. Uppdatera DNS-records om IP:n har ändrats.
3. Starta om Caddy för att säkerställa TLS-synkronisering.
4. Verifiera HTTPS-anslutningar till kritiska domäner.
### Installation av Cron
1. Kopiera cron-filen till servern:
```bash
scp cron/caddy-ddns-cert.cron user@server:/etc/cron.d/caddy-ddns-cert
```
2. Säkerställa att scriptet är körbart:
```bash
chmod +x /app/scripts/ddns-cert-sync.sh
```
## Felsökning
- **Loggar**:
- Caddy-loggar: `docker-compose logs caddy`
- Cron-loggar: `/var/log/cron-caddy-ddns.log`
- Script-loggar: `/var/log/caddy-ddns-cert-sync.log`
- **Vanliga problem**:
- **DNS-uppdateringar misslyckas**: Kontrollera att Bunny.net API-nyckeln är korrekt och att zonen och hostnames är korrekt konfigurerade.
- **TLS-fel**: Verifiera att DNS-records har propagerats korrekt och att Caddy har startats om.
- **Caddy startar inte**: Kontrollera att alla nödvändiga moduler är inkluderade i den anpassade builden (`docker-compose exec caddy caddy list-modules`).
## Uppdatering
För att uppdatera konfigurationen:
1. Redigera `Caddyfile` efter behov.
2. Starta om Caddy-containern:
```bash
docker-compose restart caddy
```
## Rollback
För att återgå till den tidigare versionen:
1. Återgå till det gamla repot:
```bash
cd ../caddy
docker-compose up -d
```
## Licens
MIT
+4 -1
View File
@@ -1,6 +1,6 @@
services:
caddy:
image: caddy:2
build: .
container_name: caddy
restart: unless-stopped
ports:
@@ -11,6 +11,9 @@ services:
- ./conf:/etc/caddy
- caddy_data:/data
- caddy_config:/config
environment:
- BUNNY_API_KEY=${BUNNY_API_KEY}
- CADDY_EMAIL=${CADDY_EMAIL}
volumes:
caddy_data:
+130
View File
@@ -0,0 +1,130 @@
#(simpleAuth)
(auth) {
basic_auth {
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
}
}
(common) {
encode gzip zstd
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
}
}
test.gynther.se {
respond "det fungerar"
}
bazarr.gynther.se {
import common
reverse_proxy http://bazarr:6767
}
prowlarr.gynther.se {
import common
reverse_proxy http://prowlarr:9696
}
radarr.gynther.se {
import common
reverse_proxy http://radarr:7878
}
sonarr.gynther.se {
import common
reverse_proxy http://sonarr:8989
}
jellyfin.gynther.se {
reverse_proxy http://jellyfin:8096
}
qbittorrent.gynther.se {
import common
reverse_proxy 192.168.50.4:8080
}
wetty.gynther.se {
import auth
import common
redir / /wetty
reverse_proxy 172.22.0.6:3000 {
transport http {
websocket
}
}
}
portainer.gynther.se {
reverse_proxy portainer:9000
}
gitea.gynther.se {
import common
reverse_proxy 192.168.50.2:3002
}
# ============================================
# Import Service (Document Converter) - Standalone UI
# ============================================
#import.gynther.se {
# import common
# reverse_proxy recipe-import-service:3000
#}
#
# ============================================
# RECIPE APP + IMPORT SERVICE
# ============================================
recept.gynther.se {
import auth
import common
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-frontend:3000
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-frontend:3000
}
# Frontend - catch all remaining routes (port 3000)
reverse_proxy /* recipe-frontend:3000
}
+223 -72
View File
@@ -1,123 +1,274 @@
#(simpleAuth)
(auth) {
basicauth {
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
}
}
(common) {
encode gzip zstd
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
}
encode gzip zstd
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()"
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Resource-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
}
}
{
# Global DNS provider for ACME DNS challenge
acme_dns bunny {env.BUNNY_API_KEY}
# Dynamic DNS configuration
dynamic_dns {
provider bunny {env.BUNNY_API_KEY}
domains {
gynther.se @ www bazarr prowlarr radarr sonarr jellyfin qbittorrent wetty portainer gitea import recept test nzbget
}
check_interval 5m
ttl 300s
versions ipv4
}
}
test.gynther.se {
respond "det fungerar"
import common
reverse_proxy recipe-flutter:5000
}
bazarr.gynther.se {
import common
reverse_proxy http://bazarr:6767
nzbget.gynther.se {
import common
reverse_proxy http://192.168.50.4:6789
}
prowlarr.gynther.se {
import common
reverse_proxy http://prowlarr:9696
import common
reverse_proxy http://prowlarr:9696
}
radarr.gynther.se {
import common
reverse_proxy http://radarr:7878
import common
reverse_proxy http://radarr:7878
}
sonarr.gynther.se {
import common
reverse_proxy http://sonarr:8989
import common
reverse_proxy http://sonarr:8989
}
jellyfin.gynther.se {
reverse_proxy http://jellyfin:8096
reverse_proxy http://jellyfin:8096
}
qbittorrent.gynther.se {
import common
reverse_proxy 192.168.50.4:8080
import common
reverse_proxy 192.168.50.4:8080
}
wetty.gynther.se {
import common
basic_auth {
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
}
redir / /wetty
reverse_proxy wetty:3000
}
portainer.gynther.se {
reverse_proxy portainer:9000
import auth
import common
redir / /wetty
reverse_proxy wetty:3001
}
gitea.gynther.se {
import common
reverse_proxy 192.168.50.2:3002
import common
reverse_proxy 192.168.50.2:3002
}
# ============================================
# Import Service (Document Converter) - Standalone UI
# ============================================
import.gynther.se {
import common
reverse_proxy recipe-import-service:3000
import common
reverse_proxy recipe-import-service:3000
}
# ============================================
# RECIPE APP + IMPORT SERVICE
# ============================================
recept.gynther.se {
import common
import common
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-frontend:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-frontend:3000
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-frontend:3000
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-frontend:3000
}
# Frontend - catch all remaining routes (port 3000)
reverse_proxy /* recipe-frontend:3000
# Frontend - catch all remaining routes (port 3000)
reverse_proxy /* recipe-frontend:3000
}
}
(common) {
encode gzip zstd
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()"
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Resource-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
}
}
test.gynther.se {
import auth
import common
reverse_proxy recipe-flutter:5000
}
<<<<<<< HEAD
nzbget.gynther.se {
import common
reverse_proxy http://192.168.50.4:6789
}
=======
>>>>>>> 0f6813d (Update Caddyfile routes and auth import)
prowlarr.gynther.se {
import common
reverse_proxy http://prowlarr:9696
}
radarr.gynther.se {
import common
reverse_proxy http://radarr:7878
}
sonarr.gynther.se {
import common
reverse_proxy http://sonarr:8989
}
jellyfin.gynther.se {
reverse_proxy http://jellyfin:8096
}
qbittorrent.gynther.se {
import common
reverse_proxy 192.168.50.4:8080
}
wetty.gynther.se {
import auth
import common
redir / /wetty
reverse_proxy wetty:3001
}
gitea.gynther.se {
import common
reverse_proxy 192.168.50.2:3002
}
# ============================================
# Import Service (Document Converter) - Standalone UI
# ============================================
import.gynther.se {
import common
reverse_proxy recipe-import-service:3000
}
# ============================================
# RECIPE APP + IMPORT SERVICE
# ============================================
recept.gynther.se {
import common
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-flutter:5000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-flutter:5000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-flutter:5000
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-flutter:5000
}
# Frontend - catch all remaining routes (port 5000)
reverse_proxy /* recipe-flutter:5000
}
+125
View File
@@ -0,0 +1,125 @@
(auth) {
basicauth {
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
}
}
(common) {
encode gzip zstd
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
}
}
test.gynther.se {
respond "det fungerar"
}
bazarr.gynther.se {
import common
reverse_proxy http://bazarr:6767
}
prowlarr.gynther.se {
import common
reverse_proxy http://prowlarr:9696
}
radarr.gynther.se {
import common
reverse_proxy http://radarr:7878
}
sonarr.gynther.se {
import common
reverse_proxy http://sonarr:8989
}
jellyfin.gynther.se {
reverse_proxy http://jellyfin:8096
}
qbittorrent.gynther.se {
import common
reverse_proxy 192.168.50.4:8080
}
wetty.gynther.se {
import auth
import common
redir / /wetty
reverse_proxy wetty:3001
}
portainer.gynther.se {
reverse_proxy portainer:9000
}
gitea.gynther.se {
import common
reverse_proxy 192.168.50.2:3002
}
# ============================================
# Import Service (Document Converter) - Standalone UI
# ============================================
import.gynther.se {
import common
reverse_proxy recipe-import-service:3000
}
# ============================================
# RECIPE APP + IMPORT SERVICE
# ============================================
recept.gynther.se {
import common
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-frontend:3000
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-frontend:3000
}
# Frontend - catch all remaining routes (port 3000)
reverse_proxy /* recipe-frontend:3000
}
+127
View File
@@ -0,0 +1,127 @@
#(simpleAuth)
(auth) {
basic_auth {
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
}
}
(common) {
encode gzip zstd
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
}
}
test.gynther.se {
respond "det fungerar"
}
bazarr.gynther.se {
import common
reverse_proxy http://bazarr:6767
}
prowlarr.gynther.se {
import common
reverse_proxy http://prowlarr:9696
}
radarr.gynther.se {
import common
reverse_proxy http://radarr:7878
}
sonarr.gynther.se {
import common
reverse_proxy http://sonarr:8989
}
jellyfin.gynther.se {
reverse_proxy http://jellyfin:8096
}
qbittorrent.gynther.se {
import common
reverse_proxy 192.168.50.4:8080
}
wetty.gynther.se {
import auth
import common
redir / /wetty
reverse_proxy wetty:3001
}
portainer.gynther.se {
reverse_proxy portainer:9000
}
gitea.gynther.se {
import common
reverse_proxy 192.168.50.2:3002
}
# ============================================
# Import Service (Document Converter) - Standalone UI
# ============================================
import.gynther.se {
import common
reverse_proxy recipe-import-service:3000
}
# ============================================
# RECIPE APP + IMPORT SERVICE
# ============================================
recept.gynther.se {
import auth
import common
# === IMPORT SERVICE (Document Converter) ===
# Dessa endpoints måste komma FÖRST innan backend reglerna!
handle /api/recipes/import* {
reverse_proxy recipe-import-service:3000
}
# === RECIPE FRONTEND PROXY ENDPOINTS ===
# Next.js API routes
handle /api/inventory-history-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/admin/merge-preview-proxy {
reverse_proxy recipe-frontend:3000
}
handle /api/recipe-preview-proxy {
reverse_proxy recipe-frontend:3000
}
# === RECIPE BACKEND API ENDPOINTS ===
# Backend körs på port 8080 (från docker-compose)
handle /api/products* {
reverse_proxy recipe-api:8080
}
handle /api/inventory* {
reverse_proxy recipe-api:8080
}
handle /api/recipes* {
reverse_proxy recipe-api:8080
}
# === HEALTH CHECKS ===
handle /health {
reverse_proxy recipe-api:8080
}
# === CATCH ALL ===
# Övriga /api/* går till frontend
handle /api/* {
reverse_proxy recipe-frontend:3000
}
# Frontend - catch all remaining routes (port 3000)
reverse_proxy /* recipe-frontend:3000
}
+3
View File
@@ -0,0 +1,3 @@
# Crontab entry for Caddy Dynamic DNS and Certificate Sync
# Run every 5 minutes to monitor IP changes
*/5 * * * * /bin/bash -c '/app/scripts/ddns-cert-sync.sh >> /var/log/cron-caddy-ddns.log 2>&1'
+123
View File
@@ -0,0 +1,123 @@
#!/bin/bash
# Script: ddns-cert-sync.sh
# Purpose: Monitor public IP changes and ensure Caddy DNS/TLS is synchronized
# Usage: Run via cron (e.g., every 5 minutes)
set -euo pipefail
# Configuration
LOCK_FILE="/tmp/caddy-ddns-cert-sync.lock"
STATE_FILE="/var/lib/caddy/last_ip.txt"
LOG_FILE="/var/log/caddy-ddns-cert-sync.log"
CADDY_BIN="/usr/bin/caddy"
IP_CHECK_URL="https://api.ipify.org?format=txt"
# Logging function
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Check if script is already running
if [ -f "$LOCK_FILE" ]; then
log "Lock file exists. Another instance is running. Exiting."
exit 0
fi
# Create lock file
trap "rm -f '$LOCK_FILE'; exit" INT TERM EXIT
touch "$LOCK_FILE"
# Get current public IP
get_current_ip() {
curl -s --max-time 10 "$IP_CHECK_URL" || echo ""
}
# Read last known IP from state file
read_last_ip() {
if [ -f "$STATE_FILE" ]; then
cat "$STATE_FILE" 2>/dev/null || echo ""
else
echo ""
fi
}
# Write current IP to state file
write_current_ip() {
echo "$1" > "$STATE_FILE"
}
# Test HTTPS connectivity
test_https() {
local domain="$1"
if curl -s --max-time 10 -o /dev/null -w "%{http_code}" "https://$domain/" | grep -q "^200$"; then
return 0
else
return 1
fi
}
# Main execution
log "Starting IP check and Caddy sync"
CURRENT_IP=$(get_current_ip)
if [ -z "$CURRENT_IP" ]; then
log "ERROR: Could not determine current public IP. Retrying in next cycle."
rm -f "$LOCK_FILE"
exit 1
fi
log "Current public IP: $CURRENT_IP"
LAST_IP=$(read_last_ip)
if [ -z "$LAST_IP" ]; then
log "No previous IP found. Writing current IP to state file."
write_current_ip "$CURRENT_IP"
rm -f "$LOCK_FILE"
exit 0
fi
log "Last known IP: $LAST_IP"
if [ "$CURRENT_IP" = "$LAST_IP" ]; then
log "IP unchanged. No action needed."
rm -f "$LOCK_FILE"
exit 0
fi
# IP has changed
log "IP changed from $LAST_IP to $CURRENT_IP. Triggering Caddy reload and TLS verification."
# Update state file
write_current_ip "$CURRENT_IP"
# Reload Caddy to ensure DNS and TLS are synchronized
if [ -x "$CADDY_BIN" ]; then
log "Reloading Caddy..."
if "$CADDY_BIN" reload --config /etc/caddy/Caddyfile; then
log "Caddy reloaded successfully."
else
log "ERROR: Failed to reload Caddy. Attempting restart."
"$CADDY_BIN" stop || true
sleep 2
"$CADDY_BIN" start --config /etc/caddy/Caddyfile --adapter caddyfile || log "ERROR: Failed to restart Caddy."
fi
else
log "ERROR: Caddy binary not found at $CADDY_BIN"
fi
# Verify HTTPS for critical domains
log "Running HTTPS verification for critical domains..."
CRITICAL_DOMAINS=("recept.gynther.se" "jellyfin.gynther.se" "wetty.gynther.se")
for domain in "${CRITICAL_DOMAINS[@]}"; do
if test_https "$domain"; then
log "HTTPS test PASSED for $domain"
else
log "WARNING: HTTPS test FAILED for $domain (may be due to DNS propagation)"
fi
done
log "IP change handling completed."
# Cleanup
rm -f "$LOCK_FILE"
exit 0
+74
View File
@@ -0,0 +1,74 @@
# Teknisk Beskrivning av Caddy Reverse Proxy
## Översikt
Caddy används som en reverse proxy för att hantera trafik till olika interna tjänster. Denna konfiguration är optimerad för att köra i en Docker-miljö och inkluderar säkerhetsåtgärder för att skydda mot vanliga webbsårbarheter.
## Konfiguration
### Grundläggande Struktur
Caddyfilen är uppdelad i två huvudsektioner:
1. **Snippets**: Återanvändbara konfigurationer som kan importeras.
- `(auth)`: Konfigurerar basautentisering.
- `(common)`: Lägger till säkerhetsrubriker och komprimeringsinställningar.
2. **Domänspecifika Regler**: Varje domän har sina egna regler för hur trafiken ska hanteras.
### Snippets
#### `(auth)`
- Använder `basicauth` för att kräva autentisering.
- Användarnamn och lösenord är krypterade med bcrypt.
#### `(common)`
- `encode gzip zstd`: Aktiverar komprimering för att förbättra prestanda.
- **Säkerhetsrubriker**:
- `Strict-Transport-Security`: Tvingar HTTPS och inkluderar subdomäner.
- `X-Content-Type-Options`: Förhindrar MIME-sniffing.
- `X-Frame-Options`: Förhindrar klickkapning.
- `X-XSS-Protection`: Aktiverar XSS-skydd.
- `Referrer-Policy`: Kontrollerar hur referrer-information skickas.
- `Permissions-Policy`: Begränsar tillgång till känsliga API:er.
- `Cross-Origin-Opener-Policy`, `Cross-Origin-Resource-Policy`, `Cross-Origin-Embedder-Policy`: Förbättrar säkerheten för cross-origin-resurser.
### Domänspecifika Regler
Varje domän har en eller flera `reverse_proxy`-regler som dirigerar trafik till rätt tjänst. Vissa domäner, som `recept.gynther.se`, har mer komplexa regler för att hantera flera tjänster.
#### Exempel: `recept.gynther.se`
- **Import Service**: Hanterar `/api/recipes/import*` och dirigerar till `recipe-import-service:3000`.
- **Frontend Proxy**: Hanterar specifika API-endpoints och dirigerar till `recipe-frontend:3000`.
- **Backend API**: Hanterar `/api/products*`, `/api/inventory*`, och `/api/recipes*` och dirigerar till `recipe-api:8080`.
- **Catch All**: All annan trafik dirigeras till `recipe-frontend:3000`.
## Säkerhet
### Autentisering
- Vissa tjänster, som `wetty.gynther.se`, kräver autentisering via `basicauth`.
### Säkerhetsrubriker
- Caddy lägger till flera säkerhetsrubriker för att skydda mot vanliga webbsårbarheter.
## Docker och Nätverk
- Caddy körs i en **Docker-installation** och kommunicerar med andra containrar via Docker-nätverket.
- Trafik mellan containrar är intern och påverkas inte av brandväggsregler på värdservern.
- **Flutter** har en egen Caddy-installation i sin Docker-container för att hantera specifika behov, vilket innebär att `test.gynther.se` dirigeras till `recipe-flutter:5000` där den egna Caddy-installationen körs.
## Brandvägg (UFW)
För att säkerställa att endast önskad trafik når servern:
- Tillåt port 22 (SSH).
- Tillåt port 80 (HTTP) och 443 (HTTPS) för webbtrafik.
## Felsökning
- **Loggar**: Använd `docker-compose logs caddy` för att se Caddy-loggar.
- **Testa Konnektivitet**: Se till att alla tjänster som Caddy ska dirigera trafik till är igång och lyssnar på rätt portar.
- **Uppdatera Konfiguration**: Om ändringar görs i `Caddyfile`, starta om Caddy-containern med `docker-compose restart caddy`.
## Slutsats
Denna konfiguration ger en säker och effektiv lösning för att hantera trafik till flera tjänster med Caddy som reverse proxy. Genom att använda Docker och Caddy kan du enkelt skalera och hantera dina tjänster.