Compare commits
10 Commits
c325a4b023
...
76933d21c1
| Author | SHA1 | Date | |
|---|---|---|---|
| 76933d21c1 | |||
| d553094a88 | |||
| a2119d3f9d | |||
| 04c6129efd | |||
| 24b76309dd | |||
| 5263d9a206 | |||
| 80883da0be | |||
| 988999c474 | |||
| b5a3c3fe21 | |||
| 7c7cf1bd02 |
@@ -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
@@ -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
|
||||||
@@ -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
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2
|
build: .
|
||||||
container_name: caddy
|
container_name: caddy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
@@ -11,6 +11,9 @@ services:
|
|||||||
- ./conf:/etc/caddy
|
- ./conf:/etc/caddy
|
||||||
- caddy_data:/data
|
- caddy_data:/data
|
||||||
- caddy_config:/config
|
- caddy_config:/config
|
||||||
|
environment:
|
||||||
|
- BUNNY_API_KEY=${BUNNY_API_KEY}
|
||||||
|
- CADDY_EMAIL=${CADDY_EMAIL}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
caddy_data:
|
caddy_data:
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
+164
-13
@@ -1,20 +1,48 @@
|
|||||||
#(simpleAuth)
|
(auth) {
|
||||||
|
basicauth {
|
||||||
|
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(common) {
|
(common) {
|
||||||
encode gzip zstd
|
encode gzip zstd
|
||||||
header {
|
header {
|
||||||
X-Frame-Options "SAMEORIGIN"
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
X-Content-Type-Options "nosniff"
|
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 {
|
test.gynther.se {
|
||||||
respond "det fungerar"
|
import common
|
||||||
|
reverse_proxy recipe-flutter:5000
|
||||||
}
|
}
|
||||||
|
|
||||||
bazarr.gynther.se {
|
nzbget.gynther.se {
|
||||||
import common
|
import common
|
||||||
reverse_proxy http://bazarr:6767
|
reverse_proxy http://192.168.50.4:6789
|
||||||
}
|
}
|
||||||
|
|
||||||
prowlarr.gynther.se {
|
prowlarr.gynther.se {
|
||||||
@@ -42,16 +70,10 @@ qbittorrent.gynther.se {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wetty.gynther.se {
|
wetty.gynther.se {
|
||||||
|
import auth
|
||||||
import common
|
import common
|
||||||
basic_auth {
|
|
||||||
admin $2a$14$DahHUWD2cKyXJ96sH5VQwuQv1bqmIn0gsdoSaw4mofzfdNY2Y0VsO
|
|
||||||
}
|
|
||||||
redir / /wetty
|
redir / /wetty
|
||||||
reverse_proxy wetty:3000
|
reverse_proxy wetty:3001
|
||||||
}
|
|
||||||
|
|
||||||
portainer.gynther.se {
|
|
||||||
reverse_proxy portainer:9000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gitea.gynther.se {
|
gitea.gynther.se {
|
||||||
@@ -121,3 +143,132 @@ recept.gynther.se {
|
|||||||
# Frontend - catch all remaining routes (port 3000)
|
# Frontend - catch all remaining routes (port 3000)
|
||||||
reverse_proxy /* recipe-frontend: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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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'
|
||||||
@@ -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
|
||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user