Files
godoxy/dev.compose.yml
T
yusing 0e4dfcdc7d feat(webui): submodule build, Dockerfile targets, embedded SPA routes
Add godoxy-webui submodule and Dockerfile stages that install Bun/Node,
run schema generation, produce a production Vite build, copy dist into the
main image, and publish separate scratch targets for agent and
socket-proxy. Makefile defaults WEBUI_DIR to ./webui, adds build-webui
and ensure-webui-dist for embedded builds/tests, introduces dev=1 and
updates `dev`/`dev-build`; docker-build-test pins build targets and the
workflow forwards targets to buildx.

Load `webui` YAML aliases (fallback to legacy frontend env aliases when
unset). Serve production UI from embedded `fs.FS` fileservers with SPA
routing and presets; in non-production, when `./webui` is present,
register a localhost Vite dev proxy (`webui_dev.yml`) and optionally
auto-start bun dev server. Attach webui compose volume; switch dev base
image to Bun; drop the standalone frontend service and related env hints.

Extend static-provider handling, preset rules/metadata, fileserver SPA
behavior for RootFS roots, README/examples, smoke/config tests; bump
the webui submodule pin.
2026-05-05 12:52:33 +08:00

522 lines
14 KiB
YAML

x-benchmark: &benchmark
restart: no
ulimits:
nofile:
soft: 65535
hard: 65535
labels:
proxy.exclude: true
proxy.#1.healthcheck.disable: true
services:
app:
image: godoxy-dev
build:
context: .
dockerfile: dev.Dockerfile
container_name: godoxy-proxy-dev
restart: unless-stopped
env_file: .env
environment:
DOCKER_HOST: unix:///var/run/docker.sock
TZ: Asia/Hong_Kong
API_ADDR: 127.0.0.1:8999
API_USER: dev
API_PASSWORD: 1234
API_SKIP_ORIGIN_CHECK: true
API_JWT_TTL: 24h
API_JWT_SECRET: 1234567891234567
labels:
proxy.exclude: true
proxy.#1.healthcheck.disable: true
ipc: host
network_mode: host
volumes:
- ./bin/godoxy:/app/run:ro
- ./webui:/app/webui
- /var/run/docker.sock:/var/run/docker.sock
- ./dev-data/config:/app/config
- ./dev-data/certs:/app/certs
- ./dev-data/error_pages:/app/error_pages:ro
- ./dev-data/data:/app/data
- ./dev-data/logs:/app/logs
- ~/certs/myCA.pem:/etc/ssl/certs/ca.crt:ro
app-test:
image: godoxy-dev
build: .
container_name: godoxy-proxy-dev-test
restart: unless-stopped
env_file: .env
network_mode: host
environment:
DOCKER_HOST: unix:///var/run/docker.sock
TZ: Asia/Hong_Kong
API_ADDR: 127.0.0.1:8999
API_USER: dev
API_PASSWORD: 1234
API_SKIP_ORIGIN_CHECK: true
API_JWT_TTL: 24h
DEBUG: true
API_JWT_SECRET: 1234567891234567
volumes:
- /etc/ssl/certs/myCA.pem:/etc/ssl/certs/myCA.pem:ro
- /var/run/docker.sock:/var/run/docker.sock
- ./dev-data/config:/app/config
- ./dev-data/certs:/app/certs
- ./dev-data/error_pages:/app/error_pages:ro
- ./dev-data/data:/app/data
- ./dev-data/logs:/app/logs
idlewatcher-test:
image: nginx:latest
container_name: idlewatcher-test
command: sh -c 'sleep 3 && nginx -g "daemon off;" -c /etc/nginx/nginx.conf'
restart: no
labels:
proxy.#1.port: "80"
proxy.idle_timeout: 10s
proxy.wake_timeout: 5s
parca:
image: ghcr.io/parca-dev/parca:v0.24.2
container_name: godoxy-parca
restart: unless-stopped
command: [/parca, --config-path, /parca.yaml]
network_mode: host
# ports:
# - 7070:7070
configs:
- source: parca
target: /parca.yaml
labels:
proxy.#1.port: "7070"
tinyauth:
image: ghcr.io/steveiliop56/tinyauth:v3
container_name: tinyauth
restart: unless-stopped
environment:
- SECRET=12345678912345671234567891234567
- APP_URL=https://tinyauth.my.app
- USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
labels:
proxy.tinyauth.port: "3000"
jotty: # issue #182
image: ghcr.io/fccview/jotty:latest
container_name: jotty
user: "1000:1000"
tmpfs:
- /app/data:rw,uid=1000,gid=1000
- /app/config:rw,uid=1000,gid=1000
- /app/.next/cache:rw,uid=1000,gid=1000
restart: unless-stopped
environment:
- NODE_ENV=production
labels:
proxy.aliases: "jotty.my.app"
stash: # issue 222
image: stashapp/stash:latest
container_name: stash
restart: no
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_METADATA=/metadata/
- STASH_CACHE=/cache/
volumes:
- /etc/localtime:/etc/localtime:ro
- ./dev-data/stash/config:/root/.stash
- ./dev-data/stash/data:/data
labels:
- proxy.#1.middlewares.themed.css="https://css.i.sh/nonexists.css"
tmpfs:
- /metadata
- /cache
- /blobs
- /generated
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
container_name: bentopdf
restart: unless-stopped
expose:
- 8080
postgres-test:
image: postgres:18-alpine
container_name: postgres-test
restart: unless-stopped
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
h2c_test_server:
build:
context: cmd/h2c_test_server
dockerfile: Dockerfile
container_name: h2c_test
restart: unless-stopped
labels:
proxy.#1.scheme: h2c
proxy.#1.port: 80
tcp_echo_server: # issue #230 TLS passthrough / termination
build:
context: cmd/tcp_echo_server
dockerfile: Dockerfile
container_name: tcp_echo_test
restart: unless-stopped
labels:
proxy.aliases: tcp-echo-passthrough,tcp-echo-termination
proxy.#1.scheme: tcp
proxy.#1.port: 443:9443
proxy.#1.healthcheck.disable: true
proxy.#2.scheme: tcp
proxy.#2.port: 443:9000
proxy.#2.tls_termination: true
proxy.#2.healthcheck.disable: true
bench: # raw TCP HTTP/1.1 responder for all benchmark endpoints
<<: *benchmark
build:
context: cmd/bench_server
dockerfile: Dockerfile
container_name: bench
godoxy:
<<: *benchmark
depends_on:
- bench
build: .
container_name: godoxy-benchmark
environment:
HTTP3_ENABLED: "true"
ports:
- 8080:80
- 8440:443
- 8440:443/udp
configs:
- source: godoxy_config
target: /app/config/config.yml
- source: godoxy_provider
target: /app/config/providers.yml
- source: benchmark_cert
target: /app/certs/bench.crt
- source: benchmark_key
target: /app/certs/bench.key
traefik:
<<: *benchmark
depends_on:
- bench
image: traefik:v3.6.15
container_name: traefik
command:
- --api.insecure=true
- --entrypoints.web.address=:8081
- --entrypoints.websecure.address=:8441
- --entrypoints.websecure.http3=true
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
- --log.level=ERROR
ports:
- 8081:8081
- 8441:8441
- 8441:8441/udp
configs:
- source: traefik_config
target: /etc/traefik/dynamic/routes.yml
- source: benchmark_cert
target: /etc/traefik/certs/bench.crt
- source: benchmark_key
target: /etc/traefik/certs/bench.key
caddy:
<<: *benchmark
depends_on:
- bench
image: caddy:2.11.2
container_name: caddy
ports:
- 8082:80
- 8442:443
- 8442:443/udp
configs:
- source: caddy_config
target: /etc/caddy/Caddyfile
- source: benchmark_cert
target: /etc/caddy/bench.crt
- source: benchmark_key
target: /etc/caddy/bench.key
tmpfs:
- /data
- /config
nginx:
<<: *benchmark
depends_on:
- bench
image: nginx:1.29.8
container_name: nginx
command: nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
ports:
- 8083:80
- 8443:443
- 8443:443/udp
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
- source: benchmark_cert
target: /etc/nginx/certs/bench.crt
- source: benchmark_key
target: /etc/nginx/certs/bench.key
configs:
godoxy_config:
content: |
autocert:
provider: local
cert_path: /app/certs/bench.crt
key_path: /app/certs/bench.key
providers:
include:
- providers.yml
godoxy_provider:
content: |
bench.domain.com:
host: bench
port: 80
healthcheck:
disable: true
benchmark_cert:
file: ./dev-data/certs/bench.domain.com.crt
benchmark_key:
file: ./dev-data/certs/bench.domain.com.key
traefik_config:
content: |
tls:
certificates:
- certFile: /etc/traefik/certs/bench.crt
keyFile: /etc/traefik/certs/bench.key
http:
routers:
bench:
rule: "Host(`bench.domain.com`)"
entryPoints:
- web
service: bench
bench-h3:
rule: "Host(`bench.domain.com`)"
entryPoints:
- websecure
tls: {}
service: bench
services:
bench:
loadBalancer:
servers:
- url: "http://bench:80"
caddy_config:
content: |
{
admin off
auto_https off
default_bind 0.0.0.0
servers {
protocols h1 h2 h3
}
}
(bench_proxy) {
reverse_proxy bench:80 {
lb_try_duration 2s
lb_try_interval 10ms
transport http {
keepalive 2m
keepalive_idle_conns 10000
keepalive_idle_conns_per_host 1000
compression off
dial_timeout 1s
dial_fallback_delay -1s
}
}
}
http://bench.domain.com {
import bench_proxy
}
https://bench.domain.com {
tls /etc/caddy/bench.crt /etc/caddy/bench.key
import bench_proxy
}
nginx_config:
content: |
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /dev/null;
pid /var/run/nginx.pid;
events {
worker_connections 10240;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log off;
map $$http_upgrade $$connection_upgrade {
default upgrade;
'' '';
}
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# HTTP/3 benchmarks reuse QUIC connections heavily. The default/low
# keepalive request cap makes Nginx send a graceful H3 close after the
# cap is reached, which benchmark clients report as H3_NO_ERROR.
keepalive_requests 1000000;
upstream backend {
server bench:80;
keepalive 128;
}
server {
listen 80 default_server;
server_name _;
return 404;
}
server {
listen 80;
server_name bench.domain.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
}
location /upload {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_request_buffering off;
}
location /stream {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
location /sse {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $$http_upgrade;
proxy_set_header Connection $$connection_upgrade;
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
}
server {
listen 443 ssl;
listen 443 quic reuseport;
http2 on;
http3 on;
server_name bench.domain.com;
ssl_certificate /etc/nginx/certs/bench.crt;
ssl_certificate_key /etc/nginx/certs/bench.key;
add_header Alt-Svc 'h3=":443"; ma=86400';
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
}
location /upload {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_request_buffering off;
}
location /stream {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
location /sse {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $$http_upgrade;
proxy_set_header Connection $$connection_upgrade;
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
}
}
parca:
content: |
object_storage:
bucket:
type: "FILESYSTEM"
config:
directory: "./data"
scrape_configs:
- job_name: "parca"
scrape_interval: "1s"
static_configs:
- targets: [ 'localhost:7777' ]