Production-ready FreeBSD jail deployments with Ansible
jail-forge is a curated collection of battle-tested deployment configurations for self-hosted applications on FreeBSD using jails and Ansible. Each application is fully configured with deployment automation, backup/restore capabilities, and disaster recovery procedures.
- Infrastructure as Code: Complete infrastructure reproducible from code
- Service Isolation: Each service runs in its own FreeBSD jail
- Flexible Networking: Support for alias, NAT, VNET, and inherit networking modes
- Production Ready: Tested deployment patterns with proper error handling
- Complete Lifecycle: Deploy, backup, restore, snapshot, and destroy operations
- BSD Conventions: Follows FreeBSD standards for paths and services
- Shared Resources: Reusable roles and patterns across all applications
Ansible automation and deployment platform with PostgreSQL backend.
- Status: ✅ Production Ready
- Services: Semaphore 2.16.37, PostgreSQL 15
- Jails: 2 (app + database)
- Features: TLS support, custom CA import, backup/restore, disaster recovery
jail-forge/
├── README.md # This file
├── CONTRIBUTING.md # How to contribute
├── LICENSE # BSD 2-Clause License
├── .github/workflows/ # CI/CD testing
├── shared/roles/jail-base/ # Base jail role (reusable)
├── semaphore/ # Semaphore deployment
│ ├── README.md
│ ├── Makefile
│ ├── playbooks/
│ ├── inventory/
│ └── group_vars/
└── <your-app>/ # Your application here
Browse the available applications above and cd into its directory:
cd semaphore/Each application has its own configuration. See the application's README for specific setup instructions.
# Copy example configuration files
cp inventory/hosts.yml.example inventory/hosts.yml
cp group_vars/all/secrets.yml.example group_vars/all/secrets.yml
# Edit with your values
vim inventory/hosts.yml
vim group_vars/all/secrets.yml# Check connectivity
make check
# Deploy full stack
make deployAll infrastructure is defined in code and can be rebuilt from scratch at any time. Backups contain only data, not configuration.
Each service runs in its own FreeBSD jail for security and maintainability. Multi-tier applications use separate jails (e.g., database jail + app jail).
jail-forge supports four networking modes for jails, each with different trade-offs:
| Mode | Complexity | Use Case | Network Stack | Internet Access |
|---|---|---|---|---|
| Alias | Simple | LAN deployment with available IPs | Shared with host | Direct (via LAN) |
| NAT | Moderate | Single public IP, port forwarding | Shared with host | Via host NAT |
| VNET | Advanced | Full isolation, multi-tenant, custom routing | Isolated per jail | Via bridge + NAT |
| Inherit | Simple | Nested jails (jail inside a jail) | Inherited from parent | Via parent jail |
When to use each mode:
-
Alias Mode (Default): Choose this for simple deployments where you have multiple IPs available on your LAN. Jails get static IP addresses on the host's network interface. This is the simplest and most straightforward option for home labs and small deployments.
-
NAT Mode: Choose this when you have a single public IP and need to expose services via port forwarding (e.g., 8080:80). The host performs NAT translation. Good for VPS deployments or environments with limited IPs.
-
VNET Mode: Choose this for maximum isolation and advanced networking requirements. Each jail gets its own complete network stack, enabling per-jail firewalls, custom routing tables, and true network isolation. Essential for multi-tenant environments or when jails need to run their own network services (VPN, routing, etc.).
-
Inherit Mode: Choose this when deploying inside an existing jail (nested jails). Child jails inherit the parent jail's network stack — no pf, interface creation, or IP assignment needed. Services communicate via localhost on different ports. Requires the parent jail to have
children.max,allow.mount.*, and a delegated ZFS dataset.
- Paths:
/var/backups,/var/log,/usr/local/etc - Services: rc.d scripts, newsyslog for log rotation
- Networking: Static IPs, PF for firewall (optional)
Every deployment includes:
- ✅ Automated deployment
- ✅ Backup with retention policies
- ✅ Restore procedures
- ✅ ZFS snapshots for quick rollback
- ✅ Disaster recovery (full rebuild + restore)
- ✅ Clean destroy operations
Adding a new application follows this pattern:
mkdir -p myapp/{playbooks,inventory,group_vars/all,roles,scripts}# From an existing app like semaphore
cp -r semaphore/inventory/hosts.yml.example myapp/inventory/
cp -r semaphore/group_vars/all/secrets.yml.template myapp/group_vars/all/
cp semaphore/{ansible.cfg,Makefile} myapp/Each app needs these playbooks in playbooks/:
prepare-host.yml- Create ZFS datasets, install jail-forgedeploy-db.yml- Setup database jail (PostgreSQL/MySQL/etc)deploy-app.yml- Setup application jail and softwarebackup.yml- Backup data directoriesrestore.yml- Restore from backupdestroy-all.yml- Clean teardown
Use semaphore as a reference implementation.
Add your app to .github/workflows/test-lifecycle.yml:
APPS_JSON: |
[
{ "name": "semaphore", ... },
{
"name": "myapp",
"working_dir": "myapp",
"jail_name": "myapp-app",
"port": 8080,
"health_endpoint": "/health",
"service_name": "myapp",
"backup_location": "/var/backups/myapp"
}
]cd myapp
make deploy # Deploy full stack
make backup # Test backup
make restore # Test restoreThat's it. Keep it simple.
- OS: FreeBSD 13.0+ (tested on 13.5-RELEASE)
- Filesystem: ZFS
- Software: Ansible 2.9+, Python 3.8+
- Network: Available IP addresses for jail assignment
Contributions are welcome! See CONTRIBUTING.md for guidelines on:
- Adding new applications
- Improving existing deployments
- Documentation improvements
- Bug fixes and enhancements
The following applications are planned or in development:
- Nextcloud - Self-hosted file sync and sharing
- Gitea - Lightweight Git server
- Authentik - Identity provider (SSO)
- Miniflux - Minimalist RSS reader
- Vaultwarden - Bitwarden-compatible password manager
- MinIO - Object storage server
- Traefik - Reverse proxy and load balancer
Want to contribute a deployment? Fork the repo and submit a PR!
GitHub Actions tests the full lifecycle automatically. See .github/TESTING.md for CI/CD setup.
jail-forge is licensed under the BSD 2-Clause License. See LICENSE for details.
Individual applications deployed by jail-forge retain their own licenses.
Gabriel Belli
- Issues: Open an issue on the repository
- Discussions: For questions and community discussion
This project builds upon:
- The excellent FreeBSD jails system
- The Ansible automation platform
- The BSD community's commitment to quality and simplicity
If you find jail-forge useful, please consider starring the repository!