Skip to content
Back to skills

Collection

BSecurity

Deploy F# applications with Tailscale sidecar for private network access. Use when: "deploy", "production", "Tailscale", "docker-compose", "Docker", "Portainer", "private network", "deployment", "ship it", "go live", "home server", "self-host", "container", "release". Creates docker-compose.yml with app + Tailscale sidecar for secure access. No public ports, no authentication needed - Tailscale handles it.

  • 24 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
securitygobashsqldockertestinggitdatabasefrontendbackendsecurity

Works with

  • cli

Security analysis

B84/100
  • mediumUses curl or wget to download content
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study

Pro scans all 21 files and shows the line behind each finding

Scanned September 8, 2026

npx -y skills add mattnigh/skills_collection --skill collection --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Collection?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Collection
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/mattnigh-collection-334fe927/badge)](https://www.skillsdirectory.com/skills/mattnigh-collection-334fe927)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: tailscale-deploy
description: |
  Deploy F# applications with Tailscale sidecar for private network access.
  Use when: "deploy", "production", "Tailscale", "docker-compose", "Docker",
  "Portainer", "private network", "deployment", "ship it", "go live",
  "home server", "self-host", "container", "release".
  Creates docker-compose.yml with app + Tailscale sidecar for secure access.
  No public ports, no authentication needed - Tailscale handles it.
allowed-tools: Read, Edit, Write, Grep, Bash
---

# Tailscale Sidecar Deployment

## When to Use This Skill

Activate when:
- User requests "deploy to production", "set up Tailscale"
- Need to create Docker deployment configuration
- Setting up private networking for F# application
- Deploying to Portainer or home server
- User mentions "docker-compose", "deployment", or "Tailscale"

## Prerequisites

- Docker and Docker Compose installed
- Tailscale account (https://tailscale.com)
- F# application with Dockerfile (multi-stage build)
- Target deployment server (Linux recommended)

## Architecture

```
Internet
    ↓ (blocked - no public ports)
Tailscale Network (WireGuard encrypted)
    ↓
Tailscale Sidecar Container
    ↓ (internal network)
F# Application Container
```

**Key Benefits:**
- No public ports exposed
- No authentication needed (Tailscale handles it)
- Access from any device on your Tailnet
- Encrypted WireGuard connections
- Device authorization at network level

## docker-compose.yml

**Location:** Project root

```yaml
version: '3.8'

services:
  # F# Application
  app:
    build: .
    container_name: my-fsharp-app
    restart: unless-stopped
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://+:5000
    volumes:
      # Persist SQLite database and files
      - ./data:/app/data
    networks:
      - app-network
    depends_on:
      - tailscale
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 10s

  # Tailscale Sidecar
  tailscale:
    image: tailscale/tailscale:latest
    container_name: my-fsharp-app-tailscale
    hostname: my-fsharp-app
    restart: unless-stopped
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_HOSTNAME=my-fsharp-app
      - TS_ACCEPT_DNS=true
      - TS_USERSPACE=false
    volumes:
      - tailscale-data:/var/lib/tailscale
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "tailscale", "status"]
      interval: 30s
      timeout: 5s
      retries: 3

networks:
  app-network:
    driver: bridge

volumes:
  tailscale-data:
```

**Configuration Notes:**
- `hostname` - Name that appears in Tailscale admin console
- `TS_HOSTNAME` - DNS name on Tailnet (access via `http://my-fsharp-app`)
- `TS_AUTHKEY` - One-time auth key from Tailscale admin
- `/dev/net/tun` - Required for Tailscale networking
- `cap_add` - Required Linux capabilities for VPN

## Environment Configuration

### .env File

**Location:** Project root (same directory as docker-compose.yml)

```bash
# Tailscale authentication key
TS_AUTHKEY=tskey-auth-xxxxxxxxxxxxx

# Application settings (optional)
ASPNETCORE_ENVIRONMENT=Production
```

**Important:**
- Add `.env` to `.gitignore` (never commit secrets)
- Auth key is one-time use
- Generate new key for each deployment

### Generate Tailscale Auth Key

1. Go to https://login.tailscale.com/admin/settings/keys
2. Click "Generate auth key"
3. **Settings:**
   - ✅ Reusable (if deploying multiple times)
   - ✅ Ephemeral (device removed when container stops)
   - Set expiration (recommend 90 days)
4. Copy key to `.env` file

## Deployment Steps

### Local Development Testing

```bash
# 1. Build application
dotnet build

# 2. Build Docker image
docker build -t my-fsharp-app:latest .

# 3. Start stack
docker-compose up -d

# 4. Check logs
docker-compose logs -f

# 5. Verify Tailscale connection
docker exec my-fsharp-app-tailscale tailscale status

# 6. Access application
# Open browser: http://my-fsharp-app (from any device on Tailnet)
```

### Production Deployment (Portainer)

**Option 1: Using Portainer UI**

1. Login to Portainer (usually `http://server:9000`)
2. Go to **Stacks** → **Add stack**
3. **Name:** `my-fsharp-app`
4. **Build method:** Web editor
5. Paste `docker-compose.yml` content
6. **Environment variables:**
   - Add: `TS_AUTHKEY` = `tskey-auth-xxxxx`
7. Click **Deploy the stack**

**Option 2: Using Git Repository**

1. Push docker-compose.yml to Git repository
2. In Portainer: **Stacks** → **Add stack**
3. **Build method:** Repository
4. Enter Git URL and branch
5. Set environment variables
6. Enable **Automatic updates** (optional)
7. Click **Deploy the stack**

### Verify Deployment

```bash
# Check container status
docker ps

# Check app logs
docker logs my-fsharp-app

# Check Tailscale logs
docker logs my-fsharp-app-tailscale

# Verify Tailscale connection
docker exec my-fsharp-app-tailscale tailscale status

# Check health
docker inspect my-fsharp-app | grep -A 5 Health

# Test app endpoint
curl http://localhost:5000/health  # From server
curl http://my-fsharp-app/health    # From Tailnet device
```

## Accessing the Application

### From Tailnet Devices

**Any device on your Tailnet can access:**
```
http://my-fsharp-app
http://my-fsharp-app:5000
```

**Install Tailscale on devices:**
- Desktop: https://tailscale.com/download
- Mobile: App Store / Google Play
- Login with same Tailscale account

### From Server (Local)

```bash
# Use localhost
curl http://localhost:5000

# Or use Tailscale hostname
curl http://my-fsharp-app:5000
```

## Updating the Application

### Update Code and Redeploy

```bash
# 1. Pull latest code
git pull origin main

# 2. Rebuild Docker image
docker-compose build

# 3. Restart containers
docker-compose up -d

# 4. Check logs
docker-compose logs -f app
```

### In Portainer

1. Go to **Stacks** → your stack
2. Click **Editor**
3. Click **Update the stack**
4. Select **Re-pull image and redeploy**
5. Click **Update**

## Troubleshooting

### Tailscale Connection Issues

```bash
# Check Tailscale status
docker exec my-fsharp-app-tailscale tailscale status

# Check Tailscale logs
docker logs my-fsharp-app-tailscale

# Verify /dev/net/tun exists
ls -la /dev/net/tun

# Restart Tailscale container
docker restart my-fsharp-app-tailscale

# Check network capabilities
docker exec my-fsharp-app-tailscale ip addr show
```

**Common Issues:**

| Issue | Solution |
|-------|----------|
| `/dev/net/tun` not found | Host needs TUN/TAP support: `modprobe tun` |
| Permission denied | Container needs `NET_ADMIN` capability |
| Auth key expired | Generate new key in Tailscale admin |
| Can't reach app | Check app is running: `docker logs my-fsharp-app` |

### Application Issues

```bash
# Check app is running
docker ps | grep my-fsharp-app

# Check app logs
docker logs my-fsharp-app --tail 100

# Check app health
docker exec my-fsharp-app curl -f http://localhost:5000/health

# Check data volume
docker exec my-fsharp-app ls -la /app/data

# Restart app
docker restart my-fsharp-app
```

### Network Issues

```bash
# Check network exists
docker network ls | grep app-network

# Inspect network
docker network inspect app-network

# Check containers can communicate
docker exec my-fsharp-app-tailscale ping -c 3 my-fsharp-app
```

### Data Persistence Issues

```bash
# Check volume exists
docker volume ls | grep tailscale

# Check data directory
ls -la ./data

# Fix permissions (if needed)
sudo chown -R $(id -u):$(id -g) ./data
```

## Multiple Applications

Deploy multiple F# apps on same server:

```yaml
# app1/docker-compose.yml
services:
  app:
    container_name: todo-app
    # ... config
  tailscale:
    container_name: todo-app-tailscale
    hostname: todo-app
    environment:
      - TS_HOSTNAME=todo-app
    # ... config

# app2/docker-compose.yml
services:
  app:
    container_name: notes-app
    # ... config
  tailscale:
    container_name: notes-app-tailscale
    hostname: notes-app
    environment:
      - TS_HOSTNAME=notes-app
    # ... config
```

Access:
- `http://todo-app`
- `http://notes-app`

## Best Practices

### ✅ Do
- Use unique hostnames for each application
- Set auth key expiration (security)
- Use ephemeral keys for temporary deployments
- Monitor Tailscale connection health
- Keep Tailscale image updated
- Persist data in volumes (not containers)
- Use health checks
- Test locally before production deployment

### ❌ Don't
- Expose ports to public internet (defeats Tailscale purpose)
- Commit `.env` file to Git
- Reuse auth keys across environments
- Run without `NET_ADMIN` capability
- Forget to mount `/dev/net/tun`
- Skip health checks
- Deploy without testing locally first

## Security Considerations

**Tailscale Provides:**
- Network-level authentication (device authorization)
- WireGuard encryption
- Access control via Tailscale ACLs
- Automatic certificate management

**Application Still Needs:**
- Input validation (SQL injection, XSS prevention)
- Authorization (who can do what in the app)
- Secure data storage
- Audit logging

**Tailscale Admin:**
- Review connected devices regularly
- Disable/remove unused devices
- Use ACLs to restrict access by group
- Enable MFA for Tailscale account

## Verification Checklist

- [ ] `docker-compose.yml` created
- [ ] `.env` file created with `TS_AUTHKEY`
- [ ] `.env` added to `.gitignore`
- [ ] Tailscale auth key generated
- [ ] Application Dockerfile exists
- [ ] Data directory created
- [ ] Containers start successfully
- [ ] Tailscale shows connected
- [ ] Application accessible via Tailscale hostname
- [ ] Health checks passing
- [ ] Logs show no errors

## Related Skills

- **fsharp-feature** - Complete application to deploy
- **fsharp-backend** - Backend that gets deployed
- **fsharp-frontend** - Frontend that gets deployed

## Related Documentation

- `/docs/07-BUILD-DEPLOY.md` - Docker build and deployment guide
- `/docs/08-TAILSCALE-INTEGRATION.md` - Detailed Tailscale integration
- `CLAUDE.md` - Deployment model overview

## Additional Resources

- [Tailscale Documentation](https://tailscale.com/kb/)
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [Portainer Documentation](https://docs.portainer.io/)
- [ASP.NET Core Deployment](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/)

Files in this skill

  • 0Chan-smc__claude-code-workflow-lab__claude__skills__frontend-dev-guidelines__SKILL.md15.1 KB
  • 17hz__nextjs-template__claude__skills__example-skill__SKILL.md316 B
  • 1ambda__dataops-platform__claude__skills__context-synthesis__SKILL.md3.5 KB
  • 1natsu172__dotfiles__claude__skills__git-analysis__SKILL.md5.4 KB
  • 1natsu172__dotfiles__claude__skills__github-pr-best-practices__SKILL.md7.7 KB
  • 23Maestro__prospect-pipeline__claude__skills__npid-fastapi-skill.md26.1 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-code-javascript__SKILL.md15.7 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-code-python__SKILL.md17.5 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-expression-syntax__SKILL.md9.4 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-mcp-tools-expert__SKILL.md12.5 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-node-configuration__SKILL.md16.6 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-workflow-patterns__SKILL.md11.2 KB
  • 3x-Projetos__claude-memory-framework__claude__skills__scientist__SKILL.md14.8 KB
  • 5MinFutures__futures-arena__claude__skills__migration-tracker__SKILL.md16.2 KB
  • 5MinFutures__futures-arena__claude__skills__planning-guidelines__SKILL.md11.8 KB
  • 92Bilal26__TaskPilotAI__claude__skills__assessment-builder__SKILL.md17.5 KB
  • 92Bilal26__TaskPilotAI__claude__skills__book-scaffolding__SKILL.md19.1 KB
  • 92Bilal26__TaskPilotAI__claude__skills__code-validation-sandbox__SKILL.md6.2 KB
  • 92Bilal26__TaskPilotAI__claude__skills__exercise-designer__SKILL.md18.1 KB
  • 92Bilal26__TaskPilotAI__claude__skills__learning-objectives__SKILL.md24.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in security →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.