# Tutorial: Docker Compose with Tailscale Remote Access

Deploy LLMHosts with Docker Compose and access it from anywhere via Tailscale. This is the recommended production setup for home servers.

**Time**: ~20 minutes | **Prerequisites**: Ubuntu 22.04+, Docker, a domain (optional), Tailscale account (free)

## 1. Clone the Repository

```bash
git clone https://github.com/LookNoHandsMom/LLMHosts.com.git
cd LLMHosts.com
```

Or use the bootstrap script:
```bash
curl -fsSL https://raw.githubusercontent.com/LookNoHandsMom/LLMHosts.com/main/scripts/bootstrap.sh | bash
```

## 2. Configure Environment

```bash
cp .env.example .env
```

Edit `.env` with your values:
```bash
# Required
DOMAIN=llmhosts.example.com          # Your domain (or localhost for Tailscale-only)
ACME_EMAIL=you@example.com           # For Let's Encrypt TLS
NEXTAUTH_SECRET=$(openssl rand -base64 32)

# Optional: Cloud API keys for BYOK
# OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...

# Optional: Email (for signup verification)
# RESEND_API_KEY=re_...
```

## 3. Start Services

```bash
# Standard deployment (includes Traefik for TLS)
docker compose -f docker-compose.prod.yml up -d

# Or if you have an existing reverse proxy (Pangolin, Caddy, nginx):
docker compose -f docker-compose.prod.yml -f docker-compose.external-proxy.yml up -d
```

Verify:
```bash
docker compose -f docker-compose.prod.yml ps
curl http://localhost:4000/health
```

## 4. Install Tailscale

Tailscale creates a secure WireGuard mesh network. Your LLMHosts server gets a stable IP accessible from any device on your tailnet.

```bash
# Install
curl -fsSL https://tailscale.com/install.sh | sh

# Authenticate
sudo tailscale up

# Get your Tailscale IP
tailscale ip -4
# Example: 100.64.0.1
```

## 5. Configure LLMHosts Tunnel

LLMHosts auto-detects Tailscale:

```bash
# From within the LLMHosts container or host:
llmhosts tunnel start
# Output: Tailscale detected. LLMHosts is accessible at:
#   http://100.64.0.1:4000
```

Or set it in `.env`:
```bash
TAILSCALE_AUTHKEY=tskey-auth-...   # Optional: for Docker container auth
```

## 6. Access from Anywhere

From any device on your Tailscale network:

```bash
# From your laptop, phone, or another server
curl http://100.64.0.1:4000/health
curl http://100.64.0.1:4000/v1/models
```

Use in the OpenAI Python SDK:
```python
from openai import OpenAI

client = OpenAI(
    base_url="http://100.64.0.1:4000/v1",  # Tailscale IP
    api_key="llmh_your_key"
)

response = client.chat.completions.create(
    model="llama2:7b",
    messages=[{"role": "user", "content": "Hello from remote!"}]
)
```

## 7. Enable HTTPS with Tailscale (Optional)

Tailscale can provision TLS certificates for your machine:

```bash
sudo tailscale cert your-machine.tailnet-name.ts.net
```

Then configure LLMHosts to use the Tailscale HTTPS address instead of the IP.

## 8. Cloudflare Tunnel Alternative

If you prefer Cloudflare Tunnel (no port forwarding, works behind CGNAT):

```bash
# Install cloudflared
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install -y cloudflared

# Authenticate and create tunnel
cloudflared tunnel login
cloudflared tunnel create llmhosts
cloudflared tunnel route dns llmhosts llmhosts.example.com

# Add token to .env
echo "CLOUDFLARE_TUNNEL_TOKEN=<your-token>" >> .env

# LLMHosts auto-detects:
llmhosts tunnel start
```

## 9. Verify End-to-End

```bash
# Local
curl http://localhost:4000/health

# Via Tailscale
curl http://100.64.0.1:4000/health

# Via domain (if configured)
curl https://llmhosts.example.com/health

# Full inference test
curl -X POST http://100.64.0.1:4000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama2:7b",
    "messages": [{"role": "user", "content": "Hello from remote!"}]
  }'
```

## Architecture

```
┌──────────────────────────────┐
│  Your Home Server            │
│  ┌────────┐  ┌────────────┐  │
│  │Traefik │  │ LLMHosts   │  │
│  │:80/:443│  │ :4000      │  │
│  └────────┘  └────────────┘  │
│  ┌────────────┐ ┌─────────┐  │
│  │ Frontend   │ │ Ollama  │  │
│  │ :3000      │ │ :11434  │  │
│  └────────────┘ └─────────┘  │
│  ┌────────────────────────┐  │
│  │ Tailscale (100.64.x.x) │  │
│  └────────────────────────┘  │
└──────────────────────────────┘
        │ WireGuard tunnel
┌───────┴──────┐
│ Your Laptop  │
│ curl :4000   │
└──────────────┘
```

## Troubleshooting

| Issue | Fix |
|-------|-----|
| Can't reach Tailscale IP | Run `tailscale status` on both machines. Both must be on same tailnet. |
| Tailscale not detected by LLMHosts | Install Tailscale on the host, not inside Docker |
| Cloudflare tunnel timeout | Check `cloudflared tunnel info` and verify DNS routing |
| `502` via tunnel but works locally | Ensure LLMHosts binds to `0.0.0.0` not `127.0.0.1` |

## Next Steps

- [Add GPU inference](./single-gpu-ollama.md)
- [Scale to Kubernetes](../deployment/migration-path.md)
- [API Reference](../guides/api-reference.md)
