Standalone Services
Standalone services are Gordon-managed containers for non-HTTP workloads such as game servers, databases, or TCP/UDP daemons. Gordon creates, starts, restarts, reconciles, and removes these containers from the [[services]] configuration during startup and reload.
Standalone services are separate from HTTP [routes]. Route normal web apps with [routes]; use [[services]] when Gordon must manage a long-running container that is reached by explicit L4 traffic routers.
Example
[[services]]
name = "rust"
image = "registry.example.com:5000/rust:latest"
enabled = true
env_file = "/srv/gordon/services/rust.env"
[services.readiness]
type = "log"
path = "/steamcmd/rust/server.log"
contains = "Server startup complete"
timeout = "2m"
[[services.ports]]
name = "game"
container = 28015
protocol = "udp"
publish = "127.0.0.1:38015"
[[services.ports]]
name = "rcon"
container = 28016
protocol = "tcp"
publish = "127.0.0.1:38016"
trusted_cidrs = ["100.64.0.0/10"]
The publish address is the host-side bind address that Gordon's traffic manager dials; use loopback for private backends. Expose services through [traffic] routers instead of binding service containers directly to a public interface.
Traffic routing
Use service:<service>:<port-name> from TCP, UDP, or TLS passthrough routers:
[entrypoints.rust]
address = "0.0.0.0:28015"
protocol = "udp"
[[traffic.udp.routers]]
name = "rust-game"
entrypoint = "rust"
service = "service:rust:game"
[entrypoints.rcon]
address = "0.0.0.0:28016"
protocol = "tcp"
trusted_cidrs = ["100.64.0.0/10"]
[[traffic.tcp.routers]]
name = "rust-rcon"
entrypoint = "rcon"
service = "service:rust:rcon"
Ports named rcon default to private. Private ports require non-empty trusted_cidrs on both the service port and target entrypoint, and the CIDR sets must match. To intentionally expose an RCON port publicly, set public = true on that port.
Volumes
Explicit volumes are optional:
[[services.volumes]]
source = "rust-data"
target = "/steamcmd/rust"
read_only = false
When [[services.volumes]] is omitted, Gordon inspects the image VOLUME metadata and creates deterministic Gordon-managed named volumes for those paths. If the image has no VOLUME metadata, the service is stateless unless the image writes inside its own filesystem.
Gordon tracks image-discovered managed volumes and only removes those managed volumes when cleanup.preserve_volumes = false. Explicit named volumes and bind mounts are not deleted as managed image volumes.
Cleanup
[services.cleanup]
preserve_volumes = true
remove_container = true
By default Gordon removes old or disabled service containers while preserving volumes. Set preserve_volumes = false only for disposable managed image volumes.
source
1# Standalone Services
2
3Standalone services are Gordon-managed containers for non-HTTP workloads such as game servers, databases, or TCP/UDP daemons. Gordon creates, starts, restarts, reconciles, and removes these containers from the `[[services]]` configuration during startup and reload.
4
5Standalone services are separate from HTTP `[routes]`. Route normal web apps with `[routes]`; use `[[services]]` when Gordon must manage a long-running container that is reached by explicit L4 traffic routers.
6
7## Example
8
9```toml
10[[services]]
11name = "rust"
12image = "registry.example.com:5000/rust:latest"
13enabled = true
14env_file = "/srv/gordon/services/rust.env"
15
16[services.readiness]
17type = "log"
18path = "/steamcmd/rust/server.log"
19contains = "Server startup complete"
20timeout = "2m"
21
22[[services.ports]]
23name = "game"
24container = 28015
25protocol = "udp"
26publish = "127.0.0.1:38015"
27
28[[services.ports]]
29name = "rcon"
30container = 28016
31protocol = "tcp"
32publish = "127.0.0.1:38016"
33trusted_cidrs = ["100.64.0.0/10"]
34```
35
36The `publish` address is the host-side bind address that Gordon's traffic manager dials; use loopback for private backends. Expose services through `[traffic]` routers instead of binding service containers directly to a public interface.
37
38## Traffic routing
39
40Use `service:<service>:<port-name>` from TCP, UDP, or TLS passthrough routers:
41
42```toml
43[entrypoints.rust]
44address = "0.0.0.0:28015"
45protocol = "udp"
46
47[[traffic.udp.routers]]
48name = "rust-game"
49entrypoint = "rust"
50service = "service:rust:game"
51
52[entrypoints.rcon]
53address = "0.0.0.0:28016"
54protocol = "tcp"
55trusted_cidrs = ["100.64.0.0/10"]
56
57[[traffic.tcp.routers]]
58name = "rust-rcon"
59entrypoint = "rcon"
60service = "service:rust:rcon"
61```
62
63Ports named `rcon` default to private. Private ports require non-empty `trusted_cidrs` on both the service port and target entrypoint, and the CIDR sets must match. To intentionally expose an RCON port publicly, set `public = true` on that port.
64
65## Volumes
66
67Explicit volumes are optional:
68
69```toml
70[[services.volumes]]
71source = "rust-data"
72target = "/steamcmd/rust"
73read_only = false
74```
75
76When `[[services.volumes]]` is omitted, Gordon inspects the image `VOLUME` metadata and creates deterministic Gordon-managed named volumes for those paths. If the image has no `VOLUME` metadata, the service is stateless unless the image writes inside its own filesystem.
77
78Gordon tracks image-discovered managed volumes and only removes those managed volumes when `cleanup.preserve_volumes = false`. Explicit named volumes and bind mounts are not deleted as managed image volumes.
79
80## Cleanup
81
82```toml
83[services.cleanup]
84preserve_volumes = true
85remove_container = true
86```
87
88By default Gordon removes old or disabled service containers while preserving volumes. Set `preserve_volumes = false` only for disposable managed image volumes.
89
90## Related
91
92- [Traffic Plane Configuration](./traffic.md)
93- [Configuration Reference](./reference.md)
94- [CLI traffic status](../cli/traffic.md)