Create a link-in-bio, digital business card, portfolio, venue page, or small-business microsite - and self-host it with Docker.
Quick start · Features · Documentation · Contributing · Security
OrbitPage is a free, MIT-licensed Linktree alternative for building link-in-bio pages, digital business cards, portfolios, creator profiles, venue menus, event pages, and small-business websites. It combines a visual editing dashboard with responsive public rendering, built-in SEO and analytics, an Express backend, SQLite, and local file storage. No external database is required.
This repository is the self-hosted edition. The optional managed service is available at orbitpage.com, but its control plane, billing, managed storage, and hosted-only features are not part of this repository.
- Own the stack and the data. Run one Docker container with SQLite and local storage, on your server or homelab.
- Edit visually. Manage content, design, menus, subpages, privacy, analytics, and publishing from the responsive dashboard.
- Publish more than a list of links. Combine profiles, media, contact details, events, maps, menus, calls to action, and focused subpages.
- Ship a discoverable public page. Configure canonical URLs, Open Graph and Twitter cards, Schema.org data, sitemaps, robots directives, QR codes, and consent-aware analytics.
- Why OrbitPage
- Quick start
- What you can build
- Dashboard workspaces
- How it runs
- First run
- Configuration
- Data and backups
- Production checklist
- Development
- Documentation
- Security and contributing
OrbitPage publishes a ready-to-run Linux amd64 image on Docker Hub and GitHub Container Registry. The commands below use Docker Hub:
sudo install -d -m 0700 /etc/orbitpage
sudo install -d -m 0750 /var/lib/orbitpage
printf 'NODE_ENV=production\nPORT=8080\nDATA_DIR=/app/data\nJWT_SECRET=%s\n' \
"$(openssl rand -hex 32)" | sudo tee /etc/orbitpage/orbitpage.env >/dev/null
sudo chmod 0600 /etc/orbitpage/orbitpage.env
sudo docker pull paueron/orbitpage:latest
sudo docker run -d --name orbitpage \
--restart unless-stopped \
--env-file /etc/orbitpage/orbitpage.env \
-p 8080:8080 \
-v /var/lib/orbitpage:/app/data \
--security-opt no-new-privileges:true \
paueron/orbitpage:latestOpen the public page at http://localhost:8080, the dashboard at http://localhost:8080/dashboard/profile, and the health check at http://localhost:8080/health.
The same image is available as ghcr.io/paoloronco/orbitpage:latest. For production, replace latest with an immutable tag from GitHub Releases. The unless-stopped policy restarts OrbitPage after failures and host reboots while respecting an explicit stop; use always only when an explicit stop must not survive a Docker daemon restart.
See the complete Docker deployment procedure for image selection, Compose, verification, updates, backups, and rollback.
- Clone the repository.
- Start the local evaluation service:
docker compose up -dThe tracked Compose file contains a public placeholder secret and is only for local evaluation on a trusted machine. Do not expose it to a network. For production, use the protected env-file Compose procedure; never commit a real secret or put it in a docker run -e argument.
On a clean x86-64 Debian 12/13 or Ubuntu 22.04/24.04 server, VM, or LXC:
curl -fsSL https://raw.githubusercontent.com/paoloronco/OrbitPage/main/install.sh | sudo bashThe installer automates the same Docker deployment, generates a private JWT secret, persists application data, starts OrbitPage, and installs the orbitpage management command.
For a Proxmox VE 8+ host, use the dedicated host-to-LXC installer instead:
curl -fsSL https://raw.githubusercontent.com/paoloronco/OrbitPage/main/install-pve.sh | bashDo not run the Linux guest installer directly on a Proxmox host. See Deployment for supported options, static networking, image pinning, backups, updates, and removal.
Requirements:
- Node.js
^20.19.0or>=22.12.0 - npm
- Git
git clone https://github.com/paoloronco/OrbitPage.git
cd OrbitPage/app
npm ci
npm run install:server
export JWT_SECRET="$(openssl rand -hex 32)"
export DATA_DIR="$PWD/.orbitpage-data"
npm run startThe production-style source run is available at http://localhost:3001.
- A main public page plus focused subpages with independent slugs, titles, descriptions, and blocks.
- Link, text, heading, separator, image, native video, social, contact, map, event, callout, and consent-aware embed blocks, with presets for media, scheduling, and forms.
- Venue menus with locale, sections, one-level subsections, products, variants, images, prices, and availability.
- Per-block visibility, ordering, scheduling, icons, cover media, calls to action, and layout controls.
- Responsive public rendering for mobile, laptop, and desktop layouts.
- Creator, company, and studio profile structures.
- Profile image or logo, shape and size, favicon, social profiles, browser title, SEO description, and footer.
- Ready-made themes plus colors, typography, spacing, surfaces, borders, radius, shadow, blur, and per-card overrides.
- Live preview using the same public renderer.
- Dashboard localization in 14 languages with Arabic RTL layout.
- A unified Publish workspace for QR codes, sitemap state, and discovery files.
- Screen and print QR presets with PNG and SVG downloads.
- Canonical URL, Open Graph, Twitter Card, Schema.org, and
noindexcontrols. - Generated
sitemap.xml. - Editable
robots.txt,llms.txt,humans.txt,ai.txt,security.txt, and safe custom text endpoints.
- Built-in self-hosted click and CTA counters, plus optional GA4 integration on the public page.
- Consent controls, policy links, Google Consent Mode, and optional external CMP integration.
- Complete or selective JSON backup and restore.
- Upload quotas, validated image and video uploads, and unused-media cleanup.
- Multiple dashboard users, scoped permissions, password management, and TOTP two-factor authentication.
- Health checks, persistent local data, Docker support, and additive SQLite migrations.
The current dashboard keeps related work together:
| Workspace | Purpose |
|---|---|
| Page | Identity, profile image, role, browser presence, and profile-card settings |
| Content | Home blocks, venue menu, and public subpages |
| AI Assistant | Propose profile, content, and theme changes for explicit review and confirmation |
| Theme | Page-wide visual system and responsive live preview |
| Publish | QR downloads, sitemap, robots, and discovery text files |
| Backup | Portable exports, selective restore, and unused-media tools |
| Analytics | Built-in performance and optional GA4 settings |
| Privacy | Consent behavior, legal policies, and external CMP settings |
| Team | Additional users and permissions |
| Account | Password and two-factor authentication |
Dashboard routes are stable, including /dashboard/profile, /dashboard/content, /dashboard/ai, /dashboard/theme, and /dashboard/publish. Legacy routes such as /admin and the old Links, Pages, Menu, and Access paths remain compatibility aliases.
Read the dashboard guide for the complete route map and editing workflow.
Browser
├─ public OrbitPage
└─ /dashboard/* React workspace
│
▼
Express application
├─ internal dashboard API
├─ SQLite database
└─ local uploads
Repository layout:
app/
src/ React + TypeScript frontend
server/ Express backend and SQLite
packages/page-schema/ Shared page-data schemas
e2e/ Playwright browser tests
docs/ User and operations guides
scripts/ Installer and repository helpers
.github/ CI, release, and image workflows
Dockerfile Canonical production image
See app/README.md for application development boundaries.
- Open the public URL. A fresh instance shows Under construction and is excluded from indexing and analytics.
- Open
/dashboard/profile. - Review the runtime, SQLite, storage, frontend, and session checks.
- Create the password for the fixed first username,
admin. - Choose the primary public-page slug.
- Complete setup and follow the dashboard guide.
The administrator, slug, and starter profile are created atomically. Existing installations created before slug-based setup remain backward compatible.
The essential production settings are:
| Variable | Required | Default | Purpose |
|---|---|---|---|
JWT_SECRET |
Production | Random outside production | Signs sessions and protects encrypted server-side secrets |
DATA_DIR |
Recommended | Server directory; /app/data in Docker |
Stores SQLite and uploads |
PORT |
No | 3001; 8080 in Docker |
HTTP listener |
PUBLIC_SITE_URL |
Recommended | Request origin | Canonical public URL for sharing, QR, sitemap, and metadata |
PUBLIC_SITE_NAME |
No | OrbitPage |
Site name in generated metadata |
SEO_INDEXING |
No | true |
Set to false for staging or private deployments |
UPLOAD_STORAGE_QUOTA_MB |
No | 1024 |
Total upload quota |
VIDEO_UPLOAD_LIMIT_MB |
No | 100 |
Per-file video limit |
For AI provider settings, cleanup controls, rate limiting, HTTPS, base paths, CORS, reset recovery, and build-time variables, use the complete Configuration reference.
Everything that must survive a restart belongs under DATA_DIR:
orbitpage.db
uploads/
Persist /app/data in Docker. Back up the database and uploads together before upgrades or restores. Never commit a database, database backup or sidecar, uploads, logs, environment file, or real user content.
The dashboard can create complete or selective JSON exports. A selective export does not replace a consistent infrastructure backup. Follow the verified backup and restore runbook, copy recovery archives off-host, and test a restore periodically.
- Keep a stable, long, random
JWT_SECRETin a protected env file or secret store. - Persist
DATA_DIRor/app/data. - Put OrbitPage behind trusted HTTPS.
- Set
PUBLIC_SITE_URLto the final public origin. - Enable TOTP for privileged users under Dashboard > Account.
- Create a verified off-host backup and complete a restore drill before relying on it.
- Verify
/healthand the public, dashboard, login, edit, and upload paths after deployment. - Set
SEO_INDEXING=falseon staging and private instances.
Read Deployment before configuring a reverse proxy, base path, cloud platform, update, or rollback.
From app/:
npm ci
npm run install:serverRun the API and frontend in separate terminals:
npm run server:dev
npm run devQuality checks:
npm run lint
npm run test:unit
npm run build
npm run test:e2e:chromiumSee Development and CONTRIBUTING.md before opening a pull request.
Start from the task-oriented documentation index.
| Task | Guide |
|---|---|
| Install or evaluate | Getting started |
| Deploy, update, or use Proxmox | Deployment |
| Configure environment variables | Configuration |
| Navigate the editor | Dashboard guide |
| Build content, menus, subpages, and themes | Content and design |
| Export, restore, clean media, or evaluate demo mode | Backups, media, and demo mode |
| Configure AI safely | AI assistant |
| Configure analytics and consent | Analytics and privacy |
| Configure search and discovery | SEO and indexing |
| Troubleshoot | Troubleshooting |
The self-hosted Express API is an internal boundary used by the bundled dashboard, not a stable external SDK. Read the self-hosted API boundary. The separate OrbitPage community node for n8n connects to the managed Automation API; it does not expose the bundled self-hosted API as a public contract.
Report suspected vulnerabilities privately through a GitHub Security Advisory or the contact in SECURITY.md. Do not open a public issue for an unpatched vulnerability.
Issues and focused pull requests are welcome. Read CONTRIBUTING.md for setup, checks, compatibility expectations, and the contribution workflow. Participation follows the Code of Conduct.
OrbitPage's open-source edition is available under the MIT License.
