volumes: wireguard-data: { name: wireguard } portainer-data: { name: portainer } gitea-mirror-data: { name: gitea_mirror } networks: # Secured internal bridge for read-only and read-write # Docker socket access socket-ro-bridge: { name: socket_ro_bridge, internal: true } socket-rw-bridge: { name: socket_rw_bridge, internal: true } matrix-internal: internal: true name: matrix_internal # Public-facing network for Nginx Proxy and web services web-network: name: web_network enable_ipv6: true services: # Read-Only Proxy: Restricts access to metadata only (GET requests) socket-ro: container_name: socket-ro image: lscr.io/linuxserver/socket-proxy:latest environment: - CONTAINERS=1 # Monitor container status - EVENTS=1 # Real-time discovery - IMAGES=1 # View image info - INFO=1 # Engine info - NETWORKS=1 # Network mapping - PING=1 # Connectivity check - SYSTEM=1 # System metadata - VOLUMES=1 # Volume inspection - LOG_LEVEL=info volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - socket-ro-bridge # Read-Write Proxy: Allows modifications (POST/EXEC) for administrative tasks socket-rw: container_name: socket-rw image: lscr.io/linuxserver/socket-proxy:latest environment: - CONTAINERS=1 - EVENTS=1 - EXEC=1 # Required for triggering tasks inside containers - IMAGES=1 - INFO=1 - NETWORKS=1 - PING=1 - POST=1 # Allows container start/stop/restart - SYSTEM=1 - VOLUMES=1 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - socket-rw-bridge # Automated Volume Backups: Daily S3 sync with container pausing backup: container_name: backup image: offen/docker-volume-backup restart: unless-stopped environment: AWS_S3_BUCKET_NAME: ${AWS_NAME} AWS_ENDPOINT: ${ENDPOINT_NAME} AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} BACKUP_CRON_EXPRESSION: "0 0 * * *" BACKUP_RETENTION_DAYS: 3 DOCKER_HOST: tcp://socket-rw:2375 # Uses RW proxy to pause containers during backup volumes: - wireguard-data:/backup/wireguard:ro - ./data/:/backup/data networks: - socket-rw-bridge - web-network # Automated Nginx Reverse Proxy: Routes traffic based on VIRTUAL_HOST labels nginx-proxy: image: nginxproxy/nginx-proxy:alpine container_name: nginx-proxy restart: unless-stopped ports: - "80:80" - "443:443" environment: - DOCKER_HOST=tcp://socket-ro:2375 # Discovers containers via RO proxy - ENABLE_IPV6=true volumes: - ./data/nginx/certs:/etc/nginx/certs:ro - ./data/nginx/default_html:/usr/share/nginx/html - ./data/nginx/vhost.d:/etc/nginx/vhost.d labels: - "docker-volume-backup.stop-during-backup=true" # Ensure consistency during backup depends_on: - socket-ro networks: - socket-ro-bridge - web-network # ACME Companion: Automated Let's Encrypt certificate issuance/renewal acme-companion: image: nginxproxy/acme-companion container_name: acme-companion restart: unless-stopped environment: - DEFAULT_EMAIL=${EMAIL} - NGINX_PROXY_CONTAINER=nginx-proxy - DOCKER_HOST=tcp://socket-rw:2375 # Needs RW to restart Nginx after renewal volumes: - ./data/nginx/certs:/etc/nginx/certs - ./data/nginx/vhost.d:/etc/nginx/vhost.d - ./data/nginx/default_html:/usr/share/nginx/html - ./data/nginx/acme_config:/etc/acme.sh labels: - "docker-volume-backup.stop-during-backup=true" depends_on: - nginx-proxy networks: - socket-rw-bridge - web-network # Main Portfolio/Website: Built from local repository # website: # container_name: web # # Reference to your internal Gitea registry # image: // self website repo # restart: unless-stopped # environment: # - VIRTUAL_HOST=${HOSTNAME}, www.${HOSTNAME} # - LETSENCRYPT_HOST=${HOSTNAME}, www.${HOSTNAME} # - LETSENCRYPT_EMAIL=${EMAIL} # volumes: # - /data/public:/usr/share/nginx/html/data # networks: # - web-network # Portainer: Web UI for container and stack management portainer: container_name: portainer image: portainer/portainer-ce:lts restart: unless-stopped environment: - VIRTUAL_HOST=mtr.${HOSTNAME} - LETSENCRYPT_HOST=mtr.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=9000 - DOCKER_HOST=socket-ro:2375 # Securely monitor engine via RO proxy volumes: - portainer-data:/data networks: - web-network - socket-ro-bridge # WireGuard VPN: Secure remote access with Web UI (wg-easy) wg-easy: image: ghcr.io/wg-easy/wg-easy:15 container_name: wg-easy restart: unless-stopped cap_add: - NET_ADMIN - SYS_MODULE sysctls: - net.ipv4.ip_forward=1 - net.ipv6.conf.all.disable_ipv6=0 environment: - TZ=Europe/Paris - VIRTUAL_HOST=vpn.${HOSTNAME} - LETSENCRYPT_HOST=vpn.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=51821 volumes: - wireguard-data:/etc/wireguard - /lib/modules:/lib/modules:ro ports: - "51820:51820/udp" labels: - "docker-volume-backup.stop-during-backup=true" networks: - web-network db-matrix: image: postgres:15-alpine container_name: db-matrix restart: unless-stopped environment: - POSTGRES_DB=synapse - POSTGRES_USER=synapse - POSTGRES_PASSWORD=${SYNAPSE_PASSWORD} volumes: - ./data/matrix/postgres:/var/lib/postgresql/data deploy: resources: limits: memory: 200M networks: - matrix-internal # Synapse: Matrix homeserver for decentralized communication synapse: image: matrixdotorg/synapse:latest container_name: synapse restart: unless-stopped deploy: resources: limits: memory: 800M reservations: memory: 400M volumes: - ./data/matrix/synapse:/data environment: - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml - VIRTUAL_HOST=msg.${HOSTNAME} - LETSENCRYPT_HOST=msg.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=8008 - SYNAPSE_POSTGRES_HOST=db-matrix - SYNAPSE_POSTGRES_USER=synapse - SYNAPSE_POSTGRES_PASSWORD=${SYNAPSE_PASSWORD} - SYNAPSE_POSTGRES_DB=synapse networks: - web-network - matrix-internal depends_on: - db-matrix # Gitea: Self-hosted Git forge (Lightweight alternative to GitHub) gitea: image: gitea/gitea:latest container_name: gitea restart: unless-stopped deploy: resources: limits: memory: 512M environment: - VIRTUAL_HOST=git.${HOSTNAME} - LETSENCRYPT_HOST=git.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=3000 - GITEA__server__DOMAIN=git.${HOSTNAME} - GITEA__server__ROOT_URL=https://git.${HOSTNAME}/ - GITEA__service__DISABLE_REGISTRATION=true volumes: - ./data/gitea:/data - /etc/localtime:/etc/localtime:ro ports: - "222:22" # SSH port mapping for Git operations networks: - web-network # Gitea Mirror: Repository synchronization and backup tool gitea-mirror: image: ghcr.io/raylabshq/gitea-mirror:latest container_name: gitea-mirror restart: unless-stopped environment: - VIRTUAL_HOST=mirror.${HOSTNAME} - LETSENCRYPT_HOST=mirror.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=4321 - BETTER_AUTH_SECRET=${MIRROR_AUTH_SECRET} - BETTER_AUTH_TRUSTED_ORIGINS=https://mirror.${HOSTNAME} volumes: - gitea-mirror-data:/app/data networks: - web-network