Feature: Subscription Aggregation Service | Date: 2026-03-29
This guide helps you get started with SubHub - a subscription aggregation service for Clash/mihomo proxies.
- Docker installed (or Python 3.12+ and uv for local development)
- One or more airport subscription URLs
- A Clash/mihomo template file (optional, a default is provided)
-
Clone the repository:
git clone <repository-url> cd subhub
-
Configure your subscriptions: Edit
config/config.yaml:sources: - id: "a1b2c3d4e5f6789abcdef123" # Generate with: openssl rand -hex 12 name: "my-airport" url: "https://your-airport.com/sub" enabled: true cache_expiry: 7200 # 2 hours template_path: "config/template.yaml" cache_dir: "cache" listen_port: 8080 listen_host: "0.0.0.0"
-
Run the container:
docker run -d \ -p 8080:8080 \ -v $(pwd)/config:/app/config \ -v $(pwd)/cache:/app/cache \ --name subhub \ subhub:latest
-
Install dependencies with uv:
uv sync
-
Run the service:
uv run python -m src.main
Test the service is running:
curl http://localhost:8080/healthExpected response:
{"status": "healthy", "version": "1.0.0", "uptime_seconds": 10}# Replace with your source ID from config.yaml
curl http://localhost:8080/subscription/a1b2c3d4e5f6789abcdef123 -o clash.yamlcurl http://localhost:8080/subscription/a1b2c3d4e5f6789abcdef123?refresh=true -o clash.yamlcurl http://localhost:8080/sources-
Download the subscription:
curl http://localhost:8080/subscription/a1b2c3d4e5f6789abcdef123 -o clash-config.yaml
-
Import into Clash/mihomo client
Add to your Clash config:
proxy-providers:
subhub:
type: http
url: "http://localhost:8080/subscription/a1b2c3d4e5f6789abcdef123"
interval: 7200
path: ./proxies.yaml
health-check:
enable: true
interval: 600
url: http://www.gstatic.com/generate_204List of subscription sources to aggregate.
sources:
- id: "a1b2c3d4e5f6789abcdef123" # Unique ID (generate: openssl rand -hex 12)
name: "airport1" # Display name (non-unique)
url: "https://..." # Subscription URL
enabled: true # Whether to fetch from this source
cache_expiry: 7200 # Cache TTL in seconds (default: 7200)Path to your Clash template YAML file. The template should contain:
proxy-groups: Your proxy group definitionsrules: Your routing rulesproxies: Empty list (will be filled by the service)
Directory for caching subscription content. Ensure this directory is writable.
# config/template.yaml
proxy-groups:
- name: "PROXY"
type: select
proxies:
- DIRECT
# Injected proxies will be appended here
- name: "Auto"
type: url-test
proxies:
- PROXY
url: "http://www.gstatic.com/generate_204"
interval: 300
rules:
- DOMAIN-SUFFIX,google.com,PROXY
- DOMAIN-SUFFIX,youtube.com,PROXY
- GEOIP,CN,DIRECT
- MATCH,PROXY
proxies: [] # This will be replaced with actual proxies- Check if port 8080 is already in use
- Verify config.yaml syntax is valid
- Check cache directory is writable
- Check source status:
curl http://localhost:8080/sources - Verify airport URLs are accessible
- Check service logs for errors
- Ensure cache_dir exists and is writable
- Check file permissions on cache directory
- Force refresh with
?refresh=true
version: '3.8'
services:
subhub:
image: subhub:latest
ports:
- "8080:8080"
volumes:
- ./config:/app/config:ro
- ./cache:/app/cache
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3server {
listen 443 ssl;
server_name subhub.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}- See HTTP API Contract for full API documentation
- See Data Model for entity definitions