ScaleTail uses Docker Compose to orchestrate Tailscale sidecar containers alongside your self-hosted services. This guide covers the complete Docker Compose workflow.
Understanding the compose structure
Every ScaleTail service follows a consistent two-container pattern:
services :
# Tailscale sidecar container
tailscale :
image : tailscale/tailscale:latest
container_name : tailscale-${SERVICE}
hostname : ${SERVICE}
# ... Tailscale configuration
# Application container
application :
image : ${IMAGE_URL}
network_mode : service:tailscale # Routes traffic through Tailscale
container_name : app-${SERVICE}
depends_on :
tailscale :
condition : service_healthy
# ... Application configuration
The network_mode: service:tailscale setting makes the application container share the Tailscale container’s network stack.
Environment configuration
Create a .env file in the service directory to configure variables:
# Tailscale authentication
TS_AUTHKEY = tskey-auth-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Service configuration
SERVICE = jellyfin
IMAGE_URL = jellyfin/jellyfin:latest
SERVICEPORT = 8096
# Tailscale Serve configuration
TS_CERT_DOMAIN = jellyfin
# Optional: DNS server
# DNS_SERVER=1.1.1.1
Never commit .env files containing real auth keys to version control. Add .env to your .gitignore.
Deploying a service
Navigate to the service directory
cd ScaleTail/services/jellyfin
Create the .env file
# Copy from example or create manually
cat > .env << EOF
TS_AUTHKEY=your-auth-key-here
SERVICE=jellyfin
IMAGE_URL=jellyfin/jellyfin:latest
SERVICEPORT=8096
TS_CERT_DOMAIN=jellyfin
EOF
Validate the configuration
# Check for syntax errors and missing variables
docker compose config
The docker compose config command renders the final configuration with all variables substituted. Review it carefully before deploying.
Start the service
# Start in detached mode
docker compose up -d
Managing services
View logs
# All containers
docker compose logs -f
# Specific container
docker compose logs -f tailscale
docker compose logs -f application
# Last 50 lines
docker compose logs --tail=50
Check status
# View running containers
docker compose ps
# Check health status
docker compose ps --format json | jq '.[] | {name: .Name, health: .Health}'
Restart services
# Restart all containers
docker compose restart
# Restart specific container
docker compose restart tailscale
Stop services
# Stop containers (keeps volumes)
docker compose stop
# Stop and remove containers (keeps volumes)
docker compose down
# Stop and remove containers and volumes
docker compose down -v
Using docker compose down -v will delete all data volumes. Only use this if you want to completely remove the service and its data.
Updating services
Update application image
# Pull the latest image
docker compose pull application
# Recreate the container with the new image
docker compose up -d application
Update Tailscale image
# Pull the latest Tailscale image
docker compose pull tailscale
# Recreate both containers (application depends on Tailscale)
docker compose up -d
Update compose.yaml
If you modify the compose.yaml file:
# Validate changes
docker compose config
# Apply changes
docker compose up -d
Multi-service deployments
You can manage multiple services from the repository root:
# Start multiple services
cd ~/ScaleTail
docker compose -f services/jellyfin/compose.yaml -f services/sonarr/compose.yaml up -d
# Or use a custom compose file that includes multiple services
Inspecting the network
View Tailscale IP
# Get the Tailscale IP assigned to the service
docker exec tailscale-jellyfin tailscale ip -4
Check connectivity
# Verify the service is on your Tailnet
docker exec tailscale-jellyfin tailscale status
# Ping another device on your Tailnet
docker exec tailscale-jellyfin ping other-device.your-tailnet.ts.net
Volume management
List volumes
# Show all volumes for the service
docker compose config --volumes
# Inspect a specific volume
docker volume inspect jellyfin_jellyfin-data
Backup volumes
# Stop the service
docker compose stop
# Backup the volume
docker run --rm -v jellyfin_jellyfin-data:/data -v $( pwd ) :/backup \
ubuntu tar czf /backup/jellyfin-backup.tar.gz /data
# Restart the service
docker compose start
Restore volumes
# Stop the service
docker compose stop
# Restore from backup
docker run --rm -v jellyfin_jellyfin-data:/data -v $( pwd ) :/backup \
ubuntu tar xzf /backup/jellyfin-backup.tar.gz -C /
# Restart the service
docker compose start
Resource limits
Add resource limits to prevent services from consuming all system resources:
services :
application :
# ... other configuration
deploy :
resources :
limits :
cpus : '2.0'
memory : 4G
reservations :
cpus : '1.0'
memory : 2G
Docker Compose best practices
Use .env files Keep secrets and configuration in .env files, not in compose.yaml
Validate before deploy Always run docker compose config to catch errors early
Pin image versions Use specific tags instead of latest for production deployments
Monitor logs Regularly check logs with docker compose logs for errors
Next steps
Health checks Configure health checks for reliability
Troubleshooting Solve common deployment issues