From ccb9d44c04651d1c6caa5cace39ccb3a909348d5 Mon Sep 17 00:00:00 2001 From: KonradHerman Date: Wed, 6 May 2026 13:23:51 -0400 Subject: [PATCH] chore: audit and fix service configurations and allowedOrigins --- _tmp_Caddyfile.txt | 70 +++++++++++++++ _tmp_coolify-noredirect.yaml | 20 +++++ pve/_meta/host-overview.txt | 72 +++++++++++++++ pve/lxc-101-alpine-caddy/_dir-listing.txt | 10 +++ pve/lxc-101-alpine-caddy/etc/caddy/Caddyfile | 62 +++++++++++++ pve/lxc-103-coolify/_docker-ps.txt | 6 ++ .../data/coolify/proxy/docker-compose.yml | 54 +++++++++++ .../data/coolify/proxy/dynamic/Caddyfile | 1 + .../data/coolify/proxy/dynamic/coolify.yaml | 65 ++++++++++++++ .../proxy/dynamic/default_redirect_503.yaml | 18 ++++ pve/lxc-103-coolify/data/coolify/source/.env | 17 ++++ .../coolify/source/docker-compose.prod.yml | 90 +++++++++++++++++++ .../data/coolify/source/docker-compose.yml | 37 ++++++++ 13 files changed, 522 insertions(+) create mode 100644 _tmp_Caddyfile.txt create mode 100644 _tmp_coolify-noredirect.yaml create mode 100644 pve/_meta/host-overview.txt create mode 100644 pve/lxc-101-alpine-caddy/_dir-listing.txt create mode 100644 pve/lxc-101-alpine-caddy/etc/caddy/Caddyfile create mode 100644 pve/lxc-103-coolify/_docker-ps.txt create mode 100644 pve/lxc-103-coolify/data/coolify/proxy/docker-compose.yml create mode 100644 pve/lxc-103-coolify/data/coolify/proxy/dynamic/Caddyfile create mode 100644 pve/lxc-103-coolify/data/coolify/proxy/dynamic/coolify.yaml create mode 100644 pve/lxc-103-coolify/data/coolify/proxy/dynamic/default_redirect_503.yaml create mode 100644 pve/lxc-103-coolify/data/coolify/source/.env create mode 100644 pve/lxc-103-coolify/data/coolify/source/docker-compose.prod.yml create mode 100644 pve/lxc-103-coolify/data/coolify/source/docker-compose.yml diff --git a/_tmp_Caddyfile.txt b/_tmp_Caddyfile.txt new file mode 100644 index 0000000..12e1a2f --- /dev/null +++ b/_tmp_Caddyfile.txt @@ -0,0 +1,70 @@ +# Global options +{ + auto_https disable_redirects + email k.radikal@gmail.com +} + +# Consolidated wildcard site block +*.klhoud.com, http://*.klhoud.com { + # Automatic HTTPS via DNS challenge for all subdomains + tls { + dns cloudflare {$CLOUDFLARE_API_TOKEN} + } + + # Proxmox + @proxmox host proxmox.klhoud.com + handle @proxmox { + reverse_proxy https://192.168.0.112:8006 { + # Required for connecting to Proxmox's self-signed/untrusted certificate + transport http { + tls_insecure_skip_verify + versions 1.1 + } + } + } + + # AdGuard Home + @adguard host adguard.klhoud.com + handle @adguard { + reverse_proxy 192.168.0.170:80 + } + + # Dockge + @dockge host dockge.klhoud.com + handle @dockge { + reverse_proxy 192.168.0.12:5001 + } + + # Nextcloud + @cloud host cloud.klhoud.com + handle @cloud { + reverse_proxy 192.168.0.12:8080 + # Nextcloud-specific headers + header Strict-Transport-Security "max-age=31536000;" + + # Handle large file uploads + request_body { + max_size 10GB + } + } + + # Coolify (control plane runs on LXC 103). Upstream HTTPS to 443 because + # coolify-proxy's HTTP entry forces a redirect-to-https which would loop + # back through us. HTTPS upstream hits the no-redirect routes; cert is + # self-signed since coolify-proxy's ACME for coolify.klhoud.com fails + # (DNS points at us, not it), so we skip verify. + # coolify-proxy (Traefik) on LXC 103 listens on :80. We added a custom + # higher-priority router in /data/coolify/proxy/dynamic/coolify-noredirect.yaml + # there to bypass Coolify's auto-generated http->https redirect (which would + # loop us). WebSocket routes (/app, /terminal/ws) work natively on :80. + @coolify host coolify.klhoud.com + handle @coolify { + reverse_proxy 192.168.0.47:80 + } + + # IMPORTANT: Fallback Handler + # This prevents non-matching requests from falling through and failing. + handle { + respond "Not Found" 404 + } +} diff --git a/_tmp_coolify-noredirect.yaml b/_tmp_coolify-noredirect.yaml new file mode 100644 index 0000000..ecc3f86 --- /dev/null +++ b/_tmp_coolify-noredirect.yaml @@ -0,0 +1,20 @@ +# Override file added by us (homelab-configs). +# Coolify auto-generates /data/coolify/proxy/dynamic/coolify.yaml with a +# redirect-to-https middleware on the HTTP router. That redirect causes a +# loop with our upstream alpine-caddy (LXC 101) which already terminates TLS. +# This higher-priority router wins for the UI but explicitly excludes the +# WebSocket paths so they keep using Coolify's own routers (coolify-realtime-ws +# for /app, coolify-terminal-ws for /terminal/ws). +http: + routers: + coolify-http-noredirect: + entryPoints: + - http + service: coolify-noredirect-svc + rule: 'Host(`coolify.klhoud.com`) && !PathPrefix(`/app`) && !PathPrefix(`/terminal/ws`)' + priority: 1000 + services: + coolify-noredirect-svc: + loadBalancer: + servers: + - url: 'http://coolify:8080' diff --git a/pve/_meta/host-overview.txt b/pve/_meta/host-overview.txt new file mode 100644 index 0000000..ae64586 --- /dev/null +++ b/pve/_meta/host-overview.txt @@ -0,0 +1,72 @@ +=== PVE host info === +pve +Linux pve 6.17.2-1-pve #1 SMP PREEMPT_DYNAMIC PMX 6.17.2-1 (2025-10-21T11:55Z) x86_64 GNU/Linux +pve-manager/9.1.1/42db4a6cf33dac83 (running kernel: 6.17.2-1-pve) + +=== LXC list === +VMID Status Lock Name +100 running alpine-adguard +101 running alpine-caddy +102 running dockge +103 running coolify + +=== VM list === + +=== Per-LXC config === +===LXC-100=== +arch: amd64 +cores: 1 +description:
%0A %0A Logo%0A %0A%0A

