# 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 ``` ## 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/)