Self-Hosting
Fork-Based Deployment Model
Every application in the Towlion ecosystem is designed to be forkable and self-deployable. Instead of multi-tenant SaaS, the platform uses repository forks as the isolation boundary.
User forks repository
↓
Configure deployment secrets
↓
Push code
↓
GitHub Actions deploys app
↓
Application runs on user's server
Each fork runs independently — there is no shared tenancy or centralized hosting.
original repo
│
├─ fork by Alice → alice.example.com
├─ fork by Bob → bob.example.com
└─ fork by Carol → carol.example.com
Benefits:
- Strong isolation between deployments
- Simple architecture (no tenant management)
- Full control for each operator
Server Requirements
| Resource | Minimum |
|---|---|
| CPU | 2 cores |
| RAM | 4 GB |
| Disk | 50 GB |
| Data disk | Mounted at /data |
Required ports:
| Port | Purpose |
|---|---|
| 22 | SSH |
| 80 | HTTP |
| 443 | HTTPS |
Required Secrets
Fork users must configure these GitHub Actions secrets:
| Secret | Purpose |
|---|---|
SERVER_HOST |
Server IP address |
SERVER_USER |
SSH user (typically deploy) |
SERVER_SSH_KEY |
SSH private key for deployment |
APP_DOMAIN |
Application domain name (e.g., app.example.com) |
Note: Database and storage credentials are auto-generated by the bootstrap script on the server. They are not GitHub secrets.
Optional secrets:
| Secret | Purpose |
|---|---|
PREVIEW_DOMAIN |
Base domain for preview environments (e.g., example.com) |
Tip: To reduce the number of required secrets from 4 to 1, you can use a self-hosted GitHub Actions runner instead. See Self-Hosted Runners.
Bootstrap Process
To deploy an application from a fork:
- Fork the repository on GitHub
- Create a server (Debian, meeting the minimum requirements)
- Run the bootstrap script to install Docker and dependencies
- Configure DNS — point your domain to the server IP
- Configure GitHub secrets — add the required secrets to your fork
- Push code — deployment runs automatically via GitHub Actions
Bootstrap Script
The repository includes a single bootstrap script that transforms a fresh Debian server into a ready-to-deploy platform:
The script is idempotent — safe to re-run on an already-bootstrapped server. It performs:
- System packages (git, curl, ufw, vnstat, unattended-upgrades)
- Firewall configuration (ports 22, 80, 443)
- Docker and Compose plugin installation
deployuser creation with SSH directory- Directory structure (
/data/*,/opt/apps,/opt/platform) - Docker network (
towlion) for cross-container communication - Credential generation (PostgreSQL, MinIO, and Grafana passwords in
/opt/platform/.env) - Platform Caddyfile with per-app import pattern
- Platform
docker-compose.yml(PostgreSQL 16, Redis 7, MinIO, Caddy 2, Loki 3.0, Promtail 3.0, Grafana 11.0) - Service startup and verification
- Infrastructure scripts and cron jobs (backups, alerts, image updates)
Post-Bootstrap Verification
After bootstrapping, run the verification script to confirm everything is working:
This performs a read-only check of all services, directories, and firewall rules.
Per-App Credentials
For each application, provision isolated database and storage credentials:
This creates a dedicated PostgreSQL user and MinIO bucket. Credentials are written to /opt/platform/credentials/<app-name>.env and automatically picked up by the deploy workflow.
Monitoring (Optional)
If you set OPS_DOMAIN during bootstrap (or add it to /opt/platform/.env), Grafana is accessible at https://OPS_DOMAIN. The default admin credentials are in /opt/platform/.env. Configure DNS for the ops domain the same way as app domains.
DNS Configuration
Point your domain (or subdomain) to your server's IP address:
For multiple applications, use subdomains:
Caddy handles TLS certificate provisioning automatically once DNS is configured.
What You Get
After deployment, your server runs:
- Your application (FastAPI backend + Next.js frontend)
- PostgreSQL database
- Redis cache and queue
- MinIO object storage
- Caddy reverse proxy with automatic TLS
- Celery background workers
All managed through GitHub — push code to deploy updates.
For the full directory layout, lifecycle sequence, and workflow assumptions, see Server Contract.