Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion deploy/model-server/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The public name of this machine. Point a DNS A record at it before `up`.
# Only for the bundled Caddy (`docker compose --profile caddy up -d`). With your own
# nginx, the name goes in its server block instead (README.md).
MODEL_SERVER_DOMAIN=models.example.com

# Shared with the gateway (AGENTFOX_MODEL_SERVER_TOKEN there too).
Expand Down
46 changes: 44 additions & 2 deletions deploy/model-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,57 @@ Then, on the instance:
# (Amazon Linux 2023: sudo dnf install -y docker && sudo systemctl enable --now docker)
sudo usermod -aG docker $USER && newgrp docker # run docker without sudo
git clone https://github.com/architsharm/agentfox && cd agentfox/deploy/model-server
cp .env.example .env # set MODEL_SERVER_DOMAIN and AGENTFOX_MODEL_SERVER_TOKEN
cp .env.example .env # set AGENTFOX_MODEL_SERVER_TOKEN
docker compose pull && docker compose up -d
docker compose logs -f models # ready once each model logs "warm in …"
curl -H "Authorization: Bearer $TOKEN" https://$MODEL_SERVER_DOMAIN/health
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8090/health
```

Generate the token on the machine and paste it only into `.env` and the gateway's
settings. Not into chat, tickets or shell history you share.

The server listens on `127.0.0.1:8090` only. Give it HTTPS and a name in one of two
ways.

**Behind the machine's nginx** (it already serves other sites on 80/443). Pick a
name, point a DNS `A` record at the machine, then add a server block:

```nginx
# /etc/nginx/sites-available/agentfox-models
upstream agentfox_models {
server 127.0.0.1:8090;
keepalive 16; # the gateway reuses connections; so should nginx
}

server {
listen 80;
server_name models.example.com;

location / {
proxy_pass http://agentfox_models;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_read_timeout 30s;
client_max_body_size 1m;
}
}
```

```bash
sudo ln -s /etc/nginx/sites-available/agentfox-models /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d models.example.com # adds the 443 block and renews it
curl -H "Authorization: Bearer $TOKEN" https://models.example.com/health
```

**On a machine with nothing on 80/443**, use the bundled Caddy instead. Set
`MODEL_SERVER_DOMAIN` in `.env`, then run `docker compose --profile caddy up -d`.

The name can be a subdomain of any domain you control. Only the gateway ever calls
it. A domain whose site is hosted elsewhere (on Vercel, say) still works: add an `A`
record for the subdomain in that domain's DNS, pointing at this machine.

`/health` lists each detector, whether it can run, and the device it runs on.

Then point the gateway at it. On Vercel, these are project environment variables:
Expand Down
23 changes: 16 additions & 7 deletions deploy/model-server/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# The model server on one machine (an EC2 instance, say), behind automatic HTTPS.
# The model server on one machine (an EC2 instance, say).
#
# cp .env.example .env # set the domain and the token
# cp .env.example .env # set the token
# docker compose up -d
#
# It listens on 127.0.0.1:8090 only. Put HTTPS in front of it with:
# * the reverse proxy the machine already runs (nginx, say; README.md has the
# server block), or
# * on a machine with nothing on ports 80/443, the bundled Caddy, which gets a
# certificate on its own: docker compose --profile caddy up -d
#
# Updating is a pull, and only when a model-side change ships: the gateway keeps
# deploying from main as often as it likes without touching this machine.
#
Expand All @@ -23,8 +29,9 @@ services:
AGENTFOX_MODEL_DEVICE: ${AGENTFOX_MODEL_DEVICE:-auto}
# Weights are read from the image only, never fetched while serving.
HF_HUB_OFFLINE: "1"
# Not published to the host: only Caddy reaches it.
expose: ["8090"]
# Loopback only: the host's reverse proxy (or the bundled Caddy) reaches it; the
# internet does not.
ports: ["127.0.0.1:8090:8090"]
healthcheck:
test: ["CMD", "python", "-c", "import os,urllib.request as u; u.urlopen(u.Request('http://127.0.0.1:8090/health', headers={'Authorization': 'Bearer ' + os.environ['AGENTFOX_MODEL_SERVER_TOKEN']}), timeout=5)"]
interval: 30s
Expand All @@ -34,12 +41,14 @@ services:
start_period: 120s

caddy:
# TLS from Let's Encrypt for MODEL_SERVER_DOMAIN, renewed automatically. The
# gateway sends the text it screens here, so it travels encrypted.
# Only with `--profile caddy`, for a machine with no reverse proxy of its own: it
# takes ports 80 and 443. TLS from Let's Encrypt for MODEL_SERVER_DOMAIN, renewed
# automatically. The gateway sends the text it screens here, so it travels encrypted.
profiles: ["caddy"]
image: caddy:2.8
restart: unless-stopped
ports: ["80:80", "443:443"]
command: ["caddy", "reverse-proxy", "--from", "${MODEL_SERVER_DOMAIN:?set MODEL_SERVER_DOMAIN in .env}", "--to", "models:8090"]
command: ["caddy", "reverse-proxy", "--from", "${MODEL_SERVER_DOMAIN:-set-MODEL_SERVER_DOMAIN-in-.env}", "--to", "models:8090"]
volumes:
- caddy-data:/data
depends_on: [models]
Expand Down
Loading