# Edge & monitoring
URL: https://openship.io/docs/cli/edge.md

Manage the OpenResty edge from the terminal — install and serve :80/:443, take over an existing reverse proxy and import its sites, route domains, apply per-route rules, and read traffic, analytics, and request logs.

The **edge** is the OpenResty reverse proxy Openship runs on ports `:80`/`:443`. It terminates
TLS, routes each hostname to the right container, enforces per-route rules (rate limits, bans,
geo/CIDR access), and — because it already sees every request — counts the traffic that feeds
the Monitoring tab. `openship edge` is the terminal surface for all of that: stand it up, take
over a proxy that's already on those ports, manage domains and rules, and read the analytics it
produces.

<Callout title="New to the edge?" type="info">
This page is the command reference. For a task-level walkthrough — taking over an existing proxy, routing a
domain, protecting a route, watching traffic — start with the [The edge](/docs/guides/the-edge) guide.
</Callout>

<Callout title="The edge vs. the server" type="info">
Two separate things run on a box. The **server** is Openship's API + dashboard (see
[Running & updating](/docs/cli/run)); the **edge** is the public reverse proxy in front of your
apps. `openship up` installs both together. `openship edge` manages just the proxy half and reads
the traffic it records — you'll use it when a proxy is already on `:80/:443`, or to drive
domains / rules / analytics without opening the dashboard.
</Callout>

<Callout title="Linux for the proxy, anywhere for the data" type="info">
Installing and taking over the proxy (`up`, `migrate`, `takeover`, `sites`, `repair`) touches
host ports and containers, so those are **Linux-only**. The control-plane half — `domains`,
`rules`, `traffic`, `analytics`, `logs`, and the interactive panel — talks to the API and works
from any machine (including macOS/desktop), against whichever instance your active
[context](/docs/cli/access) points at.
</Callout>

## When to use it

- **Something else already owns `:80/:443`.** You have nginx / Apache / Caddy on the box and want
  Openship's edge to take over — either importing its existing sites (`migrate`) or just claiming
  the ports (`takeover`).
- **Route a hostname to a port** without building a full project — `edge domains add app.example.com --port 8080`
  registers the host, points it at `127.0.0.1:8080`, and issues a certificate.
- **Protect a route** with a rate limit, an IP/country ban, or a CIDR allow-list — `edge rules add`.
- **Read what the edge is seeing** from the terminal: a traffic overview, per-domain analytics
  (visitors, countries, top paths), or the recent raw request log — `edge traffic` / `edge analytics` / `edge logs`.

Every reporting command also honours the global `--json` flag, so the same data pipes into `jq`
or a script.

## Command summary

| Command | Purpose |
|---|---|
| `openship edge` (no args) | Interactive panel — status, domains, traffic, take-over, and monitoring in one loop. |
| `openship edge status` | Is the edge installed and serving `:80/:443`? |
| `openship edge up` (alias `install`, `start`) | Ensure the edge is up; optionally enable monitoring (built-in analytics DB). |
| `openship edge migrate` | Take over `:80/:443` **and import** the existing proxy's sites. |
| `openship edge takeover` | Free `:80/:443` for the edge — stop whatever holds them (its sites drop). |
| `openship edge sites` (alias `scan`) | List reverse-proxy sites on this host the edge could import. |
| `openship edge repair` (alias `doctor`) | Diagnose why the edge isn't serving; `--fix` resolves a port conflict. |
| `openship edge domains` (alias `domain`) | Domains routed through the edge: list, register on a port, verify SSL, remove. |
| `openship edge rules` | Per-route rules: rate-limit, ban, access control. |
| `openship edge traffic` | Traffic overview for a project (requests, bandwidth, hourly periods). |
| `openship edge analytics` | Per-domain analytics: visitors, countries, top paths. |
| `openship edge logs` | Recent HTTP request logs the edge captured for a project. |

## `openship edge` — the interactive panel

Run `openship edge` with no arguments on a terminal to open a looping panel. It shows the edge's
current state (installed? serving? how many domains) and offers the right actions for where you
are: browse domains, register one, view a traffic overview, bring up or repair the edge, migrate
or take over another proxy, scan for importable sites, and — if there's no server yet — enable
monitoring. Pick an action, do it, and land back on the menu; **Quit** exits.

