Back to skills
SKILL.md
Collection
BSecurityDeploy 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
Works with
Security analysis
84/100- Uses curl or wget to download content
- Exfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study
Pro scans all 21 files and shows the line behind each finding
npx -y skills add mattnigh/skills_collection --skill collection --agent claude-codeAre you the author of Collection?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/mattnigh-collection-334fe927)---
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.md
- 17hz__nextjs-template__claude__skills__example-skill__SKILL.md
- 1ambda__dataops-platform__claude__skills__context-synthesis__SKILL.md
- 1natsu172__dotfiles__claude__skills__git-analysis__SKILL.md
- 1natsu172__dotfiles__claude__skills__github-pr-best-practices__SKILL.md
- 23Maestro__prospect-pipeline__claude__skills__npid-fastapi-skill.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-code-javascript__SKILL.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-code-python__SKILL.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-expression-syntax__SKILL.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-mcp-tools-expert__SKILL.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-node-configuration__SKILL.md
- 360AYA25__ClaudeN8N__claude__skills__n8n-workflow-patterns__SKILL.md
- 3x-Projetos__claude-memory-framework__claude__skills__scientist__SKILL.md
- 5MinFutures__futures-arena__claude__skills__migration-tracker__SKILL.md
- 5MinFutures__futures-arena__claude__skills__planning-guidelines__SKILL.md
- 92Bilal26__TaskPilotAI__claude__skills__assessment-builder__SKILL.md
- 92Bilal26__TaskPilotAI__claude__skills__book-scaffolding__SKILL.md
- 92Bilal26__TaskPilotAI__claude__skills__code-validation-sandbox__SKILL.md
- 92Bilal26__TaskPilotAI__claude__skills__exercise-designer__SKILL.md
- 92Bilal26__TaskPilotAI__claude__skills__learning-objectives__SKILL.md
Attribution
Related skills
View all in security →Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.