Implement Caddy API integration

t-266.7·WorkTask·
·
·
·Omni/Deploy.hs
Parent:t-266·Created2 months ago·Updated2 months ago

Dependencies

Description

Edit

Create Caddy API integration for dynamic reverse proxy routes.

Files to Create

  • Omni/Deploy/Caddy.py - Caddy admin API client

Caddy Admin API

Caddy exposes admin API at localhost:2019 by default.

Implementation

import requests as Requests
import json as Json

CADDY_ADMIN = "http://localhost:2019"

def build_route(service: Service) -> dict:
    """Build Caddy route config for a service."""
    if not service.http:
        return None
    
    return {
        "@id": f"biz-{service.name}",
        "match": [{"host": [service.http.domain]}],
        "handle": [{
            "handler": "reverse_proxy",
            "upstreams": [{"dial": f"localhost:{service.http.internalPort}"}]
        }]
    }

def get_current_routes() -> list:
    """Get current Caddy routes."""
    resp = Requests.get(f"{CADDY_ADMIN}/config/apps/http/servers/srv0/routes")
    return resp.json() if resp.ok else []

def upsert_route(service: Service):
    """Add or update route for service."""
    route = build_route(service)
    if not route:
        return
    
    route_id = f"biz-{service.name}"
    
    # Try to update existing
    resp = Requests.patch(
        f"{CADDY_ADMIN}/id/{route_id}",
        json=route,
        headers={"Content-Type": "application/json"}
    )
    
    if not resp.ok:
        # Add new route
        Requests.post(
            f"{CADDY_ADMIN}/config/apps/http/servers/srv0/routes",
            json=route,
            headers={"Content-Type": "application/json"}
        )

def delete_route(service_name: str):
    """Remove route for service."""
    Requests.delete(f"{CADDY_ADMIN}/id/biz-{service_name}")

def sync_routes(services: list[Service]):
    """Sync all routes from manifest."""
    for service in services:
        if service.http:
            upsert_route(service)

Caddy Base Config (managed by NixOS)

{
    admin localhost:2019
}

HTTPS/ACME

Caddy handles HTTPS automatically when domain is specified. No additional config needed.

Testing

bild --test Omni/Deploy/Caddy.py

Dependencies

  • requests (already in Python deps)

Timeline (2)

🔄[human]Open → InProgress2 months ago
🔄[human]InProgress → Done2 months ago