Skip to content

[Feature] Multi-wildcard domains, control plane isolation, 7000-series port standardization, and dashboard domain management #819

Description

@lagmandu

Context

As deployments scale from single-server setups to multi-tenant environments, managing domains, port conflicts, and infrastructure boundaries becomes critical. Currently, OpenShip mixes its internal host containers with user projects, restricts wildcard domains to a single apex, defaults to common developer ports (colliding with local web frameworks), and lacks a dedicated settings tab for the dashboard domain and telemetry.

This proposal establishes a clean boundary between OpenShip's control plane and tenant workloads while expanding domain routing flexibility.


What's being addressed

1. Multi-Wildcard Domains & Collision-Proof Subdomains

  • The Problem: OpenShip currently only allows a single wildcard domain per instance. Teams managing multiple brands, staging tiers, or client environments (e.g. *.staging.acme.com and *.preview.clients.io) cannot register multiple wildcard apexes. In addition, preview subdomains generated purely from raw project names collide when projects share names or are recreated.
  • Proposed Solution:
    • Add a dedicated wildcard_domain schema in @repo/db allowing operators to register, label, and designate a default wildcard apex.
    • Generate collision-proof subdomains (${slug}-${randomHex(6)}.${wildcardApex}) upon project provisioning.

2. Control Plane Workspace Isolation & Self-Destruction Guards

  • The Problem:
    • OpenShip's internal containers (API, Dashboard, Edge) currently surface in the main "Apps & Projects" workspace grid.
    • Operators or team members see "Stop", "Restart", or "Delete" buttons on internal control plane cards. An accidental click terminates the API container, instantly locking everyone out of the web interface and requiring manual SSH intervention on the host VM.
  • Proposed Solution:
    • Exclude appTemplateId === 'openship' by default from GET /api/projects and GET /api/projects/home.
    • Add explicit 403 PROJECT_IS_CONTROL_PLANE rejection guards on POST /api/services/:id/stop, POST /api/services/:id/restart, and DELETE /api/services/:id for internal services.

3. Standardizing Default Internal Ports to 7000-Series (7000-7400)

  • The Problem: OpenShip defaults to ports commonly used by local development servers:
    • 3001: Default fallback for React / Next.js / Vite when 3000 is occupied.
    • 4000: Standard port for Express.js / GraphQL APIs.
    • 5000: Standard for Flask / ASP.NET / local Docker registries.
      Running local developer workloads or containers frequently results in silent port bind collisions.
  • Proposed Solution: Standardize internal control-plane defaults to a dedicated 7000 block with 100-stride spacing (Dashboard: 7000, API: 7100, Web: 7200, SaaS Dashboard: 7300, SaaS API: 7400), leaving common web ports free for user applications.

4. Instance-Level Dashboard Domain & Telemetry in Settings

  • The Problem: Operators previously had to treat OpenShip as a project just to bind a custom domain (e.g. dev.domain.com) to the dashboard or view host resource usage.
  • Proposed Solution:
    • Add a dedicated Settings → Domains & Wildcard tab to manage the Dashboard Root Domain with automated Cloudflare DNS verification.
    • Add GET /api/system/telemetry and mount a live Control Plane Health & Telemetry card in Settings → Instance displaying CPU load average, Node RSS/Heap memory, and system uptime.

5. Hardened Loopback Route Ingress Protection

  • The Problem: Custom ingress rules could attempt to proxy traffic to host loopback addresses (127.0.0.1:7100 / 127.0.0.1:7000), potentially exposing internal control plane APIs.
  • Proposed Solution: Refactor isReservedLoopbackPort and isLoopbackHost in public-endpoints.ts to normalize loopback targets (localhost, 127.0.0.1, ::1, [::1]) and reject any tenant routing rules targeting internal management ports.

Proposed Implementation Breakdown

packages/
 ├── core/
 │    └── src/constants.ts                       # Standardize DEFAULT_PORT (7000, 7100, 7200)
 ├── db/
 │    ├── src/schema/wildcard-domain.ts          # Wildcard domain table schema
 │    ├── src/repos/wildcard-domain.repo.ts      # Wildcard repository queries
 │    ├── drizzle/0121_wildcard_and_dashboard_domain.sql # Drizzle migration
 │    └── src/dump.ts                            # Backup catalogue registration
apps/
 ├── api/
 │    ├── src/modules/domains/wildcard-domain.service.ts # Normalization & collision-proof slugs
 │    ├── src/modules/system/setup.controller.ts # Dashboard domain endpoints
 │    ├── src/modules/system/telemetry.controller.ts     # Live host/process telemetry endpoint
 │    ├── src/modules/services/service.controller.ts     # 403 PROJECT_IS_CONTROL_PLANE guards
 │    ├── src/modules/projects/project.controller.ts     # Exclude control plane from project grid
 │    └── src/lib/public-endpoints.ts            # Hardened loopback proxy guards
 └── dashboard/
      ├── src/pages/settings/domains/DomainsSettingsTab.tsx # Dashboard & wildcard domain UI
      └── src/pages/settings/instance/InstanceInfo.tsx      # Live telemetry & health card

Verification Plan

  1. Multi-Wildcard Domain Routing:
    • Register multiple wildcards (*.staging.acme.com, *.preview.clients.io).
    • Provision projects and verify collision-proof subdomains route through OpenResty ingress correctly.
  2. Control Plane Isolation:
    • Verify OpenShip containers no longer appear in the general projects grid.
    • Attempt to call POST /api/services/:id/stop against an internal service and verify 403 Forbidden.
  3. Port Standardization:
    • Verify dev servers start cleanly on ports 7000/7100 without colliding with local ports 3000, 3001, or 4000.
  4. Dashboard Domain & Telemetry:
    • Configure a custom dashboard domain in Settings and verify DNS auto-provisioning.
    • Verify real-time CPU and memory metrics render accurately on the Instance Info tab.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions