detached 7b54de4

docs(config): document standalone l4 services

commit
7b54de4175e1113a2cd9800dc7ab2103962c1493
author
brice · · 2026-06-30 15:55 UTC
parent
3c7cade
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
7 files · +213 -3
M docs/cli/traffic.md +3 -0
@@ -15,6 +15,8 @@ gordon traffic status --remote prod
1515 gordon traffic status --remote https://gordon.example.com --json
1616 ```
1717
18+Remote mode queries the running Gordon admin API. Local mode does not synthesize runtime traffic state from a fresh config load; use a configured remote target for authoritative counters and reload status.
19+
1820 ## Flags
1921
2022 | Flag | Description |
@@ -87,4 +89,5 @@ gordon traffic status --remote https://gordon.example.com --json
8789 ## Related
8890
8991 - [Traffic configuration](../config/traffic.md)
92+- [Standalone services](../config/services.md)
9093 - [Server status](./status.md)
@@ -15,6 +15,8 @@ gordon traffic status --remote prod
15 gordon traffic status --remote https://gordon.example.com --json15 gordon traffic status --remote https://gordon.example.com --json
16 ```16 ```
17 17
18+Remote mode queries the running Gordon admin API. Local mode does not synthesize runtime traffic state from a fresh config load; use a configured remote target for authoritative counters and reload status.
19+
18 ## Flags20 ## Flags
19 21
20 | Flag | Description |22 | Flag | Description |
@@ -87,4 +89,5 @@ gordon traffic status --remote https://gordon.example.com --json
87 ## Related89 ## Related
88 90
89 - [Traffic configuration](../config/traffic.md)91 - [Traffic configuration](../config/traffic.md)
92+- [Standalone services](../config/services.md)
90 - [Server status](./status.md)93 - [Server status](./status.md)
M docs/config/index.md +1 -0
@@ -289,6 +289,7 @@ Pattern: `GORDON_SECTION_KEY` (uppercase, underscores instead of dots)
289289 - [Server Configuration](./server.md)
290290 - [Routes Configuration](./routes.md)
291291 - [External Routes](./external-routes.md)
292+- [Standalone Services](./services.md)
292293 - [Traffic Plane](./traffic.md)
293294 - [Authentication](./auth.md)
294295 - [Telemetry](./telemetry.md)
@@ -289,6 +289,7 @@ Pattern: `GORDON_SECTION_KEY` (uppercase, underscores instead of dots)
289 - [Server Configuration](./server.md)289 - [Server Configuration](./server.md)
290 - [Routes Configuration](./routes.md)290 - [Routes Configuration](./routes.md)
291 - [External Routes](./external-routes.md)291 - [External Routes](./external-routes.md)
292+- [Standalone Services](./services.md)
292 - [Traffic Plane](./traffic.md)293 - [Traffic Plane](./traffic.md)
293 - [Authentication](./auth.md)294 - [Authentication](./auth.md)
294 - [Telemetry](./telemetry.md)295 - [Telemetry](./telemetry.md)
M docs/config/reference.md +44 -0
@@ -173,6 +173,28 @@ preserve = true # Keep volumes when containers are
173173 [external_routes]
174174 # "domain.com" = "host:port" # Proxy to non-container services
175175
176+# =============================================================================
177+# STANDALONE SERVICES
178+# =============================================================================
179+# [[services]]
180+# name = "rust"
181+# image = "registry.example.com:5000/rust:latest"
182+# enabled = true
183+# env_file = "/srv/gordon/services/rust.env"
184+#
185+# [[services.ports]]
186+# name = "game"
187+# container = 28015
188+# protocol = "udp"
189+# publish = "127.0.0.1:38015"
190+#
191+# [[services.ports]]
192+# name = "rcon"
193+# container = 28016
194+# protocol = "tcp"
195+# publish = "127.0.0.1:38016"
196+# trusted_cidrs = ["100.64.0.0/10"]
197+
176198 # =============================================================================
177199 # NETWORK GROUPS
178200 # =============================================================================
@@ -292,6 +314,27 @@ keep_last = 3 # Keep N newest tags per repository
292314 | `volumes.auto_create` | `true` | Auto-create volumes |
293315 | `volumes.prefix` | `"gordon"` | Volume prefix |
294316 | `volumes.preserve` | `true` | Keep volumes |
317+| `services[].name` | none | Standalone service name used by `service:<name>:<port>` traffic refs |
318+| `services[].image` | none | Container image for enabled standalone services |
319+| `services[].enabled` | `false` | Whether Gordon creates, starts, and reconciles the service container |
320+| `services[].env` | `[]` | Inline `KEY=value` environment entries |
321+| `services[].env_file` | `""` | Env file loaded before inline entries |
322+| `services[].ports[].name` | none | Port name used by traffic service refs |
323+| `services[].ports[].container` | none | Container port number |
324+| `services[].ports[].protocol` | none | `tcp` or `udp` |
325+| `services[].ports[].publish` | `""` | Host-side publish address, usually loopback for traffic-manager reachability |
326+| `services[].ports[].private` | `false` | Require matching service and entrypoint `trusted_cidrs` for this port |
327+| `services[].ports[].public` | `false` | Explicit public opt-out for admin port names such as `rcon` |
328+| `services[].ports[].trusted_cidrs` | `[]` | CIDRs allowed for private port routing; must match the target entrypoint |
329+| `services[].volumes[].source` | `""` | Explicit named volume or bind source; omitted service volumes use image `VOLUME` metadata |
330+| `services[].volumes[].target` | none | Absolute container mount path |
331+| `services[].volumes[].read_only` | `false` | Mount explicit volume read-only |
332+| `services[].readiness.type` | `"none"` | `none`, `tcp`, or `log` |
333+| `services[].readiness.path` | `""` | Log readiness path inside the container |
334+| `services[].readiness.contains` | `""` | Text required in the readiness log |
335+| `services[].readiness.timeout` | default wait | Positive readiness timeout when set |
336+| `services[].cleanup.preserve_volumes` | `true` | Preserve managed image-discovered volumes on cleanup |
337+| `services[].cleanup.remove_container` | `true` | Remove old, disabled, or removed service containers |
295338 | `backups.enabled` | `false` | Backup service disabled |
296339 | `backups.schedule` | `"daily"` | Backup scheduler preset |
297340 | `backups.storage_dir` | `""` | Uses `{server.data_dir}/backups` when empty |
@@ -377,4 +420,5 @@ gordon serve
377420 - [Telemetry](./telemetry.md)
378421 - [Network Isolation](./network-isolation.md)
379422 - [Volumes](./volumes.md)
423+- [Standalone Services](./services.md)
380424 - [Images](./images.md)
@@ -173,6 +173,28 @@ preserve = true # Keep volumes when containers are
173 [external_routes]173 [external_routes]
174 # "domain.com" = "host:port" # Proxy to non-container services174 # "domain.com" = "host:port" # Proxy to non-container services
175 175
176+# =============================================================================
177+# STANDALONE SERVICES
178+# =============================================================================
179+# [[services]]
180+# name = "rust"
181+# image = "registry.example.com:5000/rust:latest"
182+# enabled = true
183+# env_file = "/srv/gordon/services/rust.env"
184+#
185+# [[services.ports]]
186+# name = "game"
187+# container = 28015
188+# protocol = "udp"
189+# publish = "127.0.0.1:38015"
190+#
191+# [[services.ports]]
192+# name = "rcon"
193+# container = 28016
194+# protocol = "tcp"
195+# publish = "127.0.0.1:38016"
196+# trusted_cidrs = ["100.64.0.0/10"]
197+
176 # =============================================================================198 # =============================================================================
177 # NETWORK GROUPS199 # NETWORK GROUPS
178 # =============================================================================200 # =============================================================================
@@ -292,6 +314,27 @@ keep_last = 3 # Keep N newest tags per repository
292 | `volumes.auto_create` | `true` | Auto-create volumes |314 | `volumes.auto_create` | `true` | Auto-create volumes |
293 | `volumes.prefix` | `"gordon"` | Volume prefix |315 | `volumes.prefix` | `"gordon"` | Volume prefix |
294 | `volumes.preserve` | `true` | Keep volumes |316 | `volumes.preserve` | `true` | Keep volumes |
317+| `services[].name` | none | Standalone service name used by `service:<name>:<port>` traffic refs |
318+| `services[].image` | none | Container image for enabled standalone services |
319+| `services[].enabled` | `false` | Whether Gordon creates, starts, and reconciles the service container |
320+| `services[].env` | `[]` | Inline `KEY=value` environment entries |
321+| `services[].env_file` | `""` | Env file loaded before inline entries |
322+| `services[].ports[].name` | none | Port name used by traffic service refs |
323+| `services[].ports[].container` | none | Container port number |
324+| `services[].ports[].protocol` | none | `tcp` or `udp` |
325+| `services[].ports[].publish` | `""` | Host-side publish address, usually loopback for traffic-manager reachability |
326+| `services[].ports[].private` | `false` | Require matching service and entrypoint `trusted_cidrs` for this port |
327+| `services[].ports[].public` | `false` | Explicit public opt-out for admin port names such as `rcon` |
328+| `services[].ports[].trusted_cidrs` | `[]` | CIDRs allowed for private port routing; must match the target entrypoint |
329+| `services[].volumes[].source` | `""` | Explicit named volume or bind source; omitted service volumes use image `VOLUME` metadata |
330+| `services[].volumes[].target` | none | Absolute container mount path |
331+| `services[].volumes[].read_only` | `false` | Mount explicit volume read-only |
332+| `services[].readiness.type` | `"none"` | `none`, `tcp`, or `log` |
333+| `services[].readiness.path` | `""` | Log readiness path inside the container |
334+| `services[].readiness.contains` | `""` | Text required in the readiness log |
335+| `services[].readiness.timeout` | default wait | Positive readiness timeout when set |
336+| `services[].cleanup.preserve_volumes` | `true` | Preserve managed image-discovered volumes on cleanup |
337+| `services[].cleanup.remove_container` | `true` | Remove old, disabled, or removed service containers |
295 | `backups.enabled` | `false` | Backup service disabled |338 | `backups.enabled` | `false` | Backup service disabled |
296 | `backups.schedule` | `"daily"` | Backup scheduler preset |339 | `backups.schedule` | `"daily"` | Backup scheduler preset |
297 | `backups.storage_dir` | `""` | Uses `{server.data_dir}/backups` when empty |340 | `backups.storage_dir` | `""` | Uses `{server.data_dir}/backups` when empty |
@@ -377,4 +420,5 @@ gordon serve
377 - [Telemetry](./telemetry.md)420 - [Telemetry](./telemetry.md)
378 - [Network Isolation](./network-isolation.md)421 - [Network Isolation](./network-isolation.md)
379 - [Volumes](./volumes.md)422 - [Volumes](./volumes.md)
423+- [Standalone Services](./services.md)
380 - [Images](./images.md)424 - [Images](./images.md)
M docs/config/server.md +2 -0
@@ -429,3 +429,5 @@ sudo firewall-cmd --reload
429429 - [Configuration Overview](./index.md)
430430 - [Installation Guide](../installation.md)
431431 - [Routes Configuration](./routes.md)
432+- [Standalone Services](./services.md)
433+- [Traffic Plane Configuration](./traffic.md)
@@ -429,3 +429,5 @@ sudo firewall-cmd --reload
429 - [Configuration Overview](./index.md)429 - [Configuration Overview](./index.md)
430 - [Installation Guide](../installation.md)430 - [Installation Guide](../installation.md)
431 - [Routes Configuration](./routes.md)431 - [Routes Configuration](./routes.md)
432+- [Standalone Services](./services.md)
433+- [Traffic Plane Configuration](./traffic.md)
A docs/config/services.md +94 -0
@@ -0,0 +1,94 @@
1+# Standalone Services
2+
3+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.
4+
5+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.
6+
7+## Example
8+
9+```toml
10+[[services]]
11+name = "rust"
12+image = "registry.example.com:5000/rust:latest"
13+enabled = true
14+env_file = "/srv/gordon/services/rust.env"
15+
16+[services.readiness]
17+type = "log"
18+path = "/steamcmd/rust/server.log"
19+contains = "Server startup complete"
20+timeout = "2m"
21+
22+[[services.ports]]
23+name = "game"
24+container = 28015
25+protocol = "udp"
26+publish = "127.0.0.1:38015"
27+
28+[[services.ports]]
29+name = "rcon"
30+container = 28016
31+protocol = "tcp"
32+publish = "127.0.0.1:38016"
33+trusted_cidrs = ["100.64.0.0/10"]
34+```
35+
36+The `publish` address is the host-side loopback address that Gordon's traffic manager dials. Expose it through `[traffic]` routers instead of binding the service container directly to a public interface.
37+
38+## Traffic routing
39+
40+Use `service:<service-name>:<port-name>` from TCP, UDP, or TLS passthrough routers:
41+
42+```toml
43+[entrypoints.rust]
44+address = "0.0.0.0:28015"
45+protocol = "udp"
46+
47+[[traffic.udp.routers]]
48+name = "rust-game"
49+entrypoint = "rust"
50+service = "service:rust:game"
51+
52+[entrypoints.rcon]
53+address = "0.0.0.0:28016"
54+protocol = "tcp"
55+trusted_cidrs = ["100.64.0.0/10"]
56+
57+[[traffic.tcp.routers]]
58+name = "rust-rcon"
59+entrypoint = "rcon"
60+service = "service:rust:rcon"
61+```
62+
63+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.
64+
65+## Volumes
66+
67+Explicit volumes are optional:
68+
69+```toml
70+[[services.volumes]]
71+source = "rust-data"
72+target = "/steamcmd/rust"
73+read_only = false
74+```
75+
76+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.
77+
78+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.
79+
80+## Cleanup
81+
82+```toml
83+[services.cleanup]
84+preserve_volumes = true
85+remove_container = true
86+```
87+
88+By 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)
@@ -0,0 +1,94 @@
1+# Standalone Services
2+
3+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.
4+
5+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.
6+
7+## Example
8+
9+```toml
10+[[services]]
11+name = "rust"
12+image = "registry.example.com:5000/rust:latest"
13+enabled = true
14+env_file = "/srv/gordon/services/rust.env"
15+
16+[services.readiness]
17+type = "log"
18+path = "/steamcmd/rust/server.log"
19+contains = "Server startup complete"
20+timeout = "2m"
21+
22+[[services.ports]]
23+name = "game"
24+container = 28015
25+protocol = "udp"
26+publish = "127.0.0.1:38015"
27+
28+[[services.ports]]
29+name = "rcon"
30+container = 28016
31+protocol = "tcp"
32+publish = "127.0.0.1:38016"
33+trusted_cidrs = ["100.64.0.0/10"]
34+```
35+
36+The `publish` address is the host-side loopback address that Gordon's traffic manager dials. Expose it through `[traffic]` routers instead of binding the service container directly to a public interface.
37+
38+## Traffic routing
39+
40+Use `service:<service-name>:<port-name>` from TCP, UDP, or TLS passthrough routers:
41+
42+```toml
43+[entrypoints.rust]
44+address = "0.0.0.0:28015"
45+protocol = "udp"
46+
47+[[traffic.udp.routers]]
48+name = "rust-game"
49+entrypoint = "rust"
50+service = "service:rust:game"
51+
52+[entrypoints.rcon]
53+address = "0.0.0.0:28016"
54+protocol = "tcp"
55+trusted_cidrs = ["100.64.0.0/10"]
56+
57+[[traffic.tcp.routers]]
58+name = "rust-rcon"
59+entrypoint = "rcon"
60+service = "service:rust:rcon"
61+```
62+
63+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.
64+
65+## Volumes
66+
67+Explicit volumes are optional:
68+
69+```toml
70+[[services.volumes]]
71+source = "rust-data"
72+target = "/steamcmd/rust"
73+read_only = false
74+```
75+
76+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.
77+
78+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.
79+
80+## Cleanup
81+
82+```toml
83+[services.cleanup]
84+preserve_volumes = true
85+remove_container = true
86+```
87+
88+By 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)
M docs/config/traffic.md +29 -3
@@ -33,9 +33,33 @@ For each accepted connection on a `smart_tcp` entrypoint Gordon:
3333
3434 Malformed HTTP-looking or TLS-looking traffic is rejected instead of bypassing to raw fallback.
3535
36-## Network Services
36+## Standalone and Network Services
3737
38-Network services describe non-HTTP backends that L4 routers can target.
38+Standalone services are Gordon-managed containers that L4 routers can target with `service:<service>:<port-name>`. Define them under `[[services]]` when Gordon should own the container lifecycle.
39+
40+```toml
41+[[services]]
42+name = "rust"
43+image = "registry.example.com:5000/rust:latest"
44+enabled = true
45+
46+[[services.ports]]
47+name = "game"
48+container = 28015
49+protocol = "udp"
50+publish = "127.0.0.1:38015"
51+
52+[entrypoints.rust]
53+address = "0.0.0.0:28015"
54+protocol = "udp"
55+
56+[[traffic.udp.routers]]
57+name = "rust-game"
58+entrypoint = "rust"
59+service = "service:rust:game"
60+```
61+
62+Network services describe manually managed non-HTTP backends that L4 routers can target.
3963
4064 ```toml
4165 [[network_services]]
@@ -51,7 +75,8 @@ Service references use:
5175
5276 - `route:<domain>` for configured HTTP routes
5377 - `external_route:<domain>` for configured external HTTP routes
54-- `network_service:<service>:<port-name>` for TCP, UDP, and TLS passthrough
78+- `network_service:<service>:<port-name>` for manually managed TCP, UDP, and TLS passthrough backends
79+- `service:<service>:<port-name>` for Gordon-managed standalone service backends
5580
5681 `static:<name>` is reserved and currently unsupported.
5782
@@ -152,4 +177,5 @@ UDP sessions are keyed by client address and expire after `idle_timeout`. If `ma
152177
153178 - [Server Settings](./server.md)
154179 - [Routes](./routes.md)
180+- [Standalone Services](./services.md)
155181 - [CLI traffic status](../cli/traffic.md)
@@ -33,9 +33,33 @@ For each accepted connection on a `smart_tcp` entrypoint Gordon:
33 33
34 Malformed HTTP-looking or TLS-looking traffic is rejected instead of bypassing to raw fallback.34 Malformed HTTP-looking or TLS-looking traffic is rejected instead of bypassing to raw fallback.
35 35
36-## Network Services36+## Standalone and Network Services
37 37
38-Network services describe non-HTTP backends that L4 routers can target.38+Standalone services are Gordon-managed containers that L4 routers can target with `service:<service>:<port-name>`. Define them under `[[services]]` when Gordon should own the container lifecycle.
39+
40+```toml
41+[[services]]
42+name = "rust"
43+image = "registry.example.com:5000/rust:latest"
44+enabled = true
45+
46+[[services.ports]]
47+name = "game"
48+container = 28015
49+protocol = "udp"
50+publish = "127.0.0.1:38015"
51+
52+[entrypoints.rust]
53+address = "0.0.0.0:28015"
54+protocol = "udp"
55+
56+[[traffic.udp.routers]]
57+name = "rust-game"
58+entrypoint = "rust"
59+service = "service:rust:game"
60+```
61+
62+Network services describe manually managed non-HTTP backends that L4 routers can target.
39 63
40 ```toml64 ```toml
41 [[network_services]]65 [[network_services]]
@@ -51,7 +75,8 @@ Service references use:
51 75
52 - `route:<domain>` for configured HTTP routes76 - `route:<domain>` for configured HTTP routes
53 - `external_route:<domain>` for configured external HTTP routes77 - `external_route:<domain>` for configured external HTTP routes
54-- `network_service:<service>:<port-name>` for TCP, UDP, and TLS passthrough78+- `network_service:<service>:<port-name>` for manually managed TCP, UDP, and TLS passthrough backends
79+- `service:<service>:<port-name>` for Gordon-managed standalone service backends
55 80
56 `static:<name>` is reserved and currently unsupported.81 `static:<name>` is reserved and currently unsupported.
57 82
@@ -152,4 +177,5 @@ UDP sessions are keyed by client address and expire after `idle_timeout`. If `ma
152 177
153 - [Server Settings](./server.md)178 - [Server Settings](./server.md)
154 - [Routes](./routes.md)179 - [Routes](./routes.md)
180+- [Standalone Services](./services.md)
155 - [CLI traffic status](../cli/traffic.md)181 - [CLI traffic status](../cli/traffic.md)
M gordon.toml.example +40 -0
@@ -174,6 +174,46 @@ keep = 14
174174 [external_routes]
175175 # "status.example.com" = "127.0.0.1:9000"
176176
177+# Gordon-managed standalone L4 services. Use service:<name>:<port> from
178+# traffic routers to expose published loopback ports.
179+# [[services]]
180+# name = "rust"
181+# image = "registry.example.com:5000/rust:latest"
182+# enabled = true
183+# env_file = "/srv/gordon/services/rust.env"
184+#
185+# [[services.ports]]
186+# name = "game"
187+# container = 28015
188+# protocol = "udp"
189+# publish = "127.0.0.1:38015"
190+#
191+# [[services.ports]]
192+# name = "rcon"
193+# container = 28016
194+# protocol = "tcp"
195+# publish = "127.0.0.1:38016"
196+# trusted_cidrs = ["100.64.0.0/10"]
197+#
198+# [entrypoints.rust]
199+# address = "0.0.0.0:28015"
200+# protocol = "udp"
201+#
202+# [[traffic.udp.routers]]
203+# name = "rust-game"
204+# entrypoint = "rust"
205+# service = "service:rust:game"
206+#
207+# [entrypoints.rcon]
208+# address = "0.0.0.0:28016"
209+# protocol = "tcp"
210+# trusted_cidrs = ["100.64.0.0/10"]
211+#
212+# [[traffic.tcp.routers]]
213+# name = "rust-rcon"
214+# entrypoint = "rcon"
215+# service = "service:rust:rcon"
216+
177217 [network_groups]
178218 # "backend" = ["app.example.com", "api.example.com"]
179219
@@ -174,6 +174,46 @@ keep = 14
174 [external_routes]174 [external_routes]
175 # "status.example.com" = "127.0.0.1:9000"175 # "status.example.com" = "127.0.0.1:9000"
176 176
177+# Gordon-managed standalone L4 services. Use service:<name>:<port> from
178+# traffic routers to expose published loopback ports.
179+# [[services]]
180+# name = "rust"
181+# image = "registry.example.com:5000/rust:latest"
182+# enabled = true
183+# env_file = "/srv/gordon/services/rust.env"
184+#
185+# [[services.ports]]
186+# name = "game"
187+# container = 28015
188+# protocol = "udp"
189+# publish = "127.0.0.1:38015"
190+#
191+# [[services.ports]]
192+# name = "rcon"
193+# container = 28016
194+# protocol = "tcp"
195+# publish = "127.0.0.1:38016"
196+# trusted_cidrs = ["100.64.0.0/10"]
197+#
198+# [entrypoints.rust]
199+# address = "0.0.0.0:28015"
200+# protocol = "udp"
201+#
202+# [[traffic.udp.routers]]
203+# name = "rust-game"
204+# entrypoint = "rust"
205+# service = "service:rust:game"
206+#
207+# [entrypoints.rcon]
208+# address = "0.0.0.0:28016"
209+# protocol = "tcp"
210+# trusted_cidrs = ["100.64.0.0/10"]
211+#
212+# [[traffic.tcp.routers]]
213+# name = "rust-rcon"
214+# entrypoint = "rcon"
215+# service = "service:rust:rcon"
216+
177 [network_groups]217 [network_groups]
178 # "backend" = ["app.example.com", "api.example.com"]218 # "backend" = ["app.example.com", "api.example.com"]
179 219

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close