- 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
303 lines
7.5 KiB
Markdown
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/) |