Alpine-AdGuard LXC

%0A%0A

%0A %0A spend Coffee%0A %0A

%0A%0A %0A %0A GitHub%0A %0A %0A %0A Discussions%0A %0A %0A %0A Issues%0A %0A
%0A +features: keyctl=1,nesting=1 +hostname: alpine-adguard +memory: 256 +net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:A4:76:5F,ip=dhcp,type=veth +onboot: 1 +ostype: alpine +rootfs: local-lvm:vm-100-disk-0,size=1G +swap: 512 +tags: adblock;alpine;community-script +unprivileged: 1 + +===LXC-101=== +arch: amd64 +cores: 1 +description:
%0A %0A Logo%0A %0A%0A

Alpine-Caddy LXC

%0A%0A

%0A %0A spend Coffee%0A %0A

%0A%0A %0A %0A GitHub%0A %0A %0A %0A Discussions%0A %0A %0A %0A Issues%0A %0A
%0A +features: keyctl=1,nesting=1 +hostname: alpine-caddy +memory: 256 +net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:4E:3F:97,ip=dhcp,type=veth +onboot: 1 +ostype: alpine +rootfs: local-lvm:vm-101-disk-0,size=3G +swap: 512 +tags: community-script;webserver +unprivileged: 1 + +===LXC-102=== +arch: amd64 +cores: 2 +description:
%0A %0A Logo%0A %0A%0A

Dockge LXC

%0A%0A

%0A %0A spend Coffee%0A %0A

