Skip to content

paoloronco/OrbitPage

Repository files navigation

OrbitPage

A self-hosted public page for people, brands, venues, events, and privacy-minded teams.

Version Docker Hub GHCR Available on GitHub Available on Gitea

OrbitPage is an open-source public page manager you can run on your own server. It gives you one polished place for links, text blocks, social destinations, venue details, campaigns, announcements, click analytics, privacy controls, backup/restore, and production-ready Docker images without requiring an external database.

OrbitPage public page screenshot

Why OrbitPage?

Most public-page tools are either hosted SaaS products or self-hosted projects that need extra services before you can get started. OrbitPage is built for anyone who wants a clean public page and an admin experience that still feels simple when it runs on their own infrastructure.

If you want... OrbitPage gives you...
A flexible public page Links, text cards, separators, social links, avatars, cover images, venue or brand details, and SEO metadata
A self-hosted setup Docker, SQLite, local uploads, health checks, and a single persistent data volume
Control over privacy Optional analytics, consent/legal settings, no required external database, and self-owned data
A usable admin panel Live preview, drag-and-drop ordering, theme editing, scheduling, access management, and inline feedback
Safer operations JWT auth, bcrypt passwords, upload restrictions, storage quotas, backup/restore, CI, and Docker smoke tests

Contents

Try the Demo

The demo is the fastest way to see both sides of OrbitPage: the public page visitors see, and the admin panel you use to manage it.

Area Link Login
Public page orbitpage-demo.paoloronco.it No login required
About OrbitPage orbitpage-demo.paoloronco.it/about No login required
Admin panel orbitpage-demo.paoloronco.it/admin admin / ChangeMe123!

Demo changes may be reset and should not be used for private data.

Features

Area Highlights
Public page Name/brand, avatar or logo, bio/description, social links, link cards, text cards, separators, cover images, SEO metadata, legal footer links
Link management Link/text/separator blocks, visibility toggles, scheduling, drag-and-drop ordering, JSON import/export
Design Theme editor, live preview, colors, gradients, typography, spacing, radius, blur, glow, custom CSS
Admin Page editor, analytics, privacy/legal settings, access management, password management, demo mode support
Data ownership SQLite persistence, local uploads, full JSON backup/restore, Docker volume support
Security bcrypt password hashing, signed JWT sessions, encrypted browser token storage, rate limits, upload restrictions, storage quota
Deployment Docker Hub, GHCR, Docker Compose, health endpoint, Cloud Run compatible, no external database required

Screenshots

Public page Admin links
Public page Admin link manager
Theme editor Page editor
Theme editor Page editor

Walkthroughs:

Quick Start with Docker

Docker is the recommended way to run OrbitPage in production or on a home server.

docker run -d --name orbitpage \
  -p 8080:8080 \
  -e NODE_ENV=production \
  -e PORT=8080 \
  -e JWT_SECRET="$(openssl rand -hex 32)" \
  -v orbitpage_data:/app/data \
  paueron/orbitpage:latest

Open:

The first admin visit asks you to create the admin password. The first username is always admin.

Quick Start

Use this path when you want to run OrbitPage from source.

git clone https://github.com/paoloronco/OrbitPage.git
cd OrbitPage/app
npm ci
npm run install:server
npm run start

Open:

On the first admin visit, OrbitPage asks you to create the admin password. The first username is always admin.

Requirements:

  • Node.js ^20.19.0 or >=22.12.0
  • npm
  • Git

Production Notes

The same image is published to Docker Hub and GitHub Container Registry.

Docker Hub:

paueron/orbitpage:latest

GHCR:

ghcr.io/paoloronco/orbitpage:latest

The /app/data volume stores the SQLite database and uploads. Keep it mounted before upgrading or recreating the container.

Docker Compose

docker compose up -d

Before exposing the app publicly, replace the sample JWT_SECRET in docker-compose.yml.

Deploy Anywhere

OrbitPage can run on any platform that supports a Docker container or a Node.js service: Cloud Run, Render, Fly.io, DigitalOcean App Platform, Azure App Service, Koyeb, Northflank, CapRover, Dokku, Coolify, and similar providers.

For container platforms, the deployment shape is always the same:

NODE_ENV=production
PORT=8080
JWT_SECRET=replace-with-a-long-random-secret