The panel is a *trusted local tool*. On a desktop / loopback box the API is zero-auth, so it just
makes the call — no token needed. It only asks you to `openship login` if a call actually comes
back unauthorized (a real self-hosted server with an admin), and tells you plainly when the API
isn't reachable rather than showing a dead-end login screen.

```bash
openship edge
```

## `openship edge up`

Ensures the edge container is up and serving `:80/:443`, repairing it if it isn't. With
`--monitoring` it also stands up the built-in Openship server (a bare install with an embedded
database) so the traffic the edge counts has somewhere to land and the `traffic` / `analytics`
commands have something to read. On a box that already has Openship installed, `--monitoring` is a
no-op — monitoring is already available through the running instance.

```bash
# Just make sure the edge is serving
openship edge up

# Serve, and on a port conflict import the existing proxy's sites
openship edge up --migrate

# Also turn on monitoring (installs the built-in server + analytics DB)
openship edge up --monitoring --admin-email you@example.com
```

| Flag | Purpose |
|---|---|
| `--migrate` | On a port conflict, import the existing proxy's sites and take over. |
| `--takeover` | On a port conflict, stop whatever holds `:80/:443` (its sites drop). |
| `--monitoring` | Also enable monitoring: install the built-in Openship server + embedded DB for analytics. |
| `--no-monitoring` | Edge only — skip the monitoring prompt (the headless default). |
| `--admin-name <name>` | Admin display name for a fresh monitoring install. |
| `--admin-email <email>` | Admin email — **required** when enabling monitoring headlessly. |
| `--admin-password <pw>` | Admin password. Prefer the `OPENSHIP_ADMIN_PASSWORD` env var (keeps it out of shell history). |

<Callout title="After enabling monitoring, log in to read it" type="info">
Enabling monitoring creates a local admin, and — like every CLI-installed instance — reading its
data requires a login. Run `openship login` with a PAT from the dashboard, then
`openship edge traffic -p <project>` / `openship edge analytics -p <project>`. The panel and verbs
tell you when auth is what's missing. (Zero-auth without a login is desktop-only.)
</Callout>

## Taking over an existing proxy

If nginx, Apache, or Caddy already holds `:80/:443`, the edge can't bind them until they're freed.
These commands resolve that — and the whole operation is **journaled and rollback-safe**: if a step
fails, it unwinds cleanly rather than leaving you with neither proxy serving.

```bash
# Take over AND bring the old proxy's sites across (recommended)
openship edge migrate

# Just free the ports — the old proxy is stopped and its sites drop
openship edge takeover

# See what would be imported before committing
openship edge sites

# Diagnose why the edge isn't serving; attempt a fix
openship edge repair --fix          # defaults to migrate
openship edge repair --fix --takeover
```

`migrate` reads the existing proxy's virtual hosts, registers each one on the edge (so it keeps
serving), and only then frees the ports. `takeover` skips the import and just stops the occupant.

<Callout title="You don't have to remember to run this" type="info">
When a foreign proxy grabs `:80/:443`, the same "another proxy is here — take over and migrate its
sites?" prompt surfaces automatically during `openship up` and in the bare `openship` control
panel, not only under `openship edge`. Running the commands above is the manual equivalent.
</Callout>

## `openship edge domains`