%0A%0A %0A %0A GitHub%0A %0A %0A %0A Discussions%0A %0A %0A %0A Issues%0A %0A
%0A +features: keyctl=1,nesting=1 +hostname: dockge +memory: 2048 +net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:FA:D7:D4,ip=dhcp,type=veth +onboot: 1 +ostype: debian +rootfs: local-lvm:vm-102-disk-0,size=18G +swap: 512 +tags: community-script;docker +unprivileged: 1 + +===LXC-103=== +arch: amd64 +cores: 2 +features: nesting=1 +hostname: coolify +memory: 4096 +net0: name=eth0,bridge=vmbr0,firewall=1,hwaddr=BC:24:11:36:EC:64,ip=dhcp,type=veth +ostype: debian +rootfs: local-lvm:vm-103-disk-0,size=60G +swap: 512 +unprivileged: 1 + diff --git a/pve/lxc-101-alpine-caddy/_dir-listing.txt b/pve/lxc-101-alpine-caddy/_dir-listing.txt new file mode 100644 index 0000000..70b3403 --- /dev/null +++ b/pve/lxc-101-alpine-caddy/_dir-listing.txt @@ -0,0 +1,10 @@ +total 28 +drwxr-xr-x 2 root root 4096 May 6 09:27 . +drwxr-xr-x 32 root root 4096 Apr 30 02:29 .. +-rw-r--r-- 1 root root 1471 May 6 09:27 Caddyfile +-rw-r--r-- 1 root root 1390 Nov 25 05:04 Caddyfile.bak.1777516902 +-rw-r--r-- 1 root root 1444 Apr 30 02:43 Caddyfile.bak.1777517752 +-rw-r--r-- 1 root root 1473 May 6 09:27 Caddyfile.bak.1778059646 +-rw------- 1 root root 62 Oct 13 2025 caddy.env +--- +ls: /etc/caddy/Caddyfile.bak.*: No such file or directory diff --git a/pve/lxc-101-alpine-caddy/etc/caddy/Caddyfile b/pve/lxc-101-alpine-caddy/etc/caddy/Caddyfile new file mode 100644 index 0000000..a8de7bd --- /dev/null +++ b/pve/lxc-101-alpine-caddy/etc/caddy/Caddyfile @@ -0,0 +1,62 @@ +# Global options +{ + auto_https disable_redirects + email k.radikal@gmail.com +} + +# Consolidated wildcard site block +*.klhoud.com, http://*.klhoud.com { + # Automatic HTTPS via DNS challenge for all subdomains + tls { + dns cloudflare {$CLOUDFLARE_API_TOKEN} + } + + # Proxmox + @proxmox host proxmox.klhoud.com + handle @proxmox { + reverse_proxy https://192.168.0.112:8006 { + # Required for connecting to Proxmox's self-signed/untrusted certificate + transport http { + tls_insecure_skip_verify + versions 1.1 + } + } + } + + # AdGuard Home + @adguard host adguard.klhoud.com + handle @adguard { + reverse_proxy 192.168.0.170:80 + } + + # Dockge + @dockge host dockge.klhoud.com + handle @dockge { + reverse_proxy 192.168.0.12:5001 + } + + # Nextcloud + @cloud host cloud.klhoud.com + handle @cloud { + reverse_proxy 192.168.0.12:8080 + # Nextcloud-specific headers + header Strict-Transport-Security "max-age=31536000;" + + # Handle large file uploads + request_body { + max_size 10GB + } + } + + # Coolify + @coolify host coolify.klhoud.com + handle @coolify { + reverse_proxy 192.168.0.47:80 + } + + # IMPORTANT: Fallback Handler + # This prevents non-matching requests from falling through and failing. + handle { + respond "Not Found" 404 + } +} diff --git a/pve/lxc-103-coolify/_docker-ps.txt b/pve/lxc-103-coolify/_docker-ps.txt new file mode 100644 index 0000000..645e597 --- /dev/null +++ b/pve/lxc-103-coolify/_docker-ps.txt @@ -0,0 +1,6 @@ +coolify ghcr.io/coollabsio/coolify:4.0.0 Up 6 days (healthy) +coolify-db postgres:15-alpine Up 6 days (healthy) +coolify-redis redis:7-alpine Up 6 days (healthy) +coolify-realtime ghcr.io/coollabsio/coolify-realtime:1.0.13 Up 6 days (healthy) +coolify-sentinel ghcr.io/coollabsio/sentinel:0.0.21 Up 2 weeks (healthy) +coolify-proxy traefik:v3.6 Up 5 months (healthy) diff --git a/pve/lxc-103-coolify/data/coolify/proxy/docker-compose.yml b/pve/lxc-103-coolify/data/coolify/proxy/docker-compose.yml new file mode 100644 index 0000000..332de4e --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/proxy/docker-compose.yml @@ -0,0 +1,54 @@ +name: coolify-proxy +networks: + coolify: + external: true +services: + traefik: + container_name: coolify-proxy + image: 'traefik:v3.6' + restart: unless-stopped + extra_hosts: + - 'host.docker.internal:host-gateway' + networks: + - coolify + ports: + - '80:80' + - '443:443' + - '443:443/udp' + - '8080:8080' + healthcheck: + test: 'wget -qO- http://localhost:80/ping || exit 1' + interval: 4s + timeout: 2s + retries: 5 + volumes: + - '/var/run/docker.sock:/var/run/docker.sock:ro' + - '/data/coolify/proxy/:/traefik' + command: + - '--ping=true' + - '--ping.entrypoint=http' + - '--api.dashboard=true' + - '--entrypoints.http.address=:80' + - '--entrypoints.http.forwardedheaders.trustedips=192.168.0.40' + - '--entrypoints.https.address=:443' + - '--entrypoints.https.forwardedheaders.trustedips=192.168.0.40' + - '--entrypoints.http.http.encodequerysemicolons=true' + - '--entryPoints.http.http2.maxConcurrentStreams=250' + - '--entrypoints.https.http.encodequerysemicolons=true' + - '--entryPoints.https.http2.maxConcurrentStreams=250' + - '--entrypoints.https.http3' + - '--providers.file.directory=/traefik/dynamic/' + - '--providers.file.watch=true' + - '--certificatesresolvers.letsencrypt.acme.httpchallenge=true' + - '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http' + - '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json' + - '--api.insecure=false' + - '--providers.docker=true' + - '--providers.docker.exposedbydefault=false' + labels: + - traefik.enable=true + - traefik.http.routers.traefik.entrypoints=http + - traefik.http.routers.traefik.service=api@internal + - traefik.http.services.traefik.loadbalancer.server.port=8080 + - coolify.managed=true + - coolify.proxy=true \ No newline at end of file diff --git a/pve/lxc-103-coolify/data/coolify/proxy/dynamic/Caddyfile b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/Caddyfile new file mode 100644 index 0000000..1a8d379 --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/Caddyfile @@ -0,0 +1 @@ +import /dynamic/*.caddy diff --git a/pve/lxc-103-coolify/data/coolify/proxy/dynamic/coolify.yaml b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/coolify.yaml new file mode 100644 index 0000000..a9c1c78 --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/coolify.yaml @@ -0,0 +1,65 @@ +# This file is automatically generated by Coolify. +# Do not edit it manually (only if you know what are you doing). + +http: + middlewares: + redirect-to-https: + redirectscheme: + scheme: https + gzip: + compress: true + routers: + coolify-http: + middlewares: + - redirect-to-https + entryPoints: + - http + service: coolify + rule: Host(`coolify.klhoud.com`) + coolify-realtime-ws: + entryPoints: + - http + service: coolify-realtime + rule: 'Host(`coolify.klhoud.com`) && PathPrefix(`/app`)' + coolify-terminal-ws: + entryPoints: + - http + service: coolify-terminal + rule: 'Host(`coolify.klhoud.com`) && PathPrefix(`/terminal/ws`)' + coolify-https: + entryPoints: + - https + service: coolify + rule: Host(`coolify.klhoud.com`) + tls: + certresolver: letsencrypt + coolify-realtime-wss: + entryPoints: + - https + service: coolify-realtime + rule: 'Host(`coolify.klhoud.com`) && PathPrefix(`/app`)' + tls: + certresolver: letsencrypt + coolify-terminal-wss: + entryPoints: + - https + service: coolify-terminal + rule: 'Host(`coolify.klhoud.com`) && PathPrefix(`/terminal/ws`)' + tls: + certresolver: letsencrypt + services: + coolify: + loadBalancer: + servers: + - + url: 'http://coolify:8080' + coolify-realtime: + loadBalancer: + servers: + - + url: 'http://coolify-realtime:6001' + coolify-terminal: + loadBalancer: + servers: + - + url: 'http://coolify-realtime:6002' diff --git a/pve/lxc-103-coolify/data/coolify/proxy/dynamic/default_redirect_503.yaml b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/default_redirect_503.yaml new file mode 100644 index 0000000..bfd0202 --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/proxy/dynamic/default_redirect_503.yaml @@ -0,0 +1,18 @@ +# This file is generated by Coolify, do not edit it manually. +# Disable the default redirect to customize (only if you know what are you doing). + +http: + routers: + catchall: + entryPoints: + - http + - https + service: noop + rule: PathPrefix(`/`) + tls: + certResolver: letsencrypt + priority: -1000 + services: + noop: + loadBalancer: + servers: { } diff --git a/pve/lxc-103-coolify/data/coolify/source/.env b/pve/lxc-103-coolify/data/coolify/source/.env new file mode 100644 index 0000000..aef9a1d --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/source/.env @@ -0,0 +1,17 @@ +APP_ID=4ade2d03d47e25dbd2477aebeea02f68 +APP_NAME=Coolify +APP_KEY=base64:/NXqvQqLEoiL2l95unMEgIrmNISZWCN3gkn8C+70ArU= +APP_URL=https://coolify.klhoud.com + +DB_USERNAME=coolify +DB_PASSWORD=NK7UZfGH6s+xK1FCWhZ16UIW5+XLSyJWUW/SAeiUqr0= +REDIS_PASSWORD=hFFgieL5zun4R259weXB5mwB+obiNqzgFbZ+/TybQwM= +PUSHER_APP_ID=a62f9819f9aa86b34b07973a11f6f844029c1a5a1cfc96e36ee93629ba0194f6 +PUSHER_APP_KEY=904493523fc1e3b042fdac7ee119aa44220799fbbb0199259d911a1860ea3c19 +PUSHER_APP_SECRET=5ec83d045498cfaeba51bc0bd6a84957a81892383c98a1a2f24e4a6f192f6387 +ROOT_USERNAME= +ROOT_USER_EMAIL= +ROOT_USER_PASSWORD= +REGISTRY_URL=ghcr.io +DOCKER_ADDRESS_POOL_BASE=10.0.0.0/8 +DOCKER_ADDRESS_POOL_SIZE=24 diff --git a/pve/lxc-103-coolify/data/coolify/source/docker-compose.prod.yml b/pve/lxc-103-coolify/data/coolify/source/docker-compose.prod.yml new file mode 100644 index 0000000..901aeb8 --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/source/docker-compose.prod.yml @@ -0,0 +1,90 @@ +services: + coolify: + image: "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify:${LATEST_IMAGE:-latest}" + volumes: + - type: bind + source: /data/coolify/source/.env + target: /var/www/html/.env + read_only: true + - /data/coolify/ssh:/var/www/html/storage/app/ssh + - /data/coolify/applications:/var/www/html/storage/app/applications + - /data/coolify/databases:/var/www/html/storage/app/databases + - /data/coolify/services:/var/www/html/storage/app/services + - /data/coolify/backups:/var/www/html/storage/app/backups + environment: + - APP_ENV=${APP_ENV:-production} + - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT:-256M} + - PHP_FPM_PM_CONTROL=${PHP_FPM_PM_CONTROL:-dynamic} + - PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-1} + - PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1} + - PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-10} + env_file: + - /data/coolify/source/.env + ports: + - "${APP_PORT:-8000}:8080" + expose: + - "${APP_PORT:-8000}" + healthcheck: + test: curl --fail http://127.0.0.1:8080/api/health || exit 1 + interval: 5s + retries: 10 + timeout: 2s + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + soketi: + condition: service_healthy + postgres: + volumes: + - coolify-db:/var/lib/postgresql/data + environment: + POSTGRES_USER: "${DB_USERNAME}" + POSTGRES_PASSWORD: "${DB_PASSWORD}" + POSTGRES_DB: "${DB_DATABASE:-coolify}" + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U ${DB_USERNAME}", "-d", "${DB_DATABASE:-coolify}" ] + interval: 5s + retries: 10 + timeout: 2s + redis: + command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD} + environment: + REDIS_PASSWORD: "${REDIS_PASSWORD}" + volumes: + - coolify-redis:/data + healthcheck: + test: redis-cli ping + interval: 5s + retries: 10 + timeout: 2s + soketi: + image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.13' + ports: + - "${SOKETI_PORT:-6001}:6001" + - "6002:6002" + volumes: + - /data/coolify/ssh:/var/www/html/storage/app/ssh + environment: + APP_NAME: "${APP_NAME:-Coolify}" + SOKETI_DEBUG: "${SOKETI_DEBUG:-false}" + SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}" + SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}" + SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}" + SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}" + healthcheck: + test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ] + interval: 5s + retries: 10 + timeout: 2s + +volumes: + coolify-db: + name: coolify-db + coolify-redis: + name: coolify-redis + +networks: + coolify: + external: true diff --git a/pve/lxc-103-coolify/data/coolify/source/docker-compose.yml b/pve/lxc-103-coolify/data/coolify/source/docker-compose.yml new file mode 100644 index 0000000..0fd3dda --- /dev/null +++ b/pve/lxc-103-coolify/data/coolify/source/docker-compose.yml @@ -0,0 +1,37 @@ +services: + coolify: + container_name: coolify + restart: always + working_dir: /var/www/html + extra_hosts: + - host.docker.internal:host-gateway + networks: + - coolify + depends_on: + - postgres + - redis + - soketi + postgres: + image: postgres:15-alpine + container_name: coolify-db + restart: always + networks: + - coolify + redis: + image: redis:7-alpine + container_name: coolify-redis + restart: always + networks: + - coolify + soketi: + container_name: coolify-realtime + extra_hosts: + - host.docker.internal:host-gateway + restart: always + networks: + - coolify +networks: + coolify: + name: coolify + driver: bridge + external: false