Then persist /app/data and expose port 8080. Most platforms provide HTTPS at the edge, so ENABLE_HTTPS is usually only useful for local or private self-signed deployments.

Configuration

The production essentials are intentionally small:

Variable Required Purpose
JWT_SECRET Yes in Docker/production Stable signing key for admin sessions. Use a long random value.
PORT Usually HTTP port. Docker defaults to 8080; local Node defaults to 3001.
DATA_DIR Recommended for custom installs Directory for orbitpage.db and uploads. Docker uses /app/data.
UPLOAD_STORAGE_QUOTA_MB Optional Maximum total upload storage in MB. Defaults to 1024.
PUBLIC_SITE_URL Recommended behind proxies Canonical public URL for SEO, sitemap, and social previews.
SEO_INDEXING Optional Set to false for staging/private deployments.
RESET_TOKEN Optional Enables protected recovery/reset endpoints. Use at least 32 characters.

See the full environment reference in docs/wiki/Configuration.md.

Development

Development mode uses two processes: Express for the API and Vite for the frontend.

cd OrbitPage/app
npm ci
npm run install:server

Terminal 1:

npm run server:dev

Terminal 2:

npm run dev

Open:

Useful checks:

npm run lint
npm run test:unit
npm run build

Search and Sharing

OrbitPage generates metadata from your saved public page and environment, so most deployments do not need source-code SEO edits.

Recommended production values:

PUBLIC_SITE_URL=https://links.example.com
PUBLIC_SITE_NAME="Your Name or Brand"
SEO_INDEXING=true

Use SEO_INDEXING=false for private, staging, or preview deployments. OrbitPage will emit noindex metadata and a blocking robots.txt.

OrbitPage also serves:

  • page-based title and meta description
  • canonical URL
  • Open Graph and Twitter Card metadata
  • Schema.org JSON-LD
  • dynamic robots.txt
  • dynamic sitemap.xml with automatic lastmod updates from public content changes
  • editable llms.txt plus llm.txt alias
  • editable humans.txt, ai.txt, and security.txt
  • noindex headers for admin, API, health, and unknown SPA routes

Admins can edit these TXT endpoints from the Privacy/TXT area. Demo deployments expose the files but keep editing disabled.

Full guidance lives in docs/wiki/SEO-and-indexing.md.

Documentation

The README is the quick path. Longer operational docs live in docs/wiki/ and are ready to mirror into the GitHub Wiki:

📝 Changelog

Show full changelog
v4.6.0

Theme persistence fix

  • Accepts and persists the new profile-card and content-card palette objects in the theme API.
  • Restores saving for ready-made themes, card styles, imports, and manual fine tuning.
  • Adds backend regression coverage for modern nested theme payloads.
v4.4.0

Explicit blocks, theme studio, and privacy-ready embeds

  • Expands the block system with headings, images, contacts, social rows, callouts, maps, events, and consent-aware embeds.
  • Adds independent ready-made page themes and card-style presets with live previews and unrestricted fine tuning.
  • Adds complete profile-card and avatar customization, including colors, borders, accents, and image shape.
  • Aligns Admin previews with public rendering and reorganizes the Links editor into clear content, publishing, media, and appearance sections.
  • Hardens Google Analytics Consent Mode v2 and external CMP integrations for Cookiebot, CookieYes, OneTrust, iubenda, and custom providers.
  • Adds secure embed sandboxing, stricter CSP provider allowlists, and expanded CMP regression coverage.
v4.3.28

Automatic sitemap freshness

  • Updates /sitemap.xml automatically from public content timestamps.
  • Uses profile, links, theme, consent, and TXT file changes to generate stable lastmod values.
  • Serves the sitemap with no-store headers so crawlers do not keep stale XML.
v4.3.27

Editable crawler and LLM TXT files

  • Adds dynamic robots.txt, llms.txt, llm.txt, humans.txt, ai.txt, and security.txt endpoints.
  • Adds an admin TXT editor with save/reset controls and demo-mode read-only protection.
  • Persists custom TXT files in SQLite and includes them in backup/restore.
v4.3.26

About page SEO hardening

  • Adds richer server-rendered SEO metadata for the demo /about page.
  • Adds Open Graph/Twitter image metadata and SoftwareApplication JSON-LD for better social previews and search snippets.
  • Covers the About SEO metadata with backend regression tests.
v4.3.25

