Skip to main content
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:
.env
# 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

1

Navigate to the service directory

cd ScaleTail/services/jellyfin
2

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
3

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.
4

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

Build docs developers (and LLMs) love