# Docker Gateway & UFW Pitfalls

## Gateway IP Changes on Compose Recreate

Every `docker compose down` + `up -d` with a `networks:` section creates a **new bridge interface** with a different subnet name (`br-<random>`). The old bridge (and its interface-based UFW rules) becomes stale.

Instead of hardcoding the gateway IP in `extra_hosts`, **read it dynamically**:

```bash
# Get gateway IP for current compose network
docker inspect <service-name> \
  --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.Gateway}}{{end}}'
```

Then update compose's `extra_hosts` and UFW rules accordingly.

## UFW Rules: Subnet Over Interface

**Never use bridge-interface-based UFW rules** — they break on every compose recreate:

```bash
# ❌ Brittle — interface changes on every recreate
sudo ufw allow in on br-abcdef123456 to any port 9292 proto tcp

# ✅ Stable — covers the subnet regardless of interface name
sudo ufw allow proto tcp from 172.19.0.0/16 to any port 9292
```

Cover the Docker private ranges Docker might assign (172.17.0.0/16 to 172.31.0.0/16).

## TERMINAL_SERVER_CONNECTIONS Caching

The env var only applies on **first container initialization**. On subsequent restarts, the cached config in the WebUI database takes priority.

**To update an already-cached terminal connection:**

```python
import urllib.request, json

# 1. Get JWT token
req = urllib.request.Request(
    'http://localhost:3081/api/v1/auths/signin',
    json.dumps({'email': 'admin@localhost', 'password': '<password>'}).encode(),
    {'Content-Type': 'application/json'}
)
token = json.loads(urllib.request.urlopen(req).read())['token']

# 2. Update terminal server config
payload = {
    'TERMINAL_SERVER_CONNECTIONS': [{
        'id': 'debian-terminal',
        'name': 'Debian Terminal',
        'url': 'http://host.docker.internal:8000',
        'key': '<api-key>',
        'auth_type': 'bearer',
        'server_type': 'terminal',
        'enabled': True,
    }]
}

req = urllib.request.Request(
    'http://localhost:3081/api/v1/configs/terminal_servers',
    json.dumps(payload).encode(),
    {'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
```

## Verify Terminal Hosts

The user-facing terminal server list is at `GET /api/v1/terminals/` (returns id, url, name). If using `host.docker.internal` for the URL, verify resolution from inside the container:

```bash
docker exec open-webui getent hosts host.docker.internal
# → 172.19.0.1      host.docker.internal  (or whatever the current gateway is)
```
