The service template provides a standardized structure for adding new services to ScaleTail. It ensures consistency across all service configurations and makes it easier for users to understand and customize.
Template structure
The template is located at templates/service-template/ and includes:
compose.yaml - Docker Compose configuration with Tailscale sidecar
README.md - Documentation template for the service
.env - Environment variables (not committed to git)
Naming conventions
Follow these naming patterns consistently:
Tailscale container
Application container
tailscale :
container_name : tailscale-${SERVICE}
hostname : ${SERVICE}
Why these names? The tailscale- and app- prefixes make it easy to identify container roles when running docker ps or debugging multi-service deployments.
Template walkthrough
Tailscale sidecar configuration
The Tailscale container handles all networking:
tailscale :
image : tailscale/tailscale:latest
container_name : tailscale-${SERVICE}
hostname : ${SERVICE}
environment :
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_SERVE_CONFIG=/config/serve.json
- TS_USERSPACE=false
- TS_ENABLE_HEALTH_CHECK=true
- TS_LOCAL_ADDR_PORT=127.0.0.1:41234
#- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS
- TS_AUTH_ONCE=true
configs :
- source : ts-serve
target : /config/serve.json
volumes :
- ./config:/config
- ./ts/state:/var/lib/tailscale
devices :
- /dev/net/tun:/dev/net/tun
cap_add :
- net_admin
healthcheck :
test : [ "CMD" , "wget" , "--spider" , "-q" , "http://127.0.0.1:41234/healthz" ]
interval : 1m
timeout : 10s
retries : 3
start_period : 10s
restart : always
Serve configuration
The template includes a pre-configured Tailscale Serve setup:
configs :
ts-serve :
content : |
{"TCP":{"443":{"HTTPS":true}},
"Web":{"$${TS_CERT_DOMAIN}:443":
{"Handlers":{"/":
{"Proxy":"http://127.0.0.1:80"}}}},
"AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}
Update "Proxy":"http://127.0.0.1:80" with your service’s actual internal port. The serve configuration does not consume .env values automatically.
If Serve/Funnel is not needed, remove the TS_SERVE_CONFIG environment variable.
Application configuration
The application container shares the Tailscale network:
application :
image : ${IMAGE_URL}
network_mode : service:tailscale
container_name : app-${SERVICE}
environment :
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
volumes :
- ./${SERVICE}-data/app/config:/config
depends_on :
tailscale :
condition : service_healthy
healthcheck :
test : [ "CMD" , "pgrep" , "-f" , "${SERVICE}" ]
interval : 1m
timeout : 10s
retries : 3
start_period : 30s
restart : always
Port exposure
By default, ports are commented to keep services Tailnet-only:
#ports:
# - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT}
Only uncomment port mappings if LAN exposure is required, and document why in the README.
Testing your configuration
Before committing, validate your stack:
cd services/ < service-nam e >
docker compose config
This command:
Parses your compose.yaml and .env files
Catches syntax errors and missing variables
Shows the final resolved configuration
If docker compose config succeeds without errors, your configuration is syntactically valid.
Environment variables
The .env file contains sensitive values and service-specific configuration:
# Required
TS_AUTHKEY = tskey-auth-xxx
SERVICE = myservice
IMAGE_URL = ghcr.io/maintainer/myservice:latest
# Optional
SERVICEPORT = 8080
TS_CERT_DOMAIN = myservice.tailnet-name.ts.net
DNS_SERVER = 1.1.1.1
Never commit .env files with real auth keys or secrets. Use placeholder values in documentation.
Volume management
Pre-create bind mount paths to prevent Docker from creating root-owned directories:
mkdir -p ./config
mkdir -p ./ts/state
mkdir -p ./ ${ SERVICE } -data/app/config
Some services expect specific config directory names. If conflicts arise (e.g., both Tailscale and the app need ./config), rename one to ./ts-config and update the compose file.
Device and capability requirements
If your service needs special access, add it explicitly:
devices :
- /dev/dri:/dev/dri # GPU access
- /dev/net/tun:/dev/net/tun # Tailscale requirement
cap_add :
- net_admin # Tailscale requirement
- sys_admin # If needed by service
Document all special requirements in the README’s prerequisites section.