---
name: treehouse-networking
description: Treehouse networking — Caddy routing, TLS, public domains, tenant app exposure, container network isolation. Use for tasks involving Caddy config, custom domains, TLS certificates, or network security.
allowed-tools: Bash(ssh:*), Bash(sudo:*), Read, Write, Edit
---

# Treehouse Networking

SSH: `ssh treehouse-host '<command>'`

## Domain & Routing

- **Domain:** `devitltd.uk` (Cloudflare DNS, wildcard A record → 89.167.99.240)
- **Tenant dashboards:** `{tenant}.devitltd.uk` (HTTP basic auth)
- **Tenant apps:** `{app}.{tenant}.devitltd.uk` (public by default, optional basic auth)
- **MC admin:** `mission.null:80` (Tailscale-only)
- **TLS:** Per-subdomain Let's Encrypt via HTTP challenge (no wildcard cert)

## Caddy Config

- **System config:** `/etc/nixos/caddy-local.nix` — `mission.null:80` + import of tenant files
- **Per-tenant Caddyfiles:** `/etc/caddy/tenants/{tenant}.caddy` — dashboard reverse_proxy block + app entries
- When `ipc.ts` regenerates a Caddyfile for app changes, it always prepends the dashboard block
- Provisioning (`writeTenantCaddyfile()` in MC) creates the initial Caddyfile

```bash
# Lint and reload Caddy
treehouse caddy lint
treehouse caddy reload

# Direct
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
```

## Container Network Isolation

### Agent containers (host Docker, docker0 bridge)

- An iptables rule (`-I INPUT -i docker0 -j DROP`) blocks all container→host traffic via the bridge gateway
- Containers can still reach the internet; they cannot probe host-bound ports or other tenants
- Rule applied declaratively via `networking.firewall.extraCommands` in `configuration.nix`
- Non-admin agent containers run under Docker `runsc` (gVisor); admin uses normal runtime
- Each agent container attaches to tenant-private network `nanoclaw-tenant-<tenant>`
- No Docker socket, no `--privileged`, no extra capabilities

### Tenant apps (rootless nerdctl, slirp4netns)

- `--disable-host-loopback` is set in the rootlesskit invocation — host loopback unreachable from app containers
- No additional iptables rules needed for this path

### What this prevents

A tenant running arbitrary code cannot connect to another tenant's database, internal API, or any host-bound service via the bridge/gateway IP.

### Residual notes

- `mission.null` was reachable from a tenant sandbox via the host Tailscale IP + `Host: mission.null` header — treat network-layer blocking as the correct long-term boundary, not DNS-based
- CPU count from `nproc` is still host-visible inside gVisor sandboxes (accepted limitation)

## Tenant Deletion — Network Cleanup

On tenant deletion, remove:
- The tenant Caddyfile: `/etc/caddy/tenants/<tenant>.caddy`
- Caddy reload after removal
- Any allocated port range entries in the DB

```bash
treehouse caddy reload
```
