diff --git a/servers/bwh-us-dc9/frontdoor/.env.example b/servers/bwh-us-dc9/frontdoor/.env.example new file mode 100644 index 0000000..db71747 --- /dev/null +++ b/servers/bwh-us-dc9/frontdoor/.env.example @@ -0,0 +1,3 @@ +# Stage on 8444 first. Change to 443 only after the Arcane Agent Caddy is +# reachable through its temporary management port and host TCP 443 is free. +HAPROXY_PUBLIC_PORT=8444 diff --git a/servers/bwh-us-dc9/frontdoor/README.md b/servers/bwh-us-dc9/frontdoor/README.md new file mode 100644 index 0000000..7eea090 --- /dev/null +++ b/servers/bwh-us-dc9/frontdoor/README.md @@ -0,0 +1,12 @@ +# DC9 TLS front door + +HAProxy inspects TCP SNI without terminating TLS: + +- `dc9-tls-e2f48b.opfo.xyz` -> managed sing-box Trojan on host TCP 22591 +- `sb-dd65a3.kais.cloud` -> managed sing-box AnyTLS on host TCP 43824 +- `dc9.kais.cloud` -> the existing Arcane Agent Caddy on `arcane_default` +- unmatched SNI -> the dedicated Caddy fallback serving `dc9.opfo.xyz` + +The first deployment uses host TCP 8444. Moving it to TCP 443 requires a staged +handoff from the existing Arcane Agent Caddy so the Direct HTTPS management path +remains reachable throughout the change. diff --git a/servers/bwh-us-dc9/frontdoor/caddy/Caddyfile b/servers/bwh-us-dc9/frontdoor/caddy/Caddyfile new file mode 100644 index 0000000..26ea7cf --- /dev/null +++ b/servers/bwh-us-dc9/frontdoor/caddy/Caddyfile @@ -0,0 +1,21 @@ +{ + servers { + protocols h1 h2 + } +} + +dc9.opfo.xyz { + encode zstd gzip + header { + X-Content-Type-Options nosniff + X-Frame-Options DENY + Referrer-Policy no-referrer + } + respond < + +Service Status +

Service online

The requested service is available.

