Skip to content

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:

  1. Fork the repository on GitHub
  2. Create a server (Debian, meeting the minimum requirements)
  3. Run the bootstrap script to install Docker and dependencies
  4. Configure DNS — point your domain to the server IP
  5. Configure GitHub secrets — add the required secrets to your fork
  6. 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:

sudo ACME_EMAIL=you@example.com OPS_DOMAIN=ops.example.com bash infrastructure/bootstrap-server.sh

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
  • deploy user 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:

bash infrastructure/verify-server.sh

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:

bash /opt/platform/infrastructure/create-app-credentials.sh <app-name>

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:

A record: app.example.com → SERVER_IP

For multiple applications, use subdomains:

uku.example.com   → SERVER_IP
timer.example.com → SERVER_IP

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.