Domains routed through the edge. `add` registers a hostname and points it somewhere: attach it to an
existing project with `--project` (uses that project's port) **or** bind a brand-new tracked project
to a port with `--port` (exactly one of the two). Registering also verifies DNS and issues a
Let's Encrypt certificate unless you pass `--no-verify`.

```bash
# Route a host straight at a local port (creates a tracked project)
openship edge domains add app.example.com --port 8080

# Attach a host to an existing project
openship edge domains add www.example.com --project prj_123 --primary

# List / remove
openship edge domains list -p prj_123
openship edge domains rm app.example.com -p prj_123
```

| `add` flag | Purpose |
|---|---|
| `-p, --project <id>` | Attach to an existing project (uses its target port). |
| `--port <n>` | Bind a **new** tracked project to `127.0.0.1:<n>`. |
| `--primary` | Mark this domain as the project's primary. |
| `--no-verify` | Skip DNS verification + SSL issuance (just claim the hostname). |

For the full custom-domain / DNS / certificate workflow, see the project-level
[`openship domain`](/docs/cli/projects) command — `edge domains` is the edge-scoped view of the same
routing.

## `openship edge rules`

Per-route edge rules — rate limits, bans, and access control — applied by the proxy before a request
ever reaches your app. Scope a rule to the whole project, one domain (`--domain`), or a path prefix
(`--path`). Pass at least one rule flag; combine as many as you like into a single rule.

```bash
# 20 req/s per client IP on the login path, allowing short bursts
openship edge rules add -p prj_123 --path /login --rate-limit 20 --burst 40

# Block two countries and an abusive IP, returning 403
openship edge rules add -p prj_123 --ban-country RU,CN --ban-ip 203.0.113.7 --block-status 403

# Allow-list an office CIDR — everything else is denied
openship edge rules add -p prj_123 --allow-cidr 198.51.100.0/24

openship edge rules list -p prj_123
openship edge rules rm <ruleId> -p prj_123
```

| `add` flag | Purpose |
|---|---|
| `--path <prefix>` | Scope the rule to a path prefix (default: whole project). |
| `--domain <id>` | Scope the rule to one domain of the project. |
| `--rate-limit <rps>` | Requests/second per client IP before throttling. |
| `--burst <n>` | Burst allowance for `--rate-limit`. |
| `--ban-country <cc>` | Block ISO-2 country code(s) (repeatable / comma-separated). |
| `--ban-ip <ip>` | Block IP address(es). |
| `--deny-cidr <cidr>` | Deny CIDR range(s). |
| `--allow-cidr <cidr>` | Allow-list CIDR range(s) — everything else is denied. |
| `--allow-country <cc>` | Allow-list ISO-2 country code(s) — everything else denied. |
| `--block-status <code>` | HTTP status returned on block (`401/403/404/429/444/451/503`). |
| `--disabled` | Create the rule disabled. |

<Callout title="Rate limits need the real client IP" type="info">
Per-IP rate limits and country rules only work if the edge sees the true client address. If another
reverse proxy (or Cloudflare) sits in front, it must overwrite `X-Real-IP` with the real client IP and
you must run with `--trust-proxy` — see [`openship up`](/docs/cli/run). Openship's own managed edge
handles this for you.
</Callout>

## Viewing monitoring data

This is what makes the edge a product you *watch*, not just plumbing. The proxy counts every request
in shared memory (costing the visitor nothing — the work happens after the response is sent), a
scheduled job moves those aggregates into the database every 30 minutes, and these commands read them
back. All three take `-p, --project` and accept `--json`.

```bash
# Traffic overview: requests, bandwidth, and hourly periods
openship edge traffic -p prj_123

# Per-domain analytics: visitors, countries, top paths
openship edge analytics -p prj_123 --domain app.example.com

# Recent raw request log, and follow it live
openship edge logs -p prj_123 --limit 100
openship edge logs -p prj_123 --follow
```

| Command | Key flags |
|---|---|
| `edge traffic` | `--domain <host>` scope to one domain · `--from` / `--to` window (ISO 8601 or epoch minutes). |
| `edge analytics` | `--domain <host>` · `--from` / `--to` window (default last 7 days). |
| `edge logs` | `--limit <n>` recent entries (max 200) · `--follow` poll and print new entries as they arrive. |

<Callout title="How the numbers get there" type="info">
**The edge counts, the control plane collects.** The proxy increments counters in shared memory
(a few microseconds, after the response is already sent — no database, no I/O on the request path);
a job scrapes those aggregates into Postgres every 30 minutes; these commands read the result. A
visitor's request never touches the API or the database. The same data — traffic, top paths, request
logs — is on the dashboard's Overview and Logs tabs: see [Logs & monitoring](/docs/guides/logs-monitoring).
</Callout>

## Where to next

<Cards>
  <Card title="Running & updating" href="/docs/cli/run" description="up, stop, update — install the server the edge reports into." />
  <Card title="Projects, services & domains" href="/docs/cli/projects" description="init, project, service, and the full domain workflow." />
  <Card title="Logs & monitoring" href="/docs/guides/logs-monitoring" description="The dashboard view of the same traffic, request logs, and analytics." />
</Cards>
