headscale/docker-dev/README.md
Ryan Malloy 5abc3c87b2 OIDC groups implementation
- Add Groups field to User struct with JSON storage
- Include GetGroups() and SetGroups() helper methods
- Extract groups from OIDC claims in FromClaim()
- Add database migration 202509161200 for groups column
- Update config-example.yaml with groups scope
- Add comprehensive documentation and testing
2026-05-21 17:55:31 -06:00

303 lines
7.5 KiB
Markdown

# Headscale Docker Development Environment
This directory contains a complete Docker Compose setup for running Headscale with Tailscale clients in a local development environment.
## Overview
This setup includes:
- **Headscale server**: The control plane server
- **Two Tailscale clients**: Simulated nodes that connect through Headscale
- **Test web server**: Optional nginx server for connectivity testing
- **Helper scripts**: Automated setup and management tools
## Architecture
```
┌─────────────────────────────────────────┐
│ Docker Network (10.99.0.0/24) │
├─────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ Headscale │ 10.99.0.10 │
│ │ Server │ :8080 (API) │
│ │ │ :9090 (Metrics) │
│ │ │ :50443 (gRPC) │
│ └──────┬───────┘ │
│ │ │
│ ┌────┴────┬─────────┐ │
│ │ │ │ │
│ ┌──▼───┐ ┌──▼───┐ ┌──▼───┐ │
│ │Client│ │Client│ │ Web │ │
│ │ 1 │ │ 2 │ │Server│ │
│ │.0.21 │ │.0.22 │ │.0.30 │ │
│ └──────┘ └──────┘ └──────┘ │
│ │
│ Tailscale Network (100.64.0.0/16) │
└─────────────────────────────────────────┘
```
## Quick Start
### 1. Start the environment
```bash
# Start all services and automatically set up users/keys
make up
# Or manually:
docker compose up -d
make setup
```
### 2. Check status
```bash
# View all nodes
make status
# Watch logs
make logs
```
### 3. Test connectivity
```bash
# Test ping between clients
make ping-test
# Test web server access
make test-web
```
## ✅ Verified Working Setup
This environment has been tested and verified working with:
- **Headscale**: `headscale/headscale:latest` (as of September 2024)
- **Tailscale**: `tailscale/tailscale:latest`
- **Network**: Docker bridge network `10.99.0.0/24`
- **Tailscale Network**: `100.64.0.0/10` with IPv6 `fd7a:115c:a1e0::/48`
- **Port Mapping**: Host port `8180` → Container port `8080` (Headscale API)
### Test Results
- ✅ Headscale server starts and serves on port 8180
- ✅ Both Tailscale clients register automatically with pre-auth keys
- ✅ Clients receive IP addresses: `100.64.0.1` and `100.64.0.2`
- ✅ Bidirectional ping works between clients
-`tailscale status` shows both nodes online
- ✅ Traffic flows through encrypted Tailscale tunnel
### Key Insights from Testing
**Network Architecture**: This setup demonstrates two distinct networking layers:
1. **Docker Bridge Network** (`10.99.0.0/24`) - Physical layer for container communication
2. **Tailscale Overlay Network** (`100.64.0.0/10`) - Encrypted VPN tunnel for secure communication
When clients ping each other, the traffic uses Tailscale IPs (100.64.x.x) but actually travels through the Docker network infrastructure, demonstrating how Tailscale creates an encrypted overlay on top of existing network infrastructure.
## Available Commands
Run `make help` to see all available commands:
- `make up` - Start all services with automatic setup
- `make down` - Stop all services
- `make clean` - Remove everything including volumes
- `make status` - Show status of all nodes
- `make logs` - Show logs from all services
- `make ping-test` - Test connectivity between clients
- `make shell-headscale` - Open shell in Headscale container
- `make shell-client1` - Open shell in Client1 container
- `make shell-client2` - Open shell in Client2 container
## Manual Operations
### Creating users
```bash
docker exec headscale-server headscale users create myuser
```
### Generating pre-auth keys
```bash
docker exec headscale-server headscale preauthkeys create \
--user myuser \
--reusable \
--expiration 24h
```
### Listing nodes
```bash
docker exec headscale-server headscale nodes list
```
### Manual node registration
If automatic registration fails:
1. Start the client registration:
```bash
docker exec tailscale-client1 tailscale up \
--login-server=http://headscale:8080
```
2. Copy the node key from the output
3. Register the node:
```bash
docker exec headscale-server headscale nodes register \
--user testuser \
--key <nodekey>
```
## Configuration
### Headscale Configuration
Edit `headscale-config.yaml` to modify:
- IP ranges for nodes
- DNS settings
- DERP server configuration
- Logging levels
### ACL Policy
Edit `acl.hujson` to modify access control rules. Default policy allows all traffic between all nodes.
### Environment Variables
The `.env` file contains:
- `COMPOSE_PROJECT_NAME`: Docker Compose project name
- `TS_AUTHKEY_CLIENT1`: Pre-auth key for client 1
- `TS_AUTHKEY_CLIENT2`: Pre-auth key for client 2
## Testing Connectivity
### Between Tailscale clients
```bash
# From client1 to client2
docker exec tailscale-client1 tailscale ping client2
# Using regular ping with Tailscale IPs
docker exec tailscale-client1 ping -c 3 100.64.0.2
```
### Through the web server
```bash
# Access the test web server
docker exec tailscale-client1 curl http://webserver
```
## Troubleshooting
### Clients not connecting
1. Check Headscale logs:
```bash
make logs-headscale
```
2. Check client logs:
```bash
make logs-clients
```
3. Verify pre-auth keys are set:
```bash
cat .env
```
4. Try manual registration:
```bash
make register-manual
```
### Network issues
1. Verify Docker network:
```bash
docker network inspect headscale-dev_headscale-net
```
2. Check Tailscale status in clients:
```bash
docker exec tailscale-client1 tailscale status
docker exec tailscale-client2 tailscale status
```
3. Test basic connectivity:
```bash
docker exec tailscale-client1 ping headscale
```
### Reset everything
```bash
make clean
make up
```
## Development Workflow
### Using local Headscale build
1. Build Headscale from source:
```bash
make build-local
```
2. Update `docker-compose.yml`:
```yaml
headscale:
image: headscale:local # Instead of headscale/headscale:latest
```
3. Restart:
```bash
make down
make up
```
### Modifying ACL policies
1. Edit `acl.hujson`
2. Restart Headscale to apply changes:
```bash
docker compose restart headscale
```
### Adding more clients
1. Copy the client service definition in `docker-compose.yml`
2. Update the container name, hostname, and IP address
3. Add a new auth key environment variable
4. Run `make setup` to generate a new key
5. Start the new client
## Security Notes
- This setup is for **development only**
- Uses HTTP instead of HTTPS for simplicity
- Pre-auth keys have 24-hour expiration by default
- All traffic between nodes is allowed by default ACL
## Clean Up
To completely remove the environment:
```bash
make clean
```
This removes:
- All containers
- All volumes (including Headscale database)
- Generated auth keys in `.env`
## Related Documentation
- [Headscale Documentation](https://headscale.net/)
- [Tailscale Documentation](https://tailscale.com/kb/)
- [Docker Compose Documentation](https://docs.docker.com/compose/)