Demo-only product about page

  • Adds a polished /about page for the public demo instance.
  • Keeps /about unavailable outside demo mode and links it from the README demo table.
v4.3.24

README quick start flow

  • Moves the Docker quick start directly above the source quick start.
  • Keeps the README contents order aligned with the rendered section order.
v4.3.23

README and discoverability refresh

  • Reworks the GitHub README around self-hosted public page positioning.
  • Adds clearer demo, Docker quick start, feature, screenshot, and deployment sections.
v4.3.22

GitHub Actions hardening

  • Adds explicit read-only GITHUB_TOKEN permissions to CI and Gitea mirror workflows.
  • Covers the workflow permission policy with deployment configuration tests.
v4.3.21

CI server test ordering

  • Builds the frontend before running server tests in GitHub Actions.
  • Locks the workflow order so SPA and SEO tests always have dist/index.html on clean runners.
v4.3.20

Auth schema extraction

  • Moves auth and user-management request validation into a dedicated Zod schema module.
  • Replaces duplicated manual checks in setup, login, user, role, password, and reset handlers.
v4.3.19

Backup and restore UI

  • Adds admin dashboard controls to download a full backup JSON.
  • Adds guarded restore from backup with inline success and error states.
v4.3.18

Backup and restore API

  • Adds admin-only backup export for application tables and upload files.
  • Adds restore support with safe upload path validation and transactional database writes.
v4.3.17

Upload storage quota

  • Adds a configurable UPLOAD_STORAGE_QUOTA_MB limit for files stored in uploads.
  • Removes the newly uploaded file and returns 413 when the quota is exceeded.
v4.3.16

Upload hardening policy

  • Generates upload filenames with UUIDs instead of predictable random suffixes.
  • Stores uploaded media with owner-writable, non-world-writable permissions.
  • Copies extracted backend service modules into the production Docker image.
v4.3.15

Raster-only image uploads

  • Aligns client-side avatar, icon, and cover image uploads with the backend raster-image policy.
  • Rejects unsanitized SVG files before they can be converted into stored data URLs.
v4.3.14

Shared link DTO normalization

  • Adds a shared frontend link DTO normalizer backed by Zod.
  • Replaces duplicated link mapping in Admin and public page loading, reducing lint warnings from 154 to 114.
v4.3.13

Consent schema extraction

  • Moves consent configuration validation schemas into a dedicated backend schema module.
  • Adds regression coverage for consent config defaults and supported CMP providers.
v4.3.12

Link schema extraction

  • Extracts backend link validation schemas from the server monolith into a dedicated module.
  • Keeps the production Docker image aware of extracted server modules.
v4.3.11

CI quality gate

  • Adds blocking dependency audits for frontend and backend packages in GitHub Actions.
  • Adds a Docker smoke test that builds the production image, starts it with a CI secret, and checks /health.
v4.3.10

Theme save consistency

  • Makes theme import, reset, and editing follow the same preview-then-save workflow.
  • Exports the pending theme and keeps unsaved theme changes visible when saving fails.
v4.3.9

Link save reliability

  • Keeps unsaved link changes visible when saving fails instead of clearing the dirty state too early.
  • Shows the save error inline in the link manager so admins can retry without losing context.
v4.3.8

CMP consent flow hardening + CCPA link polish

  • Treat bootstrap CMP states from Cookiebot, OneTrust, and Cookiebot events as implicit until a user action is explicitly detected, preventing pre-granted consent from loading Google Analytics too early.
  • Improve Google Consent Mode propagation from builder CMPs and keep script dispatch aligned with explicit consent only.
  • Ensure the CCPA "Do not sell my personal information" footer link remains available with locale-aware label variants and a stable fallback target.
v4.3.6

Consent signal hardening for Google & CCPA

  • Distinguishes implicit consent state from explicit user consent for all supported external CMPs (iubenda, Cookiebot, CookieYes, OneTrust, custom snippets).
  • Defers third-party tag loading until consent is explicitly granted, including GA4 script/config gating and Google Consent Mode updates.
  • Syncs Google Consent Mode updates even when gtag is not yet loaded, avoiding silent failures and premature network requests.
  • Restores privacy footer policy URL resolution from consentConfig.legalPolicies, so CCPA "Do not sell my personal information" links remain available when hosted/embedded legal pages are used.
v4.3.6

