services: outline-client: build: . container_name: outline-client privileged: true # WireGuard UDP port is published from this service because # the wireguard container shares this network namespace. ports: - "51821:51820/udp" environment: # Replace with your Outline access key. OUTLINE_TRANSPORT: "${OUTLINE_TRANSPORT}" INTERNAL_SUBNET: "${INTERNAL_SUBNET}" cap_add: - NET_ADMIN - SYS_ADMIN devices: - /dev/net/tun:/dev/net/tun security_opt: - apparmor:unconfined sysctls: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1 - net.ipv4.conf.all.rp_filter=0 - net.ipv4.conf.default.rp_filter=0 - net.ipv6.conf.all.forwarding=0 - net.ipv6.conf.all.disable_ipv6=1 - net.ipv6.conf.default.disable_ipv6=1 restart: unless-stopped logging: driver: json-file options: max-size: "50m" max-file: "5" wireguard: image: lscr.io/linuxserver/wireguard:latest container_name: wg2outline depends_on: - outline-client # Important: share network stack with outline-client so all # traffic from WG peers leaves through Outline routing/policy. network_mode: "service:outline-client" cap_add: - NET_ADMIN - SYS_MODULE environment: - PUID=1000 - PGID=1000 - TZ=Etc/UTC # Public IP or domain of this server for peers. - SERVERURL=${SERVERURL} - SERVERPORT=51821 - PEERS=${PEERS:-1} - PEERDNS=1.1.1.1 - INTERNAL_SUBNET=${INTERNAL_SUBNET} # Keepalive helps on NAT/mobile networks. - PERSISTENTKEEPALIVE_PEERS=25 # Optional for enterprise networks that block MTU/fragmentation. - MTU=1280 # Firewall/NAT is handled by the host/namespace setup. - LOG_CONFS=true volumes: - ./wireguard-config:/config - /lib/modules:/lib/modules:ro sysctls: - net.ipv4.conf.all.src_valid_mark=1 restart: unless-stopped logging: driver: json-file options: max-size: "50m" max-file: "5"