+ +HTML +} diff --git a/servers/bwh-us-dc9/frontdoor/compose.yaml b/servers/bwh-us-dc9/frontdoor/compose.yaml new file mode 100644 index 0000000..c17ad3f --- /dev/null +++ b/servers/bwh-us-dc9/frontdoor/compose.yaml @@ -0,0 +1,44 @@ +services: + haproxy: + image: haproxy:3.4.4-alpine3.24 + container_name: dc9-haproxy + restart: unless-stopped + ports: + - "${HAPROXY_PUBLIC_PORT:-8444}:8443/tcp" + extra_hosts: + - "host.docker.internal:host-gateway" + depends_on: + - decoy-caddy + networks: + - default + - arcane + volumes: + - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro + logging: + driver: json-file + options: + max-size: 200k + max-file: "2" + + decoy-caddy: + image: caddy:2.11.4 + container_name: dc9-decoy-caddy + restart: unless-stopped + volumes: + - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + logging: + driver: json-file + options: + max-size: 200k + max-file: "2" + +networks: + arcane: + external: true + name: arcane_default + +volumes: + caddy-data: + caddy-config: diff --git a/servers/bwh-us-dc9/frontdoor/haproxy/haproxy.cfg b/servers/bwh-us-dc9/frontdoor/haproxy/haproxy.cfg new file mode 100644 index 0000000..94fd1b7 --- /dev/null +++ b/servers/bwh-us-dc9/frontdoor/haproxy/haproxy.cfg @@ -0,0 +1,37 @@ +global + log stdout format raw local0 + maxconn 4096 + +defaults + log global + mode tcp + option tcplog + timeout connect 5s + timeout client 24h + timeout server 24h + +frontend tls_443 + bind 0.0.0.0:8443 + tcp-request inspect-delay 5s + tcp-request content accept if { req.ssl_hello_type 1 } + + acl sni_trojan req.ssl_sni -i dc9-tls-e2f48b.opfo.xyz + acl sni_anytls req.ssl_sni -i sb-dd65a3.kais.cloud + acl sni_arcane req.ssl_sni -i dc9.kais.cloud + + use_backend singbox_trojan if sni_trojan + use_backend singbox_anytls if sni_anytls + use_backend arcane_agent if sni_arcane + default_backend decoy_https + +backend singbox_trojan + server trojan host.docker.internal:22591 + +backend singbox_anytls + server anytls host.docker.internal:43824 + +backend arcane_agent + server arcane arcane-agent-caddy:443 + +backend decoy_https + server caddy decoy-caddy:443 diff --git a/servers/bwh-us-dc9/sing-box/.env.example b/servers/bwh-us-dc9/sing-box/.env.example index 2dfa9a8..6eebd56 100644 --- a/servers/bwh-us-dc9/sing-box/.env.example +++ b/servers/bwh-us-dc9/sing-box/.env.example @@ -5,16 +5,11 @@ USER1_PASSWORD=change-me CLOUDFLARE_API_TOKEN=change-me ANYTLS_DOMAIN=sb-dd65a3.kais.cloud -ANYTLS_HY2_PORT=43824 +ANYTLS_PORT=43824 ANYTLS_PASSWORD=change-me HY2_PASSWORD=change-me HY2_OBFS_PASSWORD=change-me - -VLESS_PORT=22590 -VLESS_UUID=00000000-0000-4000-8000-000000000000 -REALITY_SERVER_NAME=www.cloudflare.com -REALITY_PRIVATE_KEY=change-me -REALITY_SHORT_ID=0123456789abcdef +HY2_PORT=443 # sing-box uses version 5 for the Snell v4-compatible TCP wire protocol. SNELL_V4_PORT=53469 diff --git a/servers/bwh-us-dc9/sing-box/compose.yaml b/servers/bwh-us-dc9/sing-box/compose.yaml index 89b2d95..8440b1a 100644 --- a/servers/bwh-us-dc9/sing-box/compose.yaml +++ b/servers/bwh-us-dc9/sing-box/compose.yaml @@ -1,6 +1,6 @@ services: config-render: - image: alpine:3.20 + image: alpine:3.24 environment: DOMAIN: ${DOMAIN} ACME_EMAIL: ${ACME_EMAIL} @@ -8,15 +8,11 @@ services: USER1_PASSWORD: ${USER1_PASSWORD} CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN} ANYTLS_DOMAIN: ${ANYTLS_DOMAIN} - ANYTLS_HY2_PORT: ${ANYTLS_HY2_PORT} + ANYTLS_PORT: ${ANYTLS_PORT} ANYTLS_PASSWORD: ${ANYTLS_PASSWORD} HY2_PASSWORD: ${HY2_PASSWORD} HY2_OBFS_PASSWORD: ${HY2_OBFS_PASSWORD} - VLESS_PORT: ${VLESS_PORT} - VLESS_UUID: ${VLESS_UUID} - REALITY_SERVER_NAME: ${REALITY_SERVER_NAME} - REALITY_PRIVATE_KEY: ${REALITY_PRIVATE_KEY} - REALITY_SHORT_ID: ${REALITY_SHORT_ID} + HY2_PORT: ${HY2_PORT} SNELL_V4_PORT: ${SNELL_V4_PORT} SNELL_V4_PSK: ${SNELL_V4_PSK} SNELL_V6_PORT: ${SNELL_V6_PORT} diff --git a/servers/bwh-us-dc9/sing-box/etc/sing-box/config.json.template b/servers/bwh-us-dc9/sing-box/etc/sing-box/config.json.template index 9e36b57..dd2db25 100644 --- a/servers/bwh-us-dc9/sing-box/etc/sing-box/config.json.template +++ b/servers/bwh-us-dc9/sing-box/etc/sing-box/config.json.template @@ -1,4 +1,19 @@ { + "certificate_providers": [ + { + "type": "acme", + "tag": "public-cert", + "domain": [ + "${DOMAIN}", + "${ANYTLS_DOMAIN}" + ], + "email": "${ACME_EMAIL}", + "dns01_challenge": { + "provider": "cloudflare", + "api_token": "${CLOUDFLARE_API_TOKEN}" + } + } + ], "inbounds": [ { "type": "trojan", @@ -14,15 +29,7 @@ "tls": { "enabled": true, "server_name": "${DOMAIN}", - "acme": { - "domain": "${DOMAIN}", - "data_directory": "/var/lib/sing-box/certmagic-anytls", - "email": "${ACME_EMAIL}", - "dns01_challenge": { - "provider": "cloudflare", - "api_token": "${CLOUDFLARE_API_TOKEN}" - } - } + "certificate_provider": "public-cert" }, "multiplex": { "enabled": true @@ -32,7 +39,7 @@ "type": "anytls", "tag": "anytls-in", "listen": "::", - "listen_port": ${ANYTLS_HY2_PORT}, + "listen_port": ${ANYTLS_PORT}, "users": [ { "name": "user1", @@ -42,22 +49,14 @@ "tls": { "enabled": true, "server_name": "${ANYTLS_DOMAIN}", - "acme": { - "domain": "${ANYTLS_DOMAIN}", - "data_directory": "/var/lib/sing-box/certmagic-anytls", - "email": "${ACME_EMAIL}", - "dns01_challenge": { - "provider": "cloudflare", - "api_token": "${CLOUDFLARE_API_TOKEN}" - } - } + "certificate_provider": "public-cert" } }, { "type": "hysteria2", "tag": "hysteria2-in", "listen": "0.0.0.0", - "listen_port": ${ANYTLS_HY2_PORT}, + "listen_port": ${HY2_PORT}, "obfs": { "type": "salamander", "password": "${HY2_OBFS_PASSWORD}" @@ -74,44 +73,7 @@ "alpn": [ "h3" ], - "acme": { - "domain": "${ANYTLS_DOMAIN}", - "data_directory": "/var/lib/sing-box/certmagic-anytls", - "email": "${ACME_EMAIL}", - "dns01_challenge": { - "provider": "cloudflare", - "api_token": "${CLOUDFLARE_API_TOKEN}" - } - } - } - }, - { - "type": "vless", - "tag": "vless-reality-in", - "listen": "::", - "listen_port": ${VLESS_PORT}, - "users": [ - { - "name": "user1", - "uuid": "${VLESS_UUID}", - "flow": "xtls-rprx-vision" - } - ], - "tls": { - "enabled": true, - "server_name": "${REALITY_SERVER_NAME}", - "reality": { - "enabled": true, - "handshake": { - "server": "${REALITY_SERVER_NAME}", - "server_port": 443 - }, - "private_key": "${REALITY_PRIVATE_KEY}", - "short_id": [ - "${REALITY_SHORT_ID}" - ], - "max_time_difference": "2m" - } + "certificate_provider": "public-cert" } }, {