CMP hardening for Google Consent Mode

  • Prevents builder-mode external CMP signals (especially iubenda) from being treated as explicit consent before user interaction.
  • Separates implicit provider state from explicit consent, so gtag('consent', 'update') and consent-dependent scripts dispatch only after explicit choice.
  • Restricts dataLayer fallback sync to consent update entries only, preventing default/implicit consent bootstrap from firing tags early.
v4.3.5

Documentation and wiki refresh

  • Reworks the README around demo-first evaluation, shorter feature scanning, Docker production setup, configuration, development, and SEO basics.
  • Adds a wiki-ready documentation set with expanded deployment, configuration, development, SEO, security, and troubleshooting guides.
  • Updates SECURITY.md, CONTRIBUTING.md, and the Docker Compose image reference to match the current app architecture.
v4.3.4

Minor container tag reliability

  • Fixes the main-branch Docker workflow so X.X tags are computed without shell-interpreted JavaScript template literals.
  • Adds regression coverage to keep version and minor-version image tags published from the package version.
  • Keeps Docker Hub and GHCR publishing aligned for latest, X.X.X, vX.X.X, and X.X tags.
v4.3.3

Versioned container tags from main

  • Publishes Docker version tags directly from the main-branch build, including X.X.X, vX.X.X, and X.X.
  • Avoids relying on tag-triggered workflows for automated release tags created by GitHub Actions.
  • Keeps Docker Hub and GHCR tags aligned from the same build output.
v4.3.2

Dual container registry publishing

  • Publishes Docker images to both Docker Hub (paueron/orbitpage) and GitHub Container Registry (ghcr.io/paoloronco/orbitpage).
  • Keeps latest, semantic version, minor version, and short SHA tags aligned across both registries.
  • Documents the GHCR pull path alongside the existing Docker Hub distribution path.
v4.3.1

Deployment and admin startup fixes

  • Aligns both Dockerfiles on the production runtime contract: Node 22, PORT=8080, DATA_DIR=/app/data, and mandatory JWT_SECRET.
  • Makes the app/ Dockerfile self-contained for docker build ./app.
  • Avoids the expected unauthenticated /api/auth/verify call when opening the admin login page without a stored token.
v4.3.0

Multi-user access management

  • Renames the Security admin tab to Access.
  • Adds full multi-user management: list users, create users, change any user's password, and delete users.
  • The admin user is created by default and cannot be deleted.
  • Login form now accepts any username; backend validates credentials per-user.
  • POST /api/auth/change-password now changes the password of the currently authenticated user (not hardcoded to admin).
  • New API endpoints: GET /api/users, POST /api/users, PUT /api/users/:username, DELETE /api/users/:username.
v4.2.0

Card cover images

  • Adds optional cover/header image to link and text cards.
  • Full-bleed 16:9 image displayed at the top of each card on both the public page and admin panel.
  • Supports URL input or local file upload; alt text field for accessibility.
  • Graceful fallback on broken image (no layout shift).
  • DB migrations for cover_image and cover_image_alt columns (additive, non-destructive).
v4.1.8

Legal policy embed fix

  • Allows the current Usercentrics embed domains in the production CSP.
  • Keeps embedded legal policy scripts executable and ordered when rendered on /privacy and /cookies.
  • Adds a regression test for legal policy provider CSP sources.
v4.1.7

CMP and release workflow fix

  • Executes custom external CMP scripts reliably, including pasted iubenda widget snippets.
  • Publishes Docker images only from release tags to avoid duplicate Docker builds on main and v*.
  • Keeps latest, semantic version, and short SHA Docker tags on release builds.
v4.1.6

Demo legal policy preset

  • Adds a server-side demo preset for Privacy Policy, Cookie Policy, and external CMP.
  • Serves the demo legal pages from the requested iubenda embeds when DEMO_MODE=true.
  • Keeps public footer links on /privacy and /cookies in demo mode.
  • Ensures iubenda embedded policy scripts load reliably in SPA-rendered legal pages.
v4.1.5

Privacy hotfix

  • Stops demo-mode write protection from being shown as an expired admin session.
  • Ensures embedded legal policy scripts execute on /privacy and /cookies.
  • Infers hosted legal pages from existing /privacy and /cookies profile URLs for upgraded installs.
v4.1.4

