Container Isolation on ZopCloud: One Network Per App
A shared VM is only fair if each tenant behaves as though it were alone on it. Apps on ZopCloud shared VMs now each run on their own network, so one tenant’s app cannot reach another’s. Outbound traffic is capped at 10 Mbit per second per app, a request larger than 5 MB is refused with a 413, and a custom domain is accepted only once its DNS points at the space.
Existing apps move onto their own network on their next deploy. Separately, new Azure PostgreSQL servers created by ZopDay keep requiring TLS.
A Network Per App Makes Isolation a Property of the Host
On a shared VM, apps that run on the default Docker network share one address space. Isolation there depends on every app behaving. Now each tenant’s container runs on a Docker network created for that one service, and removed when the service is torn down.
A container with no route to another tenant’s network cannot reach it by mistake or on purpose. That is a stronger guarantee than a rule asking apps not to try. Two exceptions are named. Existing containers stay on the default network until their next deploy that changes the app itself, since a configuration-only change does not recreate them. And the pool owner’s own services stay on the default network.
A Cap That Survives a Restart
Each app’s network bridge carries a 10 Mbit per second cap on outbound traffic, applied with the Linux traffic controller. A cap set once at start is lost whenever docker restarts, so a guard re-applies it every time docker starts, and teardown removes the network along with its cap.
This works when the guard runs after docker is up. The release notes ask operators to re-run the docker component on each pool VM after deploy for exactly that reason: a VM that restarted docker before the guard existed would otherwise have no cap until its next restart.
Five Megabytes and a DNS Check
Two more limits sit at the edge, in Caddy and on the server side.
| Limit | Value | What the caller sees |
|---|---|---|
| Request body size | 5 MB | 413 for anything larger |
| Custom domain | DNS must resolve to the space’s public address | 422 until it does |
| Outbound traffic | 10 Mbit per second per app | Slower transfers, no error |
The domain check runs when a domain is created, when configuration is updated and when a host is added. Managed hosts and hosts that were already bound are exempt, so existing apps keep working. Binding only a name whose DNS already points at the space stops a space from serving a name that its tenant does not control.
A Toolchain Pinned by Hash
This release also pins what gets installed on the VM. The Docker install script is fetched from a pinned commit and checked against a sha256 at a fixed Docker version. The Caddy tarball is checked against its sha512. Component images are pulled by digest rather than by a tag that can be moved.
Each pin answers the same question: if the thing at that address changed tomorrow, would a new VM install it? With a hash or a digest, the answer is no, and the install fails instead.
Database TLS Stays On
The provisioner now leaves require_secure_transport switched on for new Azure PostgreSQL servers. It switches the requirement off only for Azure MySQL. A new PostgreSQL database therefore starts out requiring encrypted connections, rather than needing someone to turn that on afterward.
