Documentation
Everything you need to install, configure, and use YardCtl.
Requirements
- FreeBSD 14.0 or later
- BastilleBSD installed and bootstrapped
- Node.js 22+ (install via
pkg install node22) - Root or
doas/sudoaccess for Bastille commands
Installation
Quick Install
⚠️ Install script coming soon. Join the waitlist for early access.
Manual Install (from source)
# Clone the repo
git clone /usr/local/yardctl # Available to beta testers
cd /usr/local/yardctl
# Install dependencies
npm install
# Copy example env
cp .env.example .env
# Start
npx tsx src/index.ts
Configuration
Configure via environment variables in .env:
# Port to listen on (default: 8080)
PORT=8080
# Privilege elevation command (doas or sudo)
ELEVATION_CMD=doas
# Mock mode — set true for development without Bastille
MOCK_MODE=false
# Comma-separated list of jails to protect from destructive ops
PROTECTED_JAILS=samba,plex,transmission
First Run
On first run with no API keys configured, YardCtl starts in bootstrap mode. All endpoints are accessible without authentication so you can create your first API key:
# Create your first API key
curl -X POST http://localhost:8080/api/keys/init \
-H "Content-Type: application/json" \
-d '{"name": "admin"}'
# Response:
# { "key": "yardctl_abc123...", "name": "admin" }
# ⚠️ Save this key — it's only shown once!
After the first key is created, all endpoints require authentication.
Authentication
Pass your API key via either method:
# Bearer token
curl -H "Authorization: Bearer yardctl_abc123..." \
http://localhost:8080/api/jails
# X-API-Key header
curl -H "X-API-Key: yardctl_abc123..." \
http://localhost:8080/api/jails
Keys are SHA-256 hashed before storage. The plaintext key is only returned at creation time.
Jail Endpoints
List all jails with status, IP, and JID.
Get details for a specific jail.
Create a new jail. Body: {"name", "release", "ip", "config?"}
Start a stopped jail.
Stop a running jail.
Restart a jail.
Destroy a jail. Blocked for protected jails.
Create Jail — Example
curl -X POST http://localhost:8080/api/jails \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "web01",
"release": "15.0-RELEASE",
"ip": "10.0.0.5/24",
"config": {
"boot": true,
"vnet": true,
"allowMlock": true
}
}'
Note: Jail names must be lowercase alphanumeric only (no hyphens or underscores). VNET networking uses the jail name for interface naming. Release names are automatically normalized (e.g., 15.0-RELEASE-p1 → 15.0-RELEASE).
Configuration Endpoints
Get all configuration for a jail.
Get a specific config property.
Set a config property. Body: {"value": "..."}
Mount Endpoints
List mounts for a jail.
Add a mount. Body: {"hostPath", "jailPath", "mode"}
Remove a mount. Body: {"jailPath"}
Network Endpoints
List network interfaces on the host.
Scan for available and used IPs on the jail subnet.
Network status overview.
API Key Endpoints
Bootstrap first API key. Only works when no keys exist.
List API keys (metadata only, no secrets).
Create a new API key.
Revoke an API key.
Protected Jails
Set PROTECTED_JAILS in your .env to prevent destructive operations (stop, destroy) on critical jails:
PROTECTED_JAILS=samba,plex,transmission,piwigo
Attempts to stop or destroy protected jails return a 403 Forbidden with a clear error message.
Running as a Service
YardCtl includes a FreeBSD rc.d script:
# Install the service script
cp scripts/jailapi.rc /usr/local/etc/rc.d/yardctl
chmod +x /usr/local/etc/rc.d/yardctl
# Enable and start
sysrc yardctl_enable="YES"
service yardctl start
# Check status
service yardctl status
# View logs
tail -f /var/log/yardctl.log