Openship Edge Routing, OpenResty Domain, and TLS Management: Architecture and Configuration
Openship implements a fully-featured edge layer using OpenResty (NGINX + Lua) that handles traffic routing, domain management, and automatic TLS termination through generated NGINX configuration fragments kept in sync with TypeScript constants.
Openship's edge routing, OpenResty domain, and TLS management stack is built on a unified OpenResty layer that runs either containerized via Docker Compose or as a bare-metal process installed by the control plane. The entire edge configuration is derived from shared TypeScript constants to guarantee identical behavior across deployment modes. Understanding these internals is essential for operators who need to debug vhosts, customize proxy behavior, or secure custom domains with Let's Encrypt.
Core Edge Components and Source Files
The edge architecture is defined by a set of TypeScript generators and constants that emit NGINX configuration fragments. These modules ensure that every deployed edge—whether inside a container or on a bare-metal box—uses the exact same directives.
Baked nginx.conf and Configuration Drift Prevention
In packages/adapters/src/infra/edge-baked-conf.ts, the bakedEdgeNginxConf generator assembles a complete nginx.conf by pulling values from shared constants including EDGE_SHARED_DICTS and EDGE_CLIENT_MAX_BODY_SIZE. The container image ships with a pre-generated copy of this file, and a CI test asserts that the generator output matches the baked copy exactly. This mechanism prevents drift between the containerized edge and the bare-metal edge.
Real-IP Handling for Cloudflare and Reverse Proxies
The packages/adapters/src/infra/edge-real-ip.ts module constructs the real_ip configuration block. By default, OpenResty trusts Cloudflare's CIDR ranges and reads the client address from the CF-Connecting-IP header. Operators can override the header name via OPENSHIP_EDGE_REAL_IP_HEADER and append additional trusted proxies. This preserves accurate logging and rate-limiting regardless of the upstream proxy topology.
Unrouted Host Fallback Responses
When a request arrives for a hostname with no deployed application, the edge returns a minimal HTML page defined in packages/adapters/src/infra/edge-not-found.ts. The constant EDGE_NOT_FOUND_HTML contains the sentinel string openship-edge-unrouted, and the content is embedded directly in the default NGINX location / block via EDGE_NOT_FOUND_LOCATION. This fallback works identically in both container and bare-metal deployments.
ACME HTTP-01 Challenges and Default TLS Certificates
TLS management is coordinated through constants defined in packages/adapters/src/infra/openresty-lua.ts. The default HTTP server listens on port 80 and includes a location that proxies ACME HTTP-01 challenges to Certbot's temporary listener. Meanwhile, the HTTPS catch-all block—edgeHttpsDefaultBlock—loads a placeholder self-signed certificate generated at build time, whose path is returned by edgeDefaultCertPaths. Once a real domain is added, the control plane swaps in the Let's Encrypt certificate and reloads the edge.
Shared Lua Memory Zones
OpenResty allocates shared dictionaries for analytics, live-log streaming, and rate-limit counters. The sizes of these lua_shared_dict zones are centralized in EDGE_SHARED_DICTS and emitted by the baked configuration generator in packages/adapters/src/infra/edge-baked-conf.ts. Keeping these sizes identical across container and bare-metal edges prevents out-of-memory mismatches under load.
Domain Onboarding Flow from Registration to HTTPS
Adding a custom domain to Openship triggers a deterministic sequence:
- The user adds the domain through the dashboard or CLI.
- The control plane writes a new vhost file (
<slug>.conf) into the sharedsites-enableddirectory. This file contains aserver_namedirective and includes the real-IP block generated byedgeRealIpConf. - The control plane triggers a configuration reload via
docker exec … nginx -s reloadfor containerized edges ornginx -s reloadfor bare-metal boxes. - OpenResty picks up the new config and begins serving traffic for the domain.
- If TLS is enabled, the edge initiates the ACME HTTP-01 flow, places the resulting certificate at the path defined by
edgeDefaultCertPaths, and updates the vhost.
On renewal or removal, apps/api/src/lib/edge-vhost-repair.ts rewrites vhost files on the fly to keep the edge consistent.
Edge CLI Commands for Operations and Import
The CLI entry point at apps/cli/src/commands/edge.ts exposes several commands for edge management:
| Command | Purpose | Example |
|---|---|---|
openship edge preflight |
Validates that the host can run the OpenResty edge by checking Docker availability, port availability, and required environment variables. | openship edge preflight |
openship edge import |
Imports existing NGINX or OpenResty configurations into the Openship control plane and converts them to the internal format. | openship edge import /etc/nginx/sites-enabled |
openship up --public-url https://example.com |
Starts a self-hosted Openship instance with the edge listening on :80 and :443, automatically handling TLS for the specified domain. |
openship up --public-url https://myapp.example.com |
The docker/docker-compose.yml file orchestrates the full stack, including the OpenResty edge container alongside Postgres, Redis, the API, and the Dashboard.
Practical Code Examples for Edge Configuration
You can programmatically generate the baked configuration, adjust real-IP settings, and create vhosts using the adapters package.
Generate the Baked nginx.conf
import { bakedEdgeNginxConf } from "./infra/edge-baked-conf";
import { writeFileSync } from "fs";
writeFileSync("apps/edge/nginx.conf", bakedEdgeNginxConf());
This writes the fully assembled configuration that mirrors the runtime-patched bare edge.
Add Trusted Proxies at Runtime
process.env.OPENSHIP_EDGE_TRUSTED_PROXES = "10.0.0.0/8,172.16.0.0/12";
import { edgeRealIpConf } from "./infra/edge-real-ip";
console.log(edgeRealIpConf());
The edgeRealIpConf function emits the updated real_ip block with the additional CIDR ranges.
Create a Custom Vhost for a New Domain
import { writeFileSync } from "fs";
import { EDGE_NOT_FOUND_LOCATION } from "./infra/edge-not-found";
const vhost = `
server {
listen 80;
server_name myapp.example.com;
${EDGE_NOT_FOUND_LOCATION}
# other directives (proxy_pass, etc.) will be added by the control plane
}
`;
writeFileSync("/etc/nginx/sites-enabled/myapp.conf", vhost);
After writing the file, the control plane triggers an NGINX reload through apps/api/src/modules/projects/edge-config.service.ts.
Summary
- Openship's edge layer is a unified OpenResty (NGINX + Lua) process that handles all traffic routing, domain management, and TLS termination.
- Configuration parity between containerized and bare-metal edges is enforced by
bakedEdgeNginxConfinpackages/adapters/src/infra/edge-baked-conf.tsand validated in CI. - Real-IP settings, unrouted host responses, and shared Lua dictionary sizes are generated from TypeScript constants to eliminate runtime mismatches.
- Custom domains are onboarded by writing vhost fragments to
sites-enabledand reloading OpenResty, with automatic ACME HTTP-01 certificate provisioning via Certbot. - Edge operations are exposed through the CLI at
apps/cli/src/commands/edge.ts, including preflight checks and configuration import.
Frequently Asked Questions
How does Openship prevent configuration drift between container and bare-metal edges?
The bakedEdgeNginxConf generator in packages/adapters/src/infra/edge-baked-conf.ts produces the complete nginx.conf from shared constants such as EDGE_SHARED_DICTS and EDGE_CLIENT_MAX_BODY_SIZE. The container image includes a pre-generated copy of this file, and a CI test asserts that the generator output matches the baked copy exactly. This guarantees that both deployment modes use identical NGINX directives.
What happens when a request reaches the OpenResty edge for an unrouted domain?
The edge serves a minimal HTML page defined by EDGE_NOT_FOUND_HTML in packages/adapters/src/infra/edge-not-found.ts. This response includes the sentinel string openship-edge-unrouted and is embedded directly in the default location / block via EDGE_NOT_FOUND_LOCATION. It functions identically whether the edge is running inside Docker or on a bare-metal server.
How does Openship handle TLS certificates for custom domains?
The default HTTP server proxies ACME HTTP-01 challenges to Certbot's temporary listener, as configured in packages/adapters/src/infra/openresty-lua.ts. The HTTPS catch-all initially loads a self-signed placeholder certificate from edgeDefaultCertPaths. Once a domain is added, the control plane obtains a Let's Encrypt certificate, updates the vhost, and reloads OpenResty through apps/api/src/modules/projects/edge-config.service.ts.
Can Openship run behind an existing CDN or reverse proxy like Cloudflare?
Yes. The packages/adapters/src/infra/edge-real-ip.ts module configures the real_ip module to trust Cloudflare's CIDR ranges by default and reads the CF-Connecting-IP header. Operators can override the header via OPENSHIP_EDGE_REAL_IP_HEADER and specify additional trusted proxies to preserve correct client IP addresses for logging and rate limiting.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →