⬑ ⬑ ⬑
⬑ ⬑ ⬑
⬑ ⬑ ⬑
A lightweight, beautiful Docker & Compose management UI.
Compose-first. No agents. No complexity. Just your containers.
β¨ Vibe coded with Claude β built through conversation, not configuration.
Orbit is a self-hosted Docker management web app β a modern, opinionated alternative to Portainer. It's designed for people who live in docker compose and want a clean UI without the enterprise overhead.
Key ideas:
- π§± Compose-first β stacks are the primary unit, not individual containers
- π¦ Template library β one-click deploy with Portainer-compatible template support
- π΄ Live updates β WebSocket-driven dashboard, no manual refresh
- π Simple auth β JWT-based, multi-user with roles
- πͺΆ Lightweight β ~10 MB images, no database, no agents
Live container grid with status and health overview.
Deploy & manage Compose stacks seamlessly.
One-click application deployments with Portainer template compatibility.
# 1. Clone
git clone https://github.com/fatihbtw/orbit.git
cd orbit
# 2. Configure (optional)
cp .env.example .env
# edit .env β set a strong ORBIT_SECRET and ORBIT_ADMIN_PASSWORD
# 3. Launch
docker compose up -d
# 4. Open
open http://localhost:3000
# Login: admin / orbit-change-me (change this!)Note: Orbit needs access to the Docker socket (
/var/run/docker.sock).
It runs as root inside the container β see Security for hardening options.
All config via environment variables or .env file:
| Variable | Default | Description |
|---|---|---|
ORBIT_ADMIN_PASSWORD |
orbit-change-me |
Admin password β change this |
ORBIT_SECRET |
CHANGE_ME_... |
JWT signing secret β use 32+ random chars |
ORBIT_PORT |
3000 |
Host port for the web UI |
LOG_LEVEL |
info |
Backend log level (debug, info, warn) |
STACKS_DIR |
/data/stacks |
Where stack YAML files are stored |
# .env example
ORBIT_ADMIN_PASSWORD=my-super-secret-password
ORBIT_SECRET=change-me-to-a-long-random-string-here
ORBIT_PORT=3000Browser
β
βΌ
βββββββββββββββββββββββ
β nginx (port 3000) β β only external port
β serves index.html β
β proxies /api/ & /wsβ
ββββββββββ¬βββββββββββββ
β internal Docker network
βΌ
βββββββββββββββββββββββ
β Node.js backend β β no external port exposed
β Hono framework β
β port 4000 (intern) β
ββββββββββ¬βββββββββββββ
β
βΌ
Docker socket
/var/run/docker.sock
Why is the backend port internal-only?
nginx already proxies all /api/ and /ws traffic to the backend over the internal Docker network. There's no reason to expose port 4000 to the host. You can uncomment the ports: section in docker-compose.yml if you need direct backend access for debugging.
Stack storage:
Compose files live in a named Docker volume (orbit-stacks). Settings (users, template URLs) are stored in /data/settings.json on the same volume β no external database needed.
- Live container grid with status, image, ports, compose project
- Health bar (% running)
- Real-time Docker events feed via WebSocket
- Create, edit, deploy and remove Compose stacks
- Live deploy log stream (
docker compose upoutput in real-time) - Stop individual stacks
- View stack logs
- 10+ built-in templates (Nginx, PostgreSQL, MySQL, Redis, WordPress, Gitea, Nextcloud, Traefik, Grafana, Uptime Kuma, Vaultwarden)
- Portainer-compatible β import any Portainer v1/v2 template JSON URL
- Grid & list view toggle (preference saved in browser)
- Category filters
- Full deploy dialog with tabs:
- Environment β edit all env vars with labels, defaults, dropdowns for
selectfields - Volumes β edit host paths, container paths, read/write mode
- Ports β override published ports
- YAML Editor β full compose YAML editor, auto-synced from other tabs
- Environment β edit all env vars with labels, defaults, dropdowns for
- Users β create/edit/delete users with roles (
admin,operator,viewer) - Template Sources β add persistent Portainer-compatible template URLs (survive restarts)
- Per-container log viewer (last 300 lines)
Orbit supports both Portainer template formats:
- v1 β plain JSON array of template objects
- v2 β
{ "version": "2", "templates": [...] }
Known working sources:
https://raw.githubusercontent.com/portainer/portainer-templates/master/templates-2.0.json
https://raw.githubusercontent.com/pi-hosted/pi-hosted/master/template/portainer-v2.json
https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json
Add them in Settings β Template Sources.
| Role | Can do |
|---|---|
admin |
Everything β users, settings, deploy, delete |
operator |
Deploy stacks, start/stop containers, view all |
viewer |
Read-only β view containers, logs, stacks |
arm64 images for node:20-alpine and nginx:alpine are available on Docker Hub. Orbit runs well.
# Same as normal, just run it
docker compose up -d- 1 GB RAM is tight but functional
- First build takes longer (arm compilation)
- Limit the backend memory if needed:
# in docker-compose.yml under backend: deploy: resources: limits: memory: 256m
| Spec | Pi Zero 2 W | Orbit requirement |
|---|---|---|
| CPU | 1 GHz quad-core ARM Cortex-A53 | Light β Hono is fast |
| RAM | 512 MB | ~100β150 MB at idle β tight |
| Arch | arm64 / armv7 | β supported by base images |
| Storage | microSD | β (wear is a concern long-term) |
The main constraint is RAM. The Node.js backend + nginx will use ~100β150 MB at idle. With Docker itself and the OS, you're close to the 512 MB ceiling, especially when deploying stacks. There's no swap by default on Raspberry Pi OS Lite.
If you want to try it:
# Enable swap first
sudo dphys-swapfile swapconf # edit /etc/dphys-swapfile, set CONF_SWAPSIZE=512
sudo dphys-swapfile setup
sudo dphys-swapfile swapon
# Add memory limits to docker-compose.yml
# backend: deploy.resources.limits.memory: 200m
# frontend: deploy.resources.limits.memory: 64m
docker compose up -dBottom line: For a Pi Zero 2 W, Orbit will start but may struggle when actively deploying stacks or pulling images. A Pi 3B+ or Pi 4 is a much more comfortable experience.
Current state (Phase 0): Orbit runs as root inside its container to access the Docker socket. This is the same approach used by Portainer and Dockge in their default configurations.
What this means: Anyone with access to the Orbit UI effectively has root on the host via Docker. Use Orbit only on trusted networks, behind a VPN, or behind an authenticated reverse proxy.
Planned hardening (Phase 1):
-
docker-socket-proxyfor fine-grained API restriction - Switch to docker group GID mapping (non-root)
- HTTPS via Caddy/Traefik integration
- Token blocklist (Redis)
- LDAP / OIDC integration
- Audit log persistence
# Backend (hot reload)
cd backend
npm install
node --watch src/index.js
# Frontend β just edit index.html, nginx serves it statically
# Rebuild containers after changes:
docker compose build --no-cache
docker compose up -dOrbit was vibe coded β the entire codebase was built through conversation with Claude (Anthropic), iterating from a rough idea to a working app without writing a single line manually. The design, architecture, bug fixes, and feature additions were all done by describing what was needed and refining the result.
This is what "vibe coding" looks like in practice: fast, iterative, surprisingly capable β and a lot of fun.
MIT Β© 2025 β do whatever you want with it.