Self-Hosted PaaS with True Multi-Tenancy
One VPS. Many Clients. Full Isolation.
Installation Β· Features Β· Deployment Guide Β· API Reference Β· Architecture
Orbita is an open-source, self-hosted Platform-as-a-Service (PaaS) built in Go, designed for developers, freelancers, and agencies who manage infrastructure for multiple clients on a single server.
Turn a single VPS into a fully isolated hosting environment for multiple client organizations β each with their own dashboard, projects, environment variables, secrets, logs, domains, and resource quotas. Clients never see each other. You, as the super-admin, see everything.
Ships as a single ~30MB binary with an embedded React SPA. Uses under 50MB of RAM at idle.
| Problem | Orbita's Solution |
|---|---|
| Dokploy/Coolify lack multi-tenancy | True tenant isolation: separate networks, secrets, volumes, quotas |
| No working invite/RBAC system | 4-role RBAC (Owner/Admin/Developer/Viewer) with email invites |
| High memory overhead (PHP/Node.js) | Go binary β under 50MB idle RAM |
| No resource quotas per client | cgroup v2 slices enforce CPU/memory limits per org |
| No cron job management | Built-in cron scheduler with run history and concurrency policies |
| Vendor lock-in with managed PaaS | 100% self-hosted, no per-seat fees, you own everything |
| Feature | Orbita | Dokploy | Coolify |
|---|---|---|---|
| Multi-tenancy | β | β | β |
| Resource quotas (cgroups) | β | β | β |
| Working invite system | β | β | Partial |
| RBAC (4 roles) | β | β | β |
| Cron job manager | β | β | β |
| Single binary deploy | β | β | β |
| Idle memory usage | <50MB | ~200MB | ~500MB |
| Written in | Go | Node.js | PHP/Laravel |
Before installing Orbita, ensure your server meets these requirements:
| Requirement | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2+ vCPU |
| RAM | 1 GB | 4 GB |
| Disk | 10 GB | 30+ GB |
| OS | Ubuntu 22.04, Debian 12, Fedora 38+, CentOS 9 | Ubuntu 24.04 |
| Architecture | 64-bit (AMD64 or ARM64) | β |
| Ports | 80, 443, 8080 open | β |
Important: It's recommended to use a fresh server. If you already have Docker or other services running on ports 80/443, you'll need to configure them to avoid conflicts.
Run a single command to install Orbita on your server:
curl -sSL https://raw.githubusercontent.com/MUKE-coder/orbita/main/install.sh | sudo bashThis script will:
- Install Docker (if not already installed)
- Initialize Docker Swarm mode
- Generate secure secrets automatically
- Ask for your domain and email
- Create
docker-compose.ymland.envfiles - Start all services (Orbita + PostgreSQL + Redis + Traefik)
- Verify the installation with a health check
After installation completes, open your server's IP in a browser at port 8080 and register the first user β they become the super admin.
βββββββββββββββββββββββββββββββββββββββββ
β Orbita Installer β
β Self-Hosted PaaS with Multi-Tenancy β
βββββββββββββββββββββββββββββββββββββββββ
[β] Docker installed
[β] Swarm initialized
[β] Secrets generated
[β] Services started
[β] Health check passed
Dashboard: http://your-server-ip:8080
If you prefer to set things up manually with Docker Compose:
# 1. Create project directory
mkdir -p /opt/orbita && cd /opt/orbita
# 2. Download the compose file
curl -sSL https://raw.githubusercontent.com/MUKE-coder/orbita/main/docker/docker-compose.prod.yml -o docker-compose.yml
# 3. Create .env with your secrets
cat > .env << EOF
DB_PASSWORD=$(openssl rand -hex 16)
JWT_SECRET=$(openssl rand -hex 32)
JWT_REFRESH_SECRET=$(openssl rand -hex 32)
ENCRYPTION_MASTER_KEY=$(openssl rand -hex 16)
APP_BASE_URL=https://your-domain.com
RESEND_API_KEY=re_your_key_here
RESEND_FROM_EMAIL=noreply@your-domain.com
ACME_EMAIL=admin@your-domain.com
EOF
# 4. Start everything
docker compose up -d
# 5. Verify
curl http://localhost:8080/health
# {"status":"ok","version":"0.1.0"}For environments where you want maximum control:
# 1. Download the binary
curl -L -o /usr/local/bin/orbita \
https://github.com/MUKE-coder/orbita/releases/latest/download/orbita-linux-amd64
chmod +x /usr/local/bin/orbita
# 2. Create config directory
mkdir -p /opt/orbita && cd /opt/orbita
# 3. Create .env (see Docker Installation above for template)
# 4. Create systemd service
cat > /etc/systemd/system/orbita.service << 'EOF'
[Unit]
Description=Orbita PaaS
After=network.target postgresql.service redis.service docker.service
[Service]
Type=simple
WorkingDirectory=/opt/orbita
ExecStart=/usr/local/bin/orbita
EnvironmentFile=/opt/orbita/.env
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# 5. Start
systemctl daemon-reload
systemctl enable --now orbita
# 6. Check status
systemctl status orbitaNote: Binary installation requires PostgreSQL 15+, Redis 7+, and Docker to be installed and running separately.
git clone https://github.com/MUKE-coder/orbita.git && cd orbita
# Build frontend
cd web && npm install && npm run build && cd ..
# Build Go binary (~30MB)
go build -ldflags="-s -w" -o orbita ./cmd/server/
# Or build Docker image
docker build -t orbita:local .After Orbita is running:
-
Register Super Admin β Open the dashboard and create the first account. This user automatically gets super admin privileges.
-
Create Organization β Click "Create Organization". Each org gets its own isolated Docker network, encryption keys, and resource quotas.
-
Set Up DNS β Point your domain (A record) and wildcard (
*.yourdomain.com) to your server IP. Traefik handles SSL automatically via Let's Encrypt. -
Configure Email (optional) β Sign up at resend.com and set your
RESEND_API_KEYfor invite emails, password resets, and deploy notifications. -
Deploy Your First App β Create a project, select an environment, and deploy from a Docker image or connect your Git repository.
A detailed, step-by-step guide for deploying Orbita on a cloud VPS or dedicated server.
Get a VPS from any cloud provider:
| Provider | Recommended Plan | Notes |
|---|---|---|
| Hetzner | CX22 (2 vCPU, 4GB RAM, β¬4.5/mo) | Best price/performance in EU |
| DigitalOcean | Basic Droplet (2 vCPU, 4GB, $24/mo) | Simple, reliable |
| Vultr | Cloud Compute (2 vCPU, 4GB, $24/mo) | Global locations |
| Linode/Akamai | Linode 4GB ($24/mo) | Good support |
| AWS Lightsail | 2 vCPU, 4GB ($32/mo) | AWS ecosystem |
| OVH | VPS Starter (2 vCPU, 4GB, β¬6/mo) | Budget EU option |
Choose Ubuntu 24.04 LTS as the operating system.
ssh root@YOUR_SERVER_IP
# Create a non-root user (recommended)
adduser orbita
usermod -aG sudo orbita
su - orbita# Update packages
sudo apt update && sudo apt upgrade -y
# Install essential tools
sudo apt install -y curl git ufw
# Configure firewall
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp # HTTP (Traefik)
sudo ufw allow 443/tcp # HTTPS (Traefik)
sudo ufw enable
# Verify firewall
sudo ufw status# Install Docker via official script
curl -fsSL https://get.docker.com | sh
# Add your user to the docker group
sudo usermod -aG docker $USER
newgrp docker
# Verify Docker
docker --version # Docker 24+
docker compose version # Docker Compose v2+
# Initialize Docker Swarm (required for service orchestration)
docker swarm initOption A: One-Line Install (Recommended)
curl -sSL https://raw.githubusercontent.com/MUKE-coder/orbita/main/install.sh | sudo bashOption B: Manual Install
# Create directory
sudo mkdir -p /opt/orbita
sudo chown $USER:$USER /opt/orbita
cd /opt/orbita
# Download docker-compose.yml
curl -sSL https://raw.githubusercontent.com/MUKE-coder/orbita/main/docker/docker-compose.prod.yml -o docker-compose.yml
# Generate secrets
cat > .env << EOF
DB_PASSWORD=$(openssl rand -hex 16)
JWT_SECRET=$(openssl rand -hex 32)
JWT_REFRESH_SECRET=$(openssl rand -hex 32)
ENCRYPTION_MASTER_KEY=$(openssl rand -hex 16)
APP_BASE_URL=https://orbita.yourdomain.com
RESEND_API_KEY=re_your_key_here
RESEND_FROM_EMAIL=noreply@yourdomain.com
ACME_EMAIL=admin@yourdomain.com
EOF
# Start
docker compose up -dPoint your domain to the server:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | orbita.yourdomain.com |
YOUR_SERVER_IP |
300 |
| A | *.orbita.yourdomain.com |
YOUR_SERVER_IP |
300 |
The wildcard record (*) enables automatic subdomain routing for deployed apps (e.g., myapp.orbita.yourdomain.com).
# Verify DNS propagation
dig orbita.yourdomain.com +short
# Should return YOUR_SERVER_IP# Health check
curl -s http://localhost:8080/health
# {"status":"ok","version":"0.1.0"}
# Check all containers
docker compose ps
# NAME STATUS
# orbita Up
# orbita-postgres Up (healthy)
# orbita-redis Up (healthy)
# orbita-traefik Up
# Check resource usage
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"- Open
https://orbita.yourdomain.comin your browser - Click "Get Started" to register
- The first user automatically becomes the super admin
- Create your first organization
- Start deploying apps!
# 1. Disable root SSH login
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# 2. Set up SSH key authentication (disable password auth)
# On your local machine:
ssh-copy-id orbita@YOUR_SERVER_IP
# 3. Enable automatic security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# 4. Set up automated database backups (daily at 2 AM)
cat > /opt/orbita/backup.sh << 'BKEOF'
#!/bin/bash
BACKUP_DIR="/opt/orbita/backups"
mkdir -p $BACKUP_DIR
docker exec orbita-postgres pg_dump -U orbita orbita | gzip > \
$BACKUP_DIR/orbita-$(date +%Y%m%d-%H%M%S).sql.gz
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: $(date)"
BKEOF
chmod +x /opt/orbita/backup.sh
echo "0 2 * * * /opt/orbita/backup.sh >> /var/log/orbita-backup.log 2>&1" | sudo tee -a /etc/crontab
# 5. Monitor logs
docker compose logs -f orbita --tail 100cd /opt/orbita
# Pull latest version
docker compose pull orbita
# Restart with zero downtime
docker compose up -d orbita
# Verify the update
curl -s http://localhost:8080/health
# Check logs for any migration messages
docker compose logs orbita --tail 20| Problem | Solution |
|---|---|
| Can't connect to port 8080 | Check firewall: sudo ufw status |
| Database connection failed | Check PostgreSQL: docker compose logs postgres |
| Redis connection failed | Check Redis: docker compose logs redis |
| SSL certificate not working | Verify DNS: dig yourdomain.com +short, check Traefik logs |
| "permission denied" on Docker socket | Add user to docker group: sudo usermod -aG docker $USER |
| High memory usage | Check container stats: docker stats --no-stream |
| Migrations failed | Check Orbita logs: docker compose logs orbita |
- Multi-Tenancy & Organizations β Fully isolated tenants with separate Docker networks, encryption keys, volume namespaces, and database-level scoping
- RBAC (4 Roles) β Owner, Admin, Developer, Viewer with API-level enforcement
- Team Invites β Cryptographically secure invite tokens via email (72h expiry)
- Projects & Environments β Logical grouping with auto-created Production + Staging environments
- Resource Plans β Super admin defines plans (Free/Starter/Pro/Enterprise) with CPU, RAM, disk, app limits
- Docker Image Deploy β Deploy from Docker Hub, GHCR, or any registry
- Git Auto-Deploy β Connect GitHub, GitLab, or Gitea. Auto-deploy on push via webhooks
- Build Engine β Build from Dockerfile or Nixpacks
- Zero-Downtime Deploys β Rolling updates via Docker Swarm with rollback to any previous version
- Deploy History β Versioned deployment records with status, trigger type, timestamps
- App Lifecycle β Start, stop, restart, scale replicas
- One-Click Provisioning β PostgreSQL 15/16, MySQL 8, MariaDB 10/11, MongoDB 6/7, Redis 7
- Auto-Generated Credentials β Strong passwords, encrypted connection strings
- Scheduled Backups β Hourly/daily/weekly with configurable retention
- Backup & Restore β Create manual backups, restore from any point
- Scheduled Containers β Docker containers on a cron schedule that run and exit
- Concurrency Policies β Allow, Forbid (skip if running), Replace (kill previous)
- Run History β Last 50 executions with status, exit code, duration, logs
- Manual Trigger β "Run Now" for immediate execution
- Timeout Enforcement β Configurable max runtime per job
- Custom Domains β Assign to apps, databases, and services
- Automatic TLS β Let's Encrypt via Traefik ACME
- HTTP β HTTPS Redirect β Automatic with security headers
- DNS Verification β Built-in DNS lookup
- 10 Pre-Built Templates β WordPress, Plausible, Uptime Kuma, n8n, Metabase, Grafana, MinIO, Gitea, Ghost CMS, Vaultwarden
- Parameterized Deploys β Configurable parameters per template
- One-Click Deploy β Select, fill params, deploy
- Real-Time Metrics β CPU%, memory, network I/O per container
- Dashboard Overview β Running apps, databases, cron jobs, resource usage
- Log Streaming β Real-time log viewer
- In-Browser Terminal β xterm.js SSH into running containers
- Shell Exec β Run one-off commands via API
- JWT Authentication β 15-min access + 30-day refresh tokens (httpOnly cookies)
- bcrypt Hashing β Cost 12
- AES-256-GCM Encryption β Secrets encrypted at rest with per-org HKDF-SHA256 derived keys
- Rate Limiting β Redis sliding window (5/15min on auth)
- CORS β Restricted to configured origin
- Org-Scoped Queries β Every query includes
organization_id - Webhook Signatures β HMAC-SHA256 verification
- API Keys β
orb_prefix keys for CI/CD
- In-App Notifications β Bell icon with unread count
- Audit Logs β Every action logged with user, resource, IP, timestamp
- Paginated History β Searchable audit trail per org
- Multi-Node β Add workers via SSH, Docker Swarm orchestration
- cgroup Slicing β Per-org CPU/memory limits via cgroup v2
- Node Management β Add, drain, remove nodes
| Component | Technology |
|---|---|
| Language | Go 1.22+ |
| HTTP | Gin |
| ORM | GORM + PostgreSQL 15 |
| Cache | Redis 7 |
| Auth | JWT (golang-jwt v5) |
| Resend API | |
| Containers | Docker SDK |
| Proxy | Traefik v3 |
| Cron | robfig/cron v3 |
| WebSocket | gorilla/websocket |
| Migrations | golang-migrate |
| Logging | zerolog |
| Component | Technology |
|---|---|
| Framework | React 18 + TypeScript |
| Build | Vite |
| Styling | Tailwind CSS v4 + shadcn/ui |
| State | Zustand |
| Data | TanStack Query |
| Forms | React Hook Form + Zod |
| Terminal | xterm.js |
Build output: Single Go binary with embedded React SPA (//go:embed)
All endpoints prefixed with /api/v1. Auth via Authorization: Bearer <token>.
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/register |
Register new user |
| POST | /auth/login |
Login (returns JWT) |
| POST | /auth/logout |
Logout |
| POST | /auth/refresh |
Refresh access token |
| POST | /auth/forgot-password |
Request OTP |
| POST | /auth/reset-password |
Reset with OTP |
| POST | /auth/verify-email |
Verify email |
| Method | Endpoint | Description |
|---|---|---|
| GET/PUT | /me |
Get/update profile |
| POST | /me/change-password |
Change password |
| GET | /me/sessions |
List sessions |
| DELETE | /me/sessions/:id |
Revoke session |
| GET/POST/DELETE | /me/api-keys |
API key management |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /orgs |
List/create |
| GET/PUT/DELETE | /orgs/:slug |
CRUD |
| GET | /orgs/:slug/members |
List members |
| POST | /orgs/:slug/invites |
Send invite |
| PUT | /orgs/:slug/members/:userId/role |
Change role |
| POST | /orgs/:slug/leave |
Leave org |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /orgs/:slug/projects |
List/create |
| GET/PUT/DELETE | /orgs/:slug/projects/:id |
CRUD |
| GET/POST | /orgs/:slug/projects/:id/environments |
Environments |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /orgs/:slug/apps |
List/create |
| GET/PUT/DELETE | /orgs/:slug/apps/:id |
CRUD |
| POST | /orgs/:slug/apps/:id/deploy |
Deploy |
| POST | /orgs/:slug/apps/:id/rollback/:deployId |
Rollback |
| POST | /orgs/:slug/apps/:id/stop|start|restart |
Lifecycle |
| GET | /orgs/:slug/apps/:id/deployments |
History |
| GET | /orgs/:slug/apps/:id/logs|metrics|status |
Monitoring |
| POST | /orgs/:slug/apps/:id/exec |
Run command |
| GET | /orgs/:slug/apps/:id/terminal |
WebSocket terminal |
| GET/POST/DELETE | /orgs/:slug/apps/:id/env |
Env vars |
| GET/POST/DELETE | /orgs/:slug/apps/:id/domains |
Domains |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /orgs/:slug/databases |
List/create |
| GET/DELETE | /orgs/:slug/databases/:id |
Get/delete |
| POST | /orgs/:slug/databases/:id/restart|stop|start |
Lifecycle |
| GET/POST | /orgs/:slug/databases/:id/backups |
Backup mgmt |
| POST | /orgs/:slug/databases/:id/backups/:id/restore |
Restore |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /orgs/:slug/cron-jobs |
List/create |
| GET/PUT/DELETE | /orgs/:slug/cron-jobs/:id |
CRUD |
| POST | /orgs/:slug/cron-jobs/:id/toggle|run |
Toggle/trigger |
| GET | /orgs/:slug/cron-jobs/:id/runs |
Run history |
| Method | Endpoint | Description |
|---|---|---|
| GET | /templates |
List marketplace templates |
| GET/POST | /orgs/:slug/services |
List/deploy |
| GET/DELETE | /orgs/:slug/services/:id |
Get/delete |
| Method | Endpoint | Description |
|---|---|---|
| GET | /orgs/:slug/dashboard |
Overview data |
| GET | /orgs/:slug/metrics/overview |
Resource usage |
| GET | /orgs/:slug/notifications |
Notifications |
| GET | /orgs/:slug/audit-logs |
Audit trail |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST/PUT/DELETE | /admin/plans |
Resource plans |
| GET | /admin/orgs |
All organizations |
| PUT | /admin/orgs/:slug/plan |
Assign plan |
| GET/POST/DELETE | /admin/nodes |
Node management |
| GET | /admin/platform/metrics |
Platform overview |
| Method | Endpoint | Description |
|---|---|---|
| POST | /webhooks/github |
GitHub push events |
| POST | /webhooks/gitlab |
GitLab events |
| POST | /webhooks/gitea |
Gitea events |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Orbita Binary (~30MB) β
β βββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
β β Gin Router β β React SPA β β Cron Scheduler β β
β β (REST API) β β (Embedded) β β (robfig/cron) β β
β ββββββββ¬ββββββββ ββββββββββββββββ βββββββββ¬ββββββββ β
β β β β
β ββββββββ΄ββββββββββββββββββββββββββββββββββββ΄ββββββββ β
β β Service Layer (10 services) β β
β β Auth β Org β Project β App β DB β Cron β Domain β β
β ββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββ β
β β Repository Layer (GORM + OrgScope) β β
β ββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββ΄ββββββ ββββββββββββ ββββββββββββββββ
β PostgreSQL β β Redis β β Docker Engineβ
β (22 tables)β β (Cache) β β (Containers) β
βββββββββββββ ββββββββββββ ββββββββ¬ββββββββ
β
ββββββββ΄ββββββββ
β Traefik β
β (TLS + Proxy)β
ββββββββββββββββ
orbita/
βββ cmd/server/main.go # Entry point
βββ cmd/migrate/main.go # Migration CLI
βββ internal/
β βββ api/handlers/ # 12 handler groups
β βββ auth/ # JWT, bcrypt, AES-256-GCM
β βββ config/ # Env config loader
β βββ cron/ # Scheduler + executor
β βββ database/ # GORM + migrations
β βββ docker/ # Docker SDK wrapper
β βββ mailer/ # Resend client
β βββ middleware/ # Auth, RBAC, rate limit
β βββ models/ # 15 GORM models
β βββ orchestrator/ # Deploy, provision, build
β βββ repository/ # 10 data access repos
β βββ service/ # 10 business logic services
β βββ traefik/ # Dynamic config writer
β βββ websocket/ # WS hub + terminal
βββ migrations/ # 22 SQL files
βββ web/src/ # React SPA (25+ pages)
βββ install.sh # One-line installer
βββ Dockerfile # Multi-stage build
βββ Makefile # Dev targets
βββ .env.example # Config template
| Category | Tables |
|---|---|
| Auth | users, sessions, email_verifications, password_resets, api_keys |
| Orgs | organizations, org_members, org_invites, resource_plans |
| Projects | projects, environments |
| Apps | applications, deployments |
| Data | managed_databases, backups, backup_schedules |
| Cron | cron_jobs, cron_runs |
| Infra | domains, nodes, env_variables, git_connections, registry_credentials |
| System | templates, services, notifications, notification_settings, audit_logs |
# Clone
git clone https://github.com/MUKE-coder/orbita.git && cd orbita
# Start PostgreSQL + Redis
docker compose -f docker/docker-compose.dev.yml up -d
# Configure
cp .env.example .env
# Edit .env β set JWT_SECRET, JWT_REFRESH_SECRET, ENCRYPTION_MASTER_KEY
# Run backend (with hot reload)
make dev
# Run frontend (separate terminal)
cd web && npm install && npm run dev| Command | Description |
|---|---|
make dev |
Start with Air hot-reload |
make build |
Build production binary |
make migrate |
Run migrations |
make test |
Run tests |
make lint |
Run linter |
make docker-up |
Start dev services |
make docker-down |
Stop dev services |
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
make test - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Open a Pull Request
MIT License β see LICENSE for details.
Orbita β Self-Hosted PaaS with True Multi-Tenancy
Built with Go, React, and a lot of coffee.
β Star on GitHub