Privacy and CMP configuration

  • Separates legal pages from consent management in the Privacy tab.
  • Adds provider-agnostic legal policy sources: external link, hosted text, and embedded code.
  • Replaces provider-specific CMP fields with a single external script flow.
  • Ensures /privacy and /cookies always render the latest selected source without stale provider fallback.
  • Keeps form edits on screen when the admin session expires during save.
v4.1.3

Consent mode

  • Ensures Google Consent Mode v2 defaults are set before analytics scripts load.
  • Defaults ad storage, analytics storage, user data, and personalization to denied when consent is enabled.
  • Avoids duplicate default consent blocks when an advanced provider already supplies one.
v4.1.2

Legal policies

  • Redesigned the Privacy tab legal policy setup with a guided, non-technical flow.
  • Added a footer visibility toggle, configured/missing status, and preview links for /privacy and /cookies.
  • Added a public /cookies placeholder page.
v4.1.1

Privacy and legal UX

  • Moved Privacy Policy and Cookie Policy editing from the page editor to Privacy.
  • Kept the existing profile-backed fields as the single persistence source.
  • Forced the public /privacy page to render in a readable light layout.
v4.1.0

Legal links

  • Made Admin > Page > Legal links the single editable source for Privacy Policy and Cookie Policy URLs.
  • Shows configured legal links in the public footer and hides them cleanly when empty.
  • Makes the Privacy & Cookies tab read-only for policy URLs, with an Edit in Page shortcut.
  • Ensures the native cookie banner derives policy URLs from the profile instead of storing duplicate consent-config URLs.
v4.0.0

Admin experience

  • Redesigned the Admin panel with a clearer dashboard layout, status metrics, sticky centered navigation, and a lighter operational workspace.
  • Improved the Links editor with a clearer toolbar, content creation cards, save state visibility, and a more helpful empty state.
  • Added animated profile checklist guidance and save confirmation feedback for theme changes.
  • Kept the public page preview isolated from the Admin styling so it continues to reflect the saved public theme.

Loading and compatibility

  • Added a single public-page payload endpoint to load profile, links, and theme together and avoid flashes of default content.
  • Preserved compatibility with existing SQLite databases through additive migrations only.
v3.8.0

Integrations

  • Added Google Analytics 4 integration in the Admin panel (new Integrations tab).
  • The GA4 Measurement ID (G-XXXXXXXXXX) is stored in the database and injected as a gtag.js script on the public page only — the admin panel is never tracked.
  • Content Security Policy updated to allow googletagmanager.com and google-analytics.com script and connect sources.
  • Measurement ID is validated client-side before saving (format G-XXXXXXXXXX).
v3.7.0

Critical fixes

  • Fixed production blank page behavior caused by CORS/CSP headers blocking API calls in production containers.
  • Fixed stale frontend assets in Docker builds by cleaning dist before building.
  • Fixed legacy database migration handling.
  • Fixed missing fs import in database.js.

Production stability

  • Improved production CORS handling for same-origin and reverse-proxy deployments.
  • Refined Content Security Policy settings.
  • Added static asset serving logs for deployment troubleshooting.
  • Improved database migration validation and error handling.
v3.6.0
  • Added live preview inside the admin panel.
  • Added a View Public Page action from the admin header.
  • Added link visibility toggles.
  • Added mobile drag-and-drop ordering.
  • Removed sensitive authentication logs.
  • Removed unused Supabase and Firebase code.
  • Fixed duplicate database migration logic.
  • Removed debug logging from PublicLinkCard.
v3.5.1
  • Updated vulnerable frontend, backend, and Docker dependencies.
  • Resolved Dependabot alerts and Docker image CVEs reported at the time of release.
  • Optimized Docker build time by avoiding source builds where precompiled binaries are available.
v3.5.0
  • Added editable profile fields with line-break support in the bio.
  • Added social link controls and profile picture display controls.
  • Added text cards and bulleted lists.
  • Added JSON import/export for links and themes.
  • Added theme controls for page styling, typography, title, meta description, and footer text.
  • Added Docker startup validation for JWT_SECRET.
  • Added optional self-signed HTTPS support with ENABLE_HTTPS=true.

License

MIT License. See LICENSE.txt.

About

Self-hosted Linktree alternative with Docker, SQLite, themes, analytics, and privacy controls.

Topics

Resources

License

Contributing

Security policy

Stars

53 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors