From b02f7fcc87fddd71be9bba20343b8d72a063112e Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Sat, 14 Mar 2026 22:56:47 -0300 Subject: [PATCH] add Caddy and Authelia support with configuration scripts and Docker setup --- containers/authelia/Dockerfile-authelia | 13 + containers/authelia/entrypoint.sh | 39 ++ containers/caddy/Dockerfile-caddy | 15 +- containers/caddy/entrypoint.sh | 26 +- .../caddy/export_wireguard_webadmin_config.py | 23 +- containers/caddy/process_config.py | 397 ++++++++++++++++++ docker-compose-caddy.yml | 120 ++++++ docker-compose-dev.yml | 29 +- 8 files changed, 649 insertions(+), 13 deletions(-) create mode 100644 containers/authelia/Dockerfile-authelia create mode 100644 containers/authelia/entrypoint.sh create mode 100644 containers/caddy/process_config.py create mode 100644 docker-compose-caddy.yml diff --git a/containers/authelia/Dockerfile-authelia b/containers/authelia/Dockerfile-authelia new file mode 100644 index 0000000..b31073f --- /dev/null +++ b/containers/authelia/Dockerfile-authelia @@ -0,0 +1,13 @@ +FROM alpine:latest AS tools +RUN apk add --no-cache inotify-tools + +FROM authelia/authelia:latest + +COPY --from=tools /usr/bin/inotifywait /usr/bin/inotifywait +COPY --from=tools /usr/lib/libinotifytools* /usr/lib/ + +COPY entrypoint.sh /usr/local/bin/authelia-entrypoint.sh + +RUN chmod +x /usr/local/bin/authelia-entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/authelia-entrypoint.sh"] diff --git a/containers/authelia/entrypoint.sh b/containers/authelia/entrypoint.sh new file mode 100644 index 0000000..97c49f1 --- /dev/null +++ b/containers/authelia/entrypoint.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +set -eu + +CONFIG_PATH="/config/configuration.yml" +MAX_WAIT=120 +WAIT_INTERVAL=2 + +echo "==> Waiting for Authelia configuration file..." +elapsed=0 +while [ ! -f "$CONFIG_PATH" ]; do + if [ "$elapsed" -ge "$MAX_WAIT" ]; then + echo "Error: Timed out waiting for ${CONFIG_PATH} after ${MAX_WAIT}s" + exit 1 + fi + sleep "$WAIT_INTERVAL" + elapsed=$((elapsed + WAIT_INTERVAL)) +done +echo "==> Configuration file found: ${CONFIG_PATH}" + +echo "==> Starting Authelia..." +authelia --config "$CONFIG_PATH" & +AUTHELIA_PID=$! + +sleep 3 + +echo "==> Watching ${CONFIG_PATH} for changes..." +while true; do + inotifywait -qq -e close_write,moved_to "${CONFIG_PATH}" 2>/dev/null || true + sleep 2 + + echo "==> Configuration change detected, restarting Authelia..." + kill "$AUTHELIA_PID" 2>/dev/null || true + wait "$AUTHELIA_PID" 2>/dev/null || true + + authelia --config "$CONFIG_PATH" & + AUTHELIA_PID=$! + echo "==> Authelia restarted with PID ${AUTHELIA_PID}" +done diff --git a/containers/caddy/Dockerfile-caddy b/containers/caddy/Dockerfile-caddy index 9bd6275..0fc7f85 100644 --- a/containers/caddy/Dockerfile-caddy +++ b/containers/caddy/Dockerfile-caddy @@ -1,8 +1,19 @@ -FROM caddy:2-alpine +FROM caddy:2 +RUN apk add --no-cache \ + python3 \ + py3-pip \ + py3-yaml \ + inotify-tools \ + bash + +RUN python3 -m venv /usr/local/bin/.venv && \ + /usr/local/bin/.venv/bin/pip install --no-cache-dir pyyaml + +COPY export_wireguard_webadmin_config.py /usr/local/bin/export_wireguard_webadmin_config.py +COPY process_config.py /usr/local/bin/process_config.py COPY entrypoint.sh /usr/local/bin/caddy-entrypoint.sh RUN chmod +x /usr/local/bin/caddy-entrypoint.sh ENTRYPOINT ["/usr/local/bin/caddy-entrypoint.sh"] -CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/containers/caddy/entrypoint.sh b/containers/caddy/entrypoint.sh index 0ba06ab..b9b9a11 100644 --- a/containers/caddy/entrypoint.sh +++ b/containers/caddy/entrypoint.sh @@ -1,10 +1,32 @@ -#!/bin/sh +#!/bin/bash set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PYTHON="${SCRIPT_DIR}/.venv/bin/python3" +JSON_DIR="${JSON_DIR:-/caddy_json_export}" +CADDYFILE_PATH="${CADDYFILE_PATH:-/etc/caddy/Caddyfile}" +echo "==> Generating wireguard_webadmin.json..." "$PYTHON" "${SCRIPT_DIR}/export_wireguard_webadmin_config.py" -exec "$@" +echo "==> Processing config files..." +"$PYTHON" "${SCRIPT_DIR}/process_config.py" + +echo "==> Starting Caddy..." +caddy run --config "$CADDYFILE_PATH" --adapter caddyfile & +CADDY_PID=$! + +sleep 2 + +echo "==> Watching ${JSON_DIR} for config changes..." +while true; do + inotifywait -qq -e close_write,moved_to,create "${JSON_DIR}/" --include '.*\.json$' 2>/dev/null || true + sleep 1 + + echo "==> Config change detected, reprocessing..." + "$PYTHON" "${SCRIPT_DIR}/process_config.py" + + echo "==> Reloading Caddy..." + caddy reload --config "$CADDYFILE_PATH" --adapter caddyfile 2>/dev/null || echo "Warning: Caddy reload failed, will retry on next change." +done diff --git a/containers/caddy/export_wireguard_webadmin_config.py b/containers/caddy/export_wireguard_webadmin_config.py index 8744f98..753c8ce 100644 --- a/containers/caddy/export_wireguard_webadmin_config.py +++ b/containers/caddy/export_wireguard_webadmin_config.py @@ -11,7 +11,11 @@ import os import re import sys -OUTPUT_FILE = os.path.join(os.path.dirname(__file__), "config_files/wireguard_webadmin.json") +OUTPUT_FILE = os.environ.get( + "OUTPUT_FILE", + os.path.join(os.path.dirname(__file__), "config_files/wireguard_webadmin.json"), +) +OUTPUT_FILE_CADDY = "/caddy_json_export/wireguard_webadmin.json" UPSTREAM = "wireguard-webadmin:8000" STATIC_ROUTES = [ @@ -122,16 +126,25 @@ def build_config(hosts: list) -> dict: } +def _write_config(filepath, config): + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, "w", encoding="utf-8") as output_file: + json.dump(config, output_file, indent=2) + output_file.write("\n") + print(f"Config written to {filepath}") + + def main() -> None: hosts = collect_hosts() config = build_config(hosts) - with open(OUTPUT_FILE, "w", encoding="utf-8") as output_file: - json.dump(config, output_file, indent=2) - output_file.write("\n") + _write_config(OUTPUT_FILE, config) - print(f"Config written to {OUTPUT_FILE}") + caddy_export_dir = os.path.dirname(OUTPUT_FILE_CADDY) + if os.path.isdir(caddy_export_dir): + _write_config(OUTPUT_FILE_CADDY, config) if __name__ == "__main__": main() + diff --git a/containers/caddy/process_config.py b/containers/caddy/process_config.py new file mode 100644 index 0000000..c35071f --- /dev/null +++ b/containers/caddy/process_config.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 +""" +Reads JSON config files exported by Django and generates: + - /etc/caddy/Caddyfile + - /authelia_config/configuration.yml + - /authelia_config/users_database.yml + +Expected input files in /caddy_json_export/: + - wireguard_webadmin.json (required, generated on container startup) + - applications.json (optional, exported from Django) + - auth_policies.json (optional, exported from Django) + - routes.json (optional, exported from Django) +""" + +import json +import os +import secrets +import string + +import yaml + +JSON_DIR = os.environ.get("JSON_DIR", "/caddy_json_export") +CADDYFILE_PATH = os.environ.get("CADDYFILE_PATH", "/etc/caddy/Caddyfile") +AUTHELIA_CONFIG_DIR = os.environ.get("AUTHELIA_CONFIG_DIR", "/authelia_config") +AUTHELIA_CONFIG_PATH = os.path.join(AUTHELIA_CONFIG_DIR, "configuration.yml") +AUTHELIA_USERS_PATH = os.path.join(AUTHELIA_CONFIG_DIR, "users_database.yml") +AUTHELIA_SECRETS_DIR = os.path.join(AUTHELIA_CONFIG_DIR, "secrets") + +AUTHELIA_INTERNAL_URL = "http://authelia:9091" +AUTHELIA_PORTAL_PATH = "/authelia" + + +def load_json(filename): + filepath = os.path.join(JSON_DIR, filename) + if not os.path.exists(filepath): + return None + with open(filepath, "r", encoding="utf-8") as json_file: + return json.load(json_file) + + +def generate_secret(length=64): + alphabet = string.ascii_letters + string.digits + return "".join(secrets.choice(alphabet) for char_index in range(length)) + + +def get_or_create_secret(name): + os.makedirs(AUTHELIA_SECRETS_DIR, exist_ok=True) + secret_path = os.path.join(AUTHELIA_SECRETS_DIR, name) + if os.path.exists(secret_path): + with open(secret_path, "r", encoding="utf-8") as secret_file: + return secret_file.read().strip() + secret_value = generate_secret() + with open(secret_path, "w", encoding="utf-8") as secret_file: + secret_file.write(secret_value) + return secret_value + + +def collect_all_applications(): + """Merge entries from wireguard_webadmin.json and applications.json.""" + apps = [] + + webadmin_data = load_json("wireguard_webadmin.json") + if webadmin_data: + apps.extend(webadmin_data.get("entries", [])) + + applications_data = load_json("applications.json") + if applications_data: + apps.extend(applications_data.get("entries", [])) + + return apps + + +def build_caddyfile(apps, auth_policies, routes): + lines = [] + has_authelia = auth_policies is not None + + for app in apps: + app_id = app.get("id", "unknown") + hosts = app.get("hosts", []) + upstream = app.get("upstream", "") + static_routes = app.get("static_routes", []) + + if not hosts or not upstream: + continue + + host_list = ", ".join(hosts) + lines.append(f"{host_list} {{") + + for static_route in static_routes: + path_prefix = static_route.get("path_prefix", "") + root_dir = static_route.get("root", "") + strip_prefix = static_route.get("strip_prefix", "") + cache_control = static_route.get("cache_control", "") + + lines.append(f" handle_path {path_prefix}/* {{") + lines.append(f" root * {root_dir}") + lines.append(f" file_server") + if cache_control: + lines.append(f" header Cache-Control \"{cache_control}\"") + lines.append(f" }}") + lines.append("") + + app_routes = {} + app_default_policy = None + if routes: + route_entries = routes.get("entries", {}) + if app_id in route_entries: + app_route_data = route_entries[app_id] + app_default_policy = app_route_data.get("default_policy") + for route in app_route_data.get("routes", []): + app_routes[route.get("path_prefix", "")] = route.get("policy", "") + + needs_auth = False + if has_authelia and auth_policies: + policies = auth_policies.get("policies", {}) + if app_default_policy and app_default_policy in policies: + policy_data = policies[app_default_policy] + if policy_data.get("policy_type") != "bypass": + needs_auth = True + for path_prefix, policy_name in app_routes.items(): + if policy_name in policies: + policy_data = policies[policy_name] + if policy_data.get("policy_type") != "bypass": + needs_auth = True + + if needs_auth: + for path_prefix, policy_name in app_routes.items(): + if policy_name in auth_policies.get("policies", {}): + policy_data = auth_policies["policies"][policy_name] + if policy_data.get("policy_type") == "bypass": + lines.append(f" @bypass_{_sanitize_id(path_prefix)} path {path_prefix}*") + lines.append(f" skip_log @bypass_{_sanitize_id(path_prefix)}") + lines.append("") + + lines.append(f" forward_auth {AUTHELIA_INTERNAL_URL} {{") + lines.append(f" uri {AUTHELIA_PORTAL_PATH}/api/authz/forward-auth") + lines.append(f" copy_headers Remote-User Remote-Groups Remote-Name Remote-Email") + lines.append(f" }}") + lines.append("") + + lines.append(f" reverse_proxy {upstream}") + lines.append(f"}}") + lines.append("") + + if has_authelia: + server_address = os.environ.get("SERVER_ADDRESS", "localhost") + lines.append(f"{server_address} {{") + lines.append(f" handle_path {AUTHELIA_PORTAL_PATH}/* {{") + lines.append(f" reverse_proxy {AUTHELIA_INTERNAL_URL}") + lines.append(f" }}") + lines.append(f"}}") + lines.append("") + + return "\n".join(lines) + + +def _sanitize_id(value): + return value.strip("/").replace("/", "_").replace("-", "_") + + +def build_authelia_config(auth_policies, routes, apps): + server_address = os.environ.get("SERVER_ADDRESS", "localhost") + + jwt_secret = get_or_create_secret("jwt_secret") + session_secret = get_or_create_secret("session_secret") + storage_encryption_key = get_or_create_secret("storage_encryption_key") + + config = { + "server": { + "address": "tcp://0.0.0.0:9091", + }, + "log": { + "level": "info", + }, + "jwt_secret": jwt_secret, + "authentication_backend": { + "file": { + "path": "/config/users_database.yml", + }, + }, + "session": { + "secret": session_secret, + "cookies": [ + { + "domain": server_address, + "authelia_url": f"https://{server_address}{AUTHELIA_PORTAL_PATH}", + "default_redirection_url": f"https://{server_address}", + }, + ], + }, + "storage": { + "encryption_key": storage_encryption_key, + "local": { + "path": "/data/db.sqlite3", + }, + }, + "notifier": { + "filesystem": { + "filename": "/data/notification.txt", + }, + }, + "access_control": build_access_control_rules(auth_policies, routes, apps), + } + + identity_providers = build_identity_providers(auth_policies, server_address) + if identity_providers: + config["identity_providers"] = identity_providers + + return config + + +def build_access_control_rules(auth_policies, routes, apps): + if not auth_policies or not routes: + return {"default_policy": "bypass", "rules": []} + + policies = auth_policies.get("policies", {}) + route_entries = routes.get("entries", {}) + + host_map = {} + for app in apps: + app_id = app.get("id", "unknown") + host_map[app_id] = app.get("hosts", []) + + rules = [] + + for app_id, route_data in route_entries.items(): + app_hosts = host_map.get(app_id, []) + if not app_hosts: + continue + + domain_list = list(app_hosts) + + for route in route_data.get("routes", []): + policy_name = route.get("policy", "") + path_prefix = route.get("path_prefix", "") + + if policy_name not in policies: + continue + + policy_data = policies[policy_name] + policy_type = policy_data.get("policy_type", "bypass") + + if policy_type == "bypass": + authelia_policy = "bypass" + elif policy_type == "deny": + authelia_policy = "deny" + else: + authelia_policy = "two_factor" + + rule = { + "domain": domain_list, + "policy": authelia_policy, + "resources": [f"^{path_prefix}.*$"], + } + + groups = policy_data.get("groups", []) + if groups and authelia_policy not in ("bypass", "deny"): + rule["subject"] = [f"group:{g}" for g in groups] + + rules.append(rule) + + default_policy_name = route_data.get("default_policy") + if default_policy_name and default_policy_name in policies: + default_policy_data = policies[default_policy_name] + default_type = default_policy_data.get("policy_type", "bypass") + + if default_type == "bypass": + authelia_default = "bypass" + elif default_type == "deny": + authelia_default = "deny" + else: + authelia_default = "two_factor" + + default_rule = { + "domain": domain_list, + "policy": authelia_default, + } + + groups = default_policy_data.get("groups", []) + if groups and authelia_default not in ("bypass", "deny"): + default_rule["subject"] = [f"group:{g}" for g in groups] + + rules.append(default_rule) + + return { + "default_policy": "deny", + "rules": rules, + } + + +def build_identity_providers(auth_policies, server_address): + if not auth_policies: + return None + + auth_methods = auth_policies.get("auth_methods", {}) + oidc_clients = [] + + for method_name, method in auth_methods.items(): + if method.get("type") != "oidc": + continue + + client_id = method.get("client_id", "") + client_secret = method.get("client_secret", "") + if not client_id: + continue + + client = { + "client_id": client_id, + "client_secret": client_secret, + "authorization_policy": "two_factor", + "redirect_uris": [ + f"https://{server_address}{AUTHELIA_PORTAL_PATH}/oidc/callback", + ], + "scopes": ["openid", "profile", "email", "groups"], + } + oidc_clients.append(client) + + if not oidc_clients: + return None + + hmac_secret = get_or_create_secret("oidc_hmac_secret") + + return { + "oidc": { + "hmac_secret": hmac_secret, + "clients": oidc_clients, + }, + } + + +def build_users_database(auth_policies): + if not auth_policies: + return {"users": {}} + + users_data = auth_policies.get("users", {}) + groups_data = auth_policies.get("groups", {}) + + user_groups = {} + for group_name, group_info in groups_data.items(): + for username in group_info.get("users", []): + if username not in user_groups: + user_groups[username] = [] + user_groups[username].append(group_name) + + users = {} + for username, user_info in users_data.items(): + user_entry = { + "displayname": username, + "email": user_info.get("email", f"{username}@localhost"), + "groups": user_groups.get(username, []), + } + password_hash = user_info.get("password_hash", "") + if password_hash: + user_entry["password"] = password_hash + + users[username] = user_entry + + return {"users": users} + + +class _NoAliasDumper(yaml.SafeDumper): + """YAML dumper that never emits anchors/aliases.""" + def ignore_aliases(self, data): + return True + + +def write_yaml(filepath, data): + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, "w", encoding="utf-8") as yaml_file: + yaml.dump(data, yaml_file, Dumper=_NoAliasDumper, default_flow_style=False, allow_unicode=True, sort_keys=False) + + +def main(): + apps = collect_all_applications() + auth_policies = load_json("auth_policies.json") + routes = load_json("routes.json") + + caddyfile_content = build_caddyfile(apps, auth_policies, routes) + os.makedirs(os.path.dirname(CADDYFILE_PATH), exist_ok=True) + with open(CADDYFILE_PATH, "w", encoding="utf-8") as caddyfile: + caddyfile.write(caddyfile_content) + print(f"Caddyfile written to {CADDYFILE_PATH}") + + if auth_policies: + authelia_config = build_authelia_config(auth_policies, routes, apps) + write_yaml(AUTHELIA_CONFIG_PATH, authelia_config) + print(f"Authelia configuration written to {AUTHELIA_CONFIG_PATH}") + + users_db = build_users_database(auth_policies) + write_yaml(AUTHELIA_USERS_PATH, users_db) + print(f"Authelia users database written to {AUTHELIA_USERS_PATH}") + else: + print("No auth_policies.json found, skipping Authelia config generation.") + + +if __name__ == "__main__": + main() diff --git a/docker-compose-caddy.yml b/docker-compose-caddy.yml new file mode 100644 index 0000000..4e88a51 --- /dev/null +++ b/docker-compose-caddy.yml @@ -0,0 +1,120 @@ +version: '3' +services: + wireguard-webadmin: + container_name: wireguard-webadmin + restart: unless-stopped + image: eduardosilva/wireguard_webadmin:latest + environment: + - SERVER_ADDRESS=${SERVER_ADDRESS} + - DEBUG_MODE=${DEBUG_MODE} + - COMPOSE_VERSION=c1c + - TZ=${TIMEZONE} + - EXTRA_ALLOWED_HOSTS=${EXTRA_ALLOWED_HOSTS} + - WIREGUARD_STATUS_CACHE_ENABLED=${WIREGUARD_STATUS_CACHE_ENABLED} + - WIREGUARD_STATUS_CACHE_WEB_LOAD_PREVIOUS_COUNT=${WIREGUARD_STATUS_CACHE_WEB_LOAD_PREVIOUS_COUNT} + - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} + - VPN_CLIENTS_CAN_ACCESS_DJANGO=${VPN_CLIENTS_CAN_ACCESS_DJANGO} + - CADDY_ENABLED=true + volumes: + - wireguard:/etc/wireguard + - static_volume:/app_static_files/ + - dnsmasq_conf:/etc/dnsmasq + - app_secrets:/app_secrets/ + - rrd_data:/rrd_data/ + - caddy_json_export:/caddy_json_export/ + ports: + # Do not directly expose the Django port to the internet, use the reverse proxy below instead + # - "127.0.0.1:8000:8000" + # Warning: Docker will have a hard time handling large amount of ports. Expose only the ports that you need. + # Ports for multiple WireGuard instances. (Probably, you just need one) + - "51820-51839:51820-51839/udp" + # Ports for port forwarding rules. Add your own ports here if you need them. + - "8080-8089:8080-8089/tcp" + cap_add: + - NET_ADMIN + - SYS_MODULE + sysctls: + - net.ipv4.conf.all.src_valid_mark=1 + - net.ipv4.ip_forward=1 + command: /bin/bash /app/init.sh + + wireguard-webadmin-cron: + container_name: wireguard-webadmin-cron + restart: unless-stopped + image: eduardosilva/wireguard_webadmin_cron:latest + environment: + - TZ=${TIMEZONE} + - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} + volumes: + - app_secrets:/app_secrets/ + depends_on: + - wireguard-webadmin + + wireguard-webadmin-rrdtool: + container_name: wireguard-webadmin-rrdtool + restart: unless-stopped + image: eduardosilva/wireguard_webadmin_rrdtool:latest + volumes: + - app_secrets:/app_secrets/ + - rrd_data:/rrd_data/ + environment: + - TZ=${TIMEZONE} + depends_on: + - wireguard-webadmin + + wireguard-webadmin-dns: + container_name: wireguard-webadmin-dns + restart: unless-stopped + image: eduardosilva/wireguard_webadmin_dns:latest + environment: + - TZ=${TIMEZONE} + volumes: + - dnsmasq_conf:/etc/dnsmasq/ + + wireguard-webadmin-caddy: + container_name: wireguard-webadmin-caddy + restart: unless-stopped + build: + context: ./containers/caddy + dockerfile: Dockerfile-caddy + environment: + - SERVER_ADDRESS=${SERVER_ADDRESS} + - EXTRA_ALLOWED_HOSTS=${EXTRA_ALLOWED_HOSTS} + - TZ=${TIMEZONE} + volumes: + - static_volume:/static + - caddy_json_export:/caddy_json_export + - authelia_config:/authelia_config + - caddy_data:/data + - caddy_config:/config + ports: + - "80:80" + - "443:443" + depends_on: + - wireguard-webadmin + + wireguard-webadmin-authelia: + container_name: wireguard-webadmin-authelia + restart: unless-stopped + build: + context: ./containers/authelia + dockerfile: Dockerfile-authelia + environment: + - TZ=${TIMEZONE} + volumes: + - authelia_config:/config + - authelia_data:/data + depends_on: + - wireguard-webadmin-caddy + +volumes: + static_volume: + wireguard: + dnsmasq_conf: + app_secrets: + rrd_data: + caddy_json_export: + authelia_config: + authelia_data: + caddy_data: + caddy_config: diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index b60f853..caa9f4b 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -16,6 +16,7 @@ services: - WIREGUARD_STATUS_CACHE_WEB_LOAD_PREVIOUS_COUNT=${WIREGUARD_STATUS_CACHE_WEB_LOAD_PREVIOUS_COUNT} - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} - VPN_CLIENTS_CAN_ACCESS_DJANGO=${VPN_CLIENTS_CAN_ACCESS_DJANGO} + - CADDY_ENABLED=true volumes: - wireguard:/etc/wireguard - static_volume:/app_static_files/ @@ -23,6 +24,7 @@ services: - dnsmasq_conf:/etc/dnsmasq - app_secrets:/app_secrets/ - rrd_data:/rrd_data/ + - caddy_json_export:/caddy_json_export/ ports: # Do not directly expose the Django port to the internet, use some kind of reverse proxy with SSL. # - "8000:8000" @@ -91,19 +93,38 @@ services: - TZ=${TIMEZONE} volumes: - static_volume:/static - - https_cert:/certificates - - letsencrypt_data:/data + - caddy_json_export:/caddy_json_export + - authelia_config:/authelia_config + - caddy_data:/data + - caddy_config:/config ports: - "80:80" - "443:443" depends_on: - wireguard-webadmin + wireguard-webadmin-authelia: + container_name: wireguard-webadmin-authelia + restart: unless-stopped + build: + context: ./containers/authelia + dockerfile: Dockerfile-authelia + environment: + - TZ=${TIMEZONE} + volumes: + - authelia_config:/config + - authelia_data:/data + depends_on: + - wireguard-webadmin-caddy + volumes: static_volume: - https_cert: wireguard: dnsmasq_conf: app_secrets: rrd_data: - letsencrypt_data: + caddy_json_export: + authelia_config: + authelia_data: + caddy_data: + caddy_config: