100 lines
3.3 KiB
YAML
100 lines
3.3 KiB
YAML
# Production-shaped Linux server deployment. Copy server.toml from docs/examples/
|
|
# and supply the TLS certificate/key as read-only files.
|
|
#
|
|
# `rvbox-server` stays private to this Compose network: nginx is the only public
|
|
# listener. JSON-RPC remains disabled in server.toml by default.
|
|
name: rvbox-server
|
|
|
|
services:
|
|
init:
|
|
image: "${RVBOX_SERVER_IMAGE:?set RVBOX_SERVER_IMAGE to a pinned rvbox-server image}"
|
|
user: "0:0"
|
|
entrypoint: ["/bin/sh", "-ec"]
|
|
# Compose does not turn a scalar `command` into one shell script argument.
|
|
# Preserve this whole program as $0 for /bin/sh -c rather than passing
|
|
# `mkdir` followed by its words as separate shell positional arguments.
|
|
command: ["mkdir -p /var/lib/rvbox-server /run/rvbox && chown 65532:65532 /var/lib/rvbox-server /run/rvbox && chmod 0700 /var/lib/rvbox-server /run/rvbox"]
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp:mode=1777,size=8m
|
|
volumes:
|
|
- server-data:/var/lib/rvbox-server
|
|
- server-run:/run/rvbox
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop: ["ALL"]
|
|
cap_add: ["CHOWN", "FOWNER"]
|
|
|
|
server:
|
|
image: "${RVBOX_SERVER_IMAGE:?set RVBOX_SERVER_IMAGE to a pinned rvbox-server image}"
|
|
restart: unless-stopped
|
|
command: ["--config", "/etc/rvbox/server.toml"]
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp:mode=1777,size=32m
|
|
volumes:
|
|
- type: bind
|
|
source: ${RVBOX_SERVER_CONFIG:-./server.toml}
|
|
target: /etc/rvbox/server.toml
|
|
read_only: true
|
|
- type: volume
|
|
source: server-data
|
|
target: /var/lib/rvbox-server
|
|
- type: volume
|
|
source: server-run
|
|
target: /run/rvbox
|
|
expose:
|
|
- "6899"
|
|
- "6901"
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:6901/readyz"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 4
|
|
start_period: 20s
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop: ["ALL"]
|
|
depends_on:
|
|
init:
|
|
condition: service_completed_successfully
|
|
|
|
nginx:
|
|
image: nginx:1.27.5-alpine
|
|
restart: unless-stopped
|
|
read_only: true
|
|
depends_on:
|
|
server:
|
|
condition: service_healthy
|
|
ports:
|
|
- "${RVBOX_HTTPS_BIND:-0.0.0.0}:${RVBOX_HTTPS_PORT:-443}:443"
|
|
tmpfs:
|
|
- /var/cache/nginx:uid=101,gid=101,mode=0755,size=16m
|
|
- /var/run:uid=101,gid=101,mode=0755,size=4m
|
|
volumes:
|
|
- type: bind
|
|
source: ./nginx.conf
|
|
target: /etc/nginx/conf.d/default.conf
|
|
read_only: true
|
|
- type: bind
|
|
source: ${RVBOX_TLS_CERT:?set RVBOX_TLS_CERT to the public certificate path}
|
|
target: /etc/nginx/tls/server.pem
|
|
read_only: true
|
|
- type: bind
|
|
source: ${RVBOX_TLS_KEY:?set RVBOX_TLS_KEY to the private key path}
|
|
target: /etc/nginx/tls/server-key.pem
|
|
read_only: true
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop: ["ALL"]
|
|
# The nginx master creates worker-owned temporary directories beneath its
|
|
# explicitly mounted tmpfs paths, then drops workers to UID/GID 101. These
|
|
# are the exact bootstrap capabilities required for that lifecycle,
|
|
# including Docker user-namespace-remapping hosts; it retains no network,
|
|
# process, mount, or broad administration capability.
|
|
cap_add: ["NET_BIND_SERVICE", "DAC_OVERRIDE", "CHOWN", "SETUID", "SETGID"]
|
|
|
|
volumes:
|
|
server-data:
|
|
server-run:
|