Skip to content

Commit 329d35b

Browse files
committed
Release v0.2.0 - Add comprehensive Web UI for management
Major Features: - Browser-based Web UI for complete system management - Dashboard with Tailscale status and system health - Full CRUD operations for Caddy proxies and socat relays - Backup and restore functionality with tar.gz archives - Dual authentication (token + Tailscale network) - Dark theme with responsive design Technical Implementation: - Go-based Web UI with embedded HTML/CSS/JS - Multi-stage Docker build with Go 1.21 - Auto-migration from RELAY_LIST env var to JSON configs - Process management with PID tracking for socat relays - Automatic Caddyfile generation from proxy configs - Web UI runs on port 8021 Configuration Changes: - Added webui.yaml configuration file - New JSON config files: proxies.json, relays.json - Authentication token stored at /var/lib/tailscale/.webui_token - Backups stored at /var/lib/tailscale/backups/ Docker Changes: - Updated Dockerfile with webui-builder stage - Exposed port 8021 for Web UI - Updated start.sh to launch Web UI on startup - Fixed go.mod version from 1.25.6 to 1.21 - Removed user restriction from compose-test.yml Documentation: - Comprehensive README update with Web UI sections - Added CHANGELOG.md with full release notes - Added AGENTS.md for coding agent instructions - Troubleshooting guide and upgrade instructions Files Added: 33 new files in webui/ directory Files Modified: Dockerfile, README.md, compose-test.yml, start.sh Total Lines: ~5,500 lines of Go code + templates + documentation
1 parent a182cc8 commit 329d35b

40 files changed

+5700
-13
lines changed

AGENTS.md

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# Agent Development Guide
2+
3+
This guide provides coding agents with essential information for working with the tailrelay codebase.
4+
5+
## Project Overview
6+
7+
**tailrelay** is a Docker container that combines Tailscale, Caddy, and socat to expose local services (particularly Start9 services) to a Tailscale network. The project includes:
8+
9+
- Docker image building with Tailscale, Caddy, and socat
10+
- Shell script orchestration for service startup
11+
- Python-based integration testing
12+
- Docker Compose for development and testing
13+
14+
## Build, Test & Development Commands
15+
16+
### Build Docker Image
17+
18+
```bash
19+
# Build development image
20+
docker buildx build -t sudocarlos/tailrelay:dev --load .
21+
22+
# Build production image (with version tag)
23+
docker buildx build -t sudocarlos/tailrelay:latest .
24+
```
25+
26+
### Run Tests
27+
28+
```bash
29+
# Full integration test suite (Python)
30+
python docker-compose-test.py
31+
32+
# Full integration test suite (Bash)
33+
./docker-compose-test.sh
34+
35+
# Prerequisites: Create .env file from template
36+
cp .env.example .env
37+
# Edit .env with your TAILRELAY_HOST, TAILNET_DOMAIN, COMPOSE_FILE
38+
```
39+
40+
### Development Environment
41+
42+
```bash
43+
# Start test environment
44+
docker compose -f compose-test.yml up -d
45+
46+
# View logs
47+
docker compose -f compose-test.yml logs tailrelay-test
48+
49+
# Stop test environment
50+
docker compose -f compose-test.yml down
51+
52+
# Check listening ports
53+
docker exec -it tailrelay-test netstat -tulnp | grep LISTEN
54+
55+
# Manual health checks
56+
curl -sSL http://tailrelay-dev:8080 # Test HTTP proxy
57+
curl -sSL http://tailrelay-dev:9002/healthz # Health endpoint
58+
curl -sSL http://tailrelay-dev:9002/metrics # Metrics endpoint
59+
```
60+
61+
### Running Single Tests
62+
63+
Since this project uses integration tests rather than unit tests, there's no single test runner. Tests are curl-based health checks defined in the test scripts:
64+
65+
```bash
66+
# Run a single health check manually
67+
curl -sSL http://${TAILRELAY_HOST}:8080 && echo success || echo fail
68+
curl -sSL http://${TAILRELAY_HOST}:9002/healthz && echo success || echo fail
69+
```
70+
71+
## Code Style Guidelines
72+
73+
### Shell Scripts (Bash/sh)
74+
75+
**File Extensions & Shebangs:**
76+
- Use `.sh` extension for shell scripts
77+
- Use `#!/usr/bin/env bash` for Bash scripts
78+
- Use `#!/bin/ash` for Alpine Linux scripts (Dockerfile entrypoint)
79+
80+
**Style Conventions:**
81+
- Use 4-space indentation (not tabs)
82+
- Variable names in UPPER_SNAKE_CASE for environment variables
83+
- Variable names in lower_snake_case for local variables
84+
- Use `${VAR}` syntax for variable expansion (prefer braces)
85+
- Quote all variables: `"$VAR"` unless word splitting is intended
86+
- Use `set -e` for error handling (fail fast)
87+
- Use `set -x` for debugging (show commands)
88+
89+
**Error Handling:**
90+
```bash
91+
# Check command exit codes
92+
if [ $? -ne 0 ]; then
93+
echo "failed!"
94+
exit 1
95+
fi
96+
97+
# Alternative with conditional execution
98+
command || { echo "failed!"; exit 1; }
99+
```
100+
101+
**Comments:**
102+
- Use `#` for single-line comments
103+
- Add descriptive comments for complex logic
104+
- Document environment variables at the top of scripts
105+
106+
### Python Scripts
107+
108+
**Imports:**
109+
- Standard library imports first
110+
- Third-party imports second
111+
- Separate groups with blank lines
112+
- Alphabetically sorted within groups when practical
113+
114+
```python
115+
import subprocess
116+
import time
117+
import sys
118+
from pathlib import Path
119+
from typing import List, Tuple
120+
121+
from dotenv import load_dotenv
122+
```
123+
124+
**Type Hints:**
125+
- Use type hints for function parameters and return values
126+
- Use `typing` module types: `List`, `Tuple`, `Dict`, etc.
127+
- Example: `def run(cmd: str, *, capture_output=False) -> Tuple[int, str, str]:`
128+
129+
**Naming Conventions:**
130+
- Variables and functions: `lower_snake_case`
131+
- Constants: `UPPER_SNAKE_CASE`
132+
- Classes: `PascalCase`
133+
- Private functions/vars: prefix with `_`
134+
135+
**String Formatting:**
136+
- Prefer f-strings for string interpolation
137+
- Example: `f"❌ Build failed:\n{err}"`
138+
139+
**Error Handling:**
140+
- Use try-except blocks for subprocess timeouts
141+
- Return error codes instead of raising exceptions when appropriate
142+
- Provide descriptive error messages with emoji indicators (✅, ❌, ⚠️)
143+
144+
**Docstrings:**
145+
- Use triple-quoted strings for function documentation
146+
- Include parameter and return value descriptions
147+
148+
```python
149+
def run(cmd: str, *, capture_output=False, timeout=None) -> Tuple[int, str, str]:
150+
"""Run a shell command and return (returncode, stdout, stderr).
151+
If the process times out, return rc=124 and a timeout message instead of raising."""
152+
```
153+
154+
### Dockerfile
155+
156+
**Best Practices:**
157+
- Use `ARG` for build-time variables
158+
- Use `ENV` for runtime variables
159+
- Combine `RUN` commands to reduce layers
160+
- Use `--no-cache` with apk/apt for smaller images
161+
- Add `LABEL` for maintainer information
162+
- Use multi-stage builds when appropriate
163+
164+
**Version Pinning:**
165+
- Pin versions for base images: `tailscale/tailscale:$TAILSCALE_VERSION`
166+
- Pin versions for Alpine packages when stability is critical
167+
168+
### Caddyfile Configuration
169+
170+
**Style:**
171+
- Use tabs for indentation (Caddy convention)
172+
- One site block per listening address
173+
- Group related directives together
174+
- Always specify full domain with port: `host.domain.ts.net:port`
175+
176+
**Common Patterns:**
177+
```
178+
hostname.tailnet.ts.net:port {
179+
reverse_proxy target:port {
180+
header_up Host {upstream_hostport}
181+
trusted_proxies private_ranges
182+
}
183+
}
184+
```
185+
186+
## Environment Variables
187+
188+
**Required Variables:**
189+
- `TS_HOSTNAME` - Tailscale machine name (must match Caddyfile)
190+
- `TS_STATE_DIR` - Tailscale state directory (default: `/var/lib/tailscale/`)
191+
192+
**Optional Variables:**
193+
- `RELAY_LIST` - Comma-separated socat relay definitions: `port:host:port`
194+
- Example: `50001:electrs.embassy:50001,21004:lnd.embassy:10009`
195+
- `TS_EXTRA_FLAGS` - Additional Tailscale flags
196+
- `TS_AUTH_ONCE` - Authenticate once (default: `true`)
197+
- `TS_ENABLE_METRICS` - Enable metrics endpoint (default: `true`)
198+
- `TS_ENABLE_HEALTH_CHECK` - Enable health check endpoint (default: `true`)
199+
200+
**Test Environment Variables (.env file):**
201+
- `TAILRELAY_HOST` - Test container hostname
202+
- `TAILNET_DOMAIN` - Tailscale domain for testing
203+
- `COMPOSE_FILE` - Path to docker-compose test file
204+
205+
## File Structure
206+
207+
```
208+
.
209+
├── Dockerfile # Multi-service container definition
210+
├── start.sh # Container entrypoint script
211+
├── Caddyfile.example # Example Caddy configuration
212+
├── docker-compose-test.py # Python integration tests
213+
├── docker-compose-test.sh # Bash integration tests
214+
├── compose-test.yml # Docker Compose test configuration
215+
├── requirements.txt # Python dependencies (python-dotenv)
216+
├── .env.example # Environment variable template
217+
└── README.md # User documentation
218+
```
219+
220+
## Testing Strategy
221+
222+
**Integration Tests:**
223+
- Build Docker image with dev tag
224+
- Start containers with docker-compose
225+
- Wait for services to initialize (3 second delay)
226+
- Run health checks via curl
227+
- Verify listening ports
228+
- Clean up containers
229+
230+
**Health Check Endpoints:**
231+
- HTTP proxy: `:8080`, `:8081` (proxied services)
232+
- HTTPS with TLS: `:8443`
233+
- Tailscale health: `:9002/healthz`
234+
- Tailscale metrics: `:9002/metrics`
235+
236+
## Common Pitfalls & Notes
237+
238+
1. **File Persistence**: Start9 removes files on reboot - always backup `/home/start9/tailscale`
239+
2. **Hostname Matching**: `TS_HOSTNAME` must match the hostname in Caddyfile
240+
3. **Tailnet Domain**: Must be exact Tailnet name from Tailscale admin console
241+
4. **RELAY_LIST Format**: Strict format `port:host:port` - parsing is fragile
242+
5. **Docker Network**: Use `--net start9` for Start9 deployments
243+
6. **TLS Certificates**: Require HTTPS enabled in Tailscale admin console
244+
7. **Container Execution**: Uses `exec` to replace shell with containerboot (PID 1 handling)
245+
246+
## Version Information
247+
248+
- Current Version: `v0.1.1` (defined in Dockerfile ARG and start.sh)
249+
- Tailscale Base: `v1.92.5` (Dockerfile ARG)
250+
- Alpine Linux with Caddy and socat
251+
252+
## Making Changes
253+
254+
When modifying the project:
255+
256+
1. Update version in both `Dockerfile` ARG and `start.sh`
257+
2. Test with both Python and Bash test scripts
258+
3. Verify all health check endpoints respond
259+
4. Update README.md if user-facing changes
260+
5. Rebuild image before testing: `docker buildx build`
261+
6. Test in isolated network: use compose-test.yml

0 commit comments

Comments
 (0)