February 2, 2026 · Feature
Building Docker Compose for FreeBSD Jails
One of the goals for Lochs is Docker Compose-style multi-container orchestration. The concept: define multiple jails, their dependencies, networks, and volumes in a single YAML file, and bring them all up with one command.
The Format: prison.yml
We chose YAML for configuration (matching Docker Compose conventions) and kept the structure familiar:
version: "1"
services:
web:
build: ./web
ports:
- "8080:80"
depends_on:
- db
environment:
- DATABASE_URL=postgresql://db:5432/myapp
networks:
- frontend
- backend
db:
image: freebsd:15
command: /usr/local/bin/pg_ctl start -D /var/db/postgres/data15
volumes:
- pgdata:/var/db/postgres/data15
networks:
- backend
networks:
frontend:
subnet: 10.0.1.0/24
backend:
subnet: 10.0.2.0/24
volumes:
pgdata:
Dependency Resolution
The depends_on field creates a directed acyclic graph of jail startup order. We implemented topological sorting to determine the correct order: jails with no dependencies start first, and jails that depend on others wait until their dependencies are running.
Circular dependencies are detected at parse time and reported as errors rather than causing deadlocks.
Network Creation
Named networks in prison.yml map to Linux bridge interfaces. Each network gets its own bridge with the specified subnet. Jails attached to a network get a veth pair connected to that bridge. A jail can be on multiple networks simultaneously (like the web service above on both frontend and backend).
Port Forwarding
Port forwarding uses socat to map host ports to jail ports. When you specify -p 8080:80, Lochs spawns a socat process that listens on the host's port 8080 and forwards traffic to the jail's IP on port 80. This is simpler than iptables-based forwarding and works reliably across different Linux distributions.
Cleanup
lochs compose down tears everything down in reverse dependency order: stop jails that depend on others first, then stop the dependencies, then remove networks. This prevents orphaned processes and dangling network interfaces.
Current Status
The YAML parser, dependency resolver, and network creation are implemented. Port forwarding via socat works. The compose lifecycle (up/down/ps) is functional. What's still in progress: build directive support (building from Prisonfiles within compose), volume driver abstraction, and health checks.