---
title: "Orrery Studio Part 6: Self-Hosting AI Agents with Docker Compose"
url: "https://tirraflow.com/posts/orrery-studio-part-6-self-hosting-ai-agents-with-docker-compose"
author: "taoufiq"
published: "2026-10-25T13:05:49Z"
updated: "2026-10-25T13:04:49Z"
category: "AI Agents"
difficulty: "advanced"
series: "Orrery Studio"
series_part: 6
series_url: "https://tirraflow.com/series/orrery-studio"
tags: ["Docker", "Agents", "Security"]
---

# Orrery Studio Part 6: Self-Hosting AI Agents with Docker Compose

> **Status, October 2026:** the Studio runs in the Tirraflow lab for admins only, on Orrery 0.10.0. One security question below is still open, and it's described as such.

Self-hosting Orrery Studio, with a remote A2A agent and an MCP egress proxy, took four new pieces in a Docker Compose file: a demo A2A agent, a one-shot job that makes its TLS certificates, an egress proxy rule and two nginx routes. This part shows the setup on Tirraflow's single VPS, and the five problems found in its first day: one hit production, four were caught in review.

---

## The Setup

![Orrery Studio deployment on one VPS with Docker Compose: nginx in front, Orrery and the demo A2A writer on internal networks, a one-shot certificate job, and a squid egress proxy as the only way out to two hosts](https://tirraflow.com/uploads/c12d074d-24ec-4712-8772-3c6238902c3e.png)

- **Orrery** sits on internal-only Docker networks with no route out. The Studio is turned on with one variable, which Orrery refuses unless human clients are listed too.
- **The demo writer** is the plain A2A agent from [Part 3](https://tirraflow.com/posts/orrery-studio-part-3-how-the-a2a-protocol-works-from-agent-cards-to-tasks), on the same internal network under the name `demo-writer.studio.internal`. Orrery reaches it directly, because that one host is allowlisted.
- **The certificate job** runs with no network at all, makes a throwaway CA and the writer's certificate, then discards the CA key. Orrery mounts only the CA certificate; the writer's key never leaves the writer's volume.
- **The egress proxy** is squid, allowing `CONNECT` to exactly two hosts on port 443.

```yaml
orrery:
  environment:
    ORRERY_STUDIO_ENABLED: "true"
    ORRERY_STUDIO_REGISTRY: /studio/registry.yaml
    ORRERY_STUDIO_EGRESS_PROXY: http://lab-egress:3128
    ORRERY_A2A_PRIVATE_ALLOW: demo-writer.studio.internal
    ORRERY_A2A_CA_FILE: /ca/ca.pem
  volumes:
    - ./labs/orrery/studio-registry.yaml:/studio/registry.yaml:ro
    - studio-demo-ca:/ca:ro     # the CA certificate only
```

The demo writer and the certificate job ship inside the signed Orrery image, so the Studio's demo pieces run only released, signature-verified code.

---

## Five Problems From the First Day

### 1. The writer was killed before it could listen (production)

The writer has no LLM, so 128 MiB of memory seemed plenty. It went into an out-of-memory loop: importing the a2a-sdk and uvicorn stack takes about 137 MiB steady and 147 MiB at peak. The limit is now 256 MiB, with the measurement written next to it. Measure, then set the limit.

### 2. A certificate renewal could stop half-way (review)

The job runs as root only to write into the volumes and hand files to the image's user. With just the `CHOWN` capability, the first run worked, but a _renewal_ would write a new `ca.pem`, then fail to open the writer's existing certificate. That leaves a new CA beside an old certificate, and the lab stays broken until someone deletes the volumes. It now also gets `DAC_OVERRIDE` and `FOWNER`, the Linux capabilities to open and change files it doesn't own, and still nothing else.

### 3. Both sides read certificates only at start (review)

Orrery loads the CA once, and the writer loads its certificate once. A renewal that restarts only one of them pairs a new CA with an old certificate. So the lab's deploy job watches the certificate job's output, and when it says `regenerating`, it restarts the writer and Orrery _together_.

```bash
if compose logs --no-log-prefix --since "$STARTED" lab-studio-certs | grep -q '^regenerating'; then
  compose restart lab-studio-writer orrery
fi
```

### 4. A 30-day certificate nobody would renew (review)

The job's default was 30 days, renewed when a week is left. But it only runs on a lab deploy, and nothing schedules one. The lab would have broken quietly a month later. Since this CA is trusted by one Orrery and nothing else, the certificates now last 825 days.

### 5. nginx would buffer anyone's upload (review)

A composition can be bigger than the lab's usual 64 KB limit, so `/studio/` needed a larger one. But a buffering nginx reads the whole body _before_ Orrery can reject an unauthenticated caller, so anyone could make it hold that much memory at a time. The body is now streamed straight through, with a 1 MB cap. The live trace gets its own route with buffering off and a 10-minute timeout.

```nginx
location /studio/ {
    client_max_body_size    1m;
    proxy_request_buffering off;   # Orrery refuses strangers before the body is read
}
```

---

## Still Open: The Proxy Checks Names, Not SNI

Squid allows a `CONNECT` by the hostname in the request, and the `-n` flag stops it from reverse-resolving bare IP addresses. But it can't see the SNI, the hostname sent inside the TLS handshake. `tirraflow.com` sits behind Cloudflare's shared addresses, so code inside Orrery that set its own SNI could reach any Cloudflare-fronted site through that tunnel.

Orrery's own clients send the real hostname, so this needs hostile code already running in the container. Closing it fully means a squid build that can peek at the SNI, or a route to the blog's origin that never leaves the box. That decision is still open, and the squid config says so in a comment.

---

## Where This Leaves the Studio

- **Live:** admins can build and run compositions with Tirraflow's MCP server and the demo A2A agent, on Claude Haiku 5.5, within the lab's daily token budget.
- **Not yet:** readers can't use it. Opening it means one isolated runner per learner, which is phase P3.
- **Next:** human approval steps, remotes that act after a person confirms, and editing the registry from the console.

To try the parts that are public today, connect your own assistant to `https://tirraflow.com/mcp`, the same MCP server the Studio's research node uses. Then start the series again from [Part 1](https://tirraflow.com/posts/orrery-studio-part-1-a-visual-builder-for-multi-agent-ai-systems), or browse the [hands-on labs](https://tirraflow.com/labs).
