services: # Reverse Proxy - Caddy for routing all .cell traffic caddy: image: git.pic.ngo/roof/pic-caddy:latest container_name: cell-caddy profiles: ["core", "full"] ports: - "80:80" - "443:443" volumes: - ./config/caddy/Caddyfile:/etc/caddy/Caddyfile - ./data/caddy:/data - ./config/caddy/certs:/config/caddy/certs restart: unless-stopped mem_limit: 256m cpus: 0.5 pids_limit: 256 cap_add: - NET_ADMIN networks: cell-network: ipv4_address: ${CADDY_IP:-172.20.0.2} logging: driver: json-file options: max-size: "10m" max-file: "5" # DNS Server - CoreDNS for .cell TLD resolution dns: image: coredns/coredns:1.11.3@sha256:9caabbf6238b189a65d0d6e6ac138de60d6a1c419e5a341fbbb7c78382559c6e container_name: cell-dns profiles: ["core", "full"] command: ["-conf", "/etc/coredns/Corefile"] ports: - "${DNS_PORT:-53}:53/udp" - "${DNS_PORT:-53}:53/tcp" volumes: - ./config/dns/Corefile:/etc/coredns/Corefile - ./data/dns:/data restart: unless-stopped mem_limit: 128m cpus: 0.25 pids_limit: 256 networks: cell-network: ipv4_address: ${DNS_IP:-172.20.0.3} logging: driver: json-file options: max-size: "10m" max-file: "5" # NTP Server - chrony for time synchronization ntp: build: ./ntp container_name: cell-ntp profiles: ["core", "full"] ports: - "${NTP_PORT:-123}:123/udp" volumes: - ./config/ntp/chrony.conf:/etc/chrony/chrony.conf restart: unless-stopped mem_limit: 128m cpus: 0.25 pids_limit: 256 networks: cell-network: ipv4_address: ${NTP_IP:-172.20.0.5} cap_add: - SYS_TIME logging: driver: json-file options: max-size: "10m" max-file: "5" # WireGuard VPN wireguard: build: ./wireguard container_name: cell-wireguard profiles: ["core", "full"] ports: - "${WG_PORT:-51820}:${WG_PORT:-51820}/udp" volumes: - ./config/wireguard:/config restart: unless-stopped mem_limit: 256m cpus: 0.5 pids_limit: 256 networks: cell-network: ipv4_address: ${WG_IP:-172.20.0.9} cap_add: - NET_ADMIN # FALLBACK for kernels lacking builtin WireGuard: re-add `privileged: true`, # `- SYS_MODULE` under cap_add, and the `- /lib/modules:/lib/modules` volume. # Default assumes a modern kernel (>= 5.6) with WireGuard compiled in. sysctls: - net.ipv4.conf.all.src_valid_mark=1 - net.ipv4.ip_forward=1 - net.ipv4.conf.all.rp_filter=0 logging: driver: json-file options: max-size: "10m" max-file: "5" # API Server api: build: ./api container_name: cell-api profiles: ["core", "full"] ports: - "127.0.0.1:${API_PORT:-3000}:3000" environment: - DDNS_URL=${DDNS_URL:-https://ddns.pic.ngo/api/v1} - DDNS_TOTP_SECRET=${DDNS_TOTP_SECRET:-S6UMA464YIKM74QHXWL5WELDIO3HFZ6K} volumes: - ./data/api:/app/data - ./data/dns:/app/data/dns - ./config/api:/app/config - ./config/cosign:/app/config/cosign:ro - ./config/caddy:/app/config-caddy - ./config/wireguard:/app/config/wireguard - ./config/dns:/app/config/dns - ./data/logs:/app/api/data/logs - /var/run/docker.sock:/var/run/docker.sock - ./.env:/app/.env.compose - ./docker-compose.yml:/app/docker-compose.yml:ro - ./docker-compose.services.yml:/app/docker-compose.services.yml - ./scripts:/app/scripts:ro pid: host restart: unless-stopped mem_limit: 512m cpus: 1.0 pids_limit: 256 networks: cell-network: ipv4_address: ${API_IP:-172.20.0.10} depends_on: - wireguard - dns logging: driver: json-file options: max-size: "10m" max-file: "5" # Web UI - React + Vite webui: build: ./webui container_name: cell-webui profiles: ["core", "full"] ports: - "${WEBUI_PORT:-8081}:8080" restart: unless-stopped mem_limit: 256m cpus: 0.5 pids_limit: 256 networks: cell-network: ipv4_address: ${WEBUI_IP:-172.20.0.11} logging: driver: json-file options: max-size: "10m" max-file: "5" networks: cell-network: name: cell-network external: true