Skip to content

Ports & host detection

norsk-ctl binds three classes of port: the daemon’s local API (talked to by the CLI), the proxy front door (what your browser hits), and per-instance ingest ports (SRT, RTMP, etc. that your pipelines listen on). This page is the single source of truth for the defaults, how to change them, and how the installer picks the public host that goes into the TLS certificate.

The proxy port depends on the network mode. From shared/src/derived-settings.ts:

Network modeDefault proxy portNotes
docker (default)443The default for install.sh --server
hybrid443Same binding as docker; set --network-mode hybrid at install / init

TLS is always on; the insecure-HTTP mode was removed (#280).

Plus, regardless of network mode:

PortServiceDirectionNotes
8333norsk-ctl daemon API + /mcpLocal-onlyCLI and the norsk-ctl mcp stdio bridge talk to this. Do NOT expose to the public internet. The nginx proxy enforces a loopback bypass on /mcp — external /mcp requests are blocked
22SSHInboundTo run the installer and operate the box.
80HTTP→HTTPS redirect + Let’s Encrypt issuanceInboundBound by default for the redirect (a user typing http://<host>/ is bounced to HTTPS) and used by certbot HTTP-01. Opt out with --no-http-redirect at install/init when 80 is owned by something else on the host — certbot then becomes unavailable (the HTTP-01 challenge needs 80).
5001+ (typical)Media ingestInboundSRT/RTMP/etc. — configured per instance, published from media containers to the host. 5001 is the SRT default (backend/src/docker/constants.ts:62); your pipeline can listen on any port you give it.

The proxy port lives in the proxyPort field of config.yaml. Two ways to set it:

Terminal window
sudo bash install.sh --server --license /tmp/license.json --ip auto --proxy-port 8443
# or, post-install:
norsk-ctl init --proxy-port 8443

Writes proxyPort: 8443 into config.yaml. The defaults above don’t apply once proxyPort is set.

# /etc/norsk-ctl/config.yaml (or ~/.norsk-ctl/config.yaml for --local installs)
proxyPort: 8443
Terminal window
sudo systemctl restart norsk-ctl

The public host is the hostname or IP your clients type into the browser. It serves two roles:

  • It’s baked into the self-signed TLS certificate’s Subject Alternative Name (SAN), so the browser doesn’t reject the cert as for-the-wrong-host.
  • It’s the prefix the proxy advertises for per-instance URLs (Studio, API, etc.).

You set it at install time. Three options:

Use the exact string you’ll type into the browser — DNS name or IP:

Terminal window
sudo bash install.sh --server --license /tmp/license.json --public-host norsk.example.com

Prefer this when:

  • You have a DNS name (it’ll appear correctly in the cert SAN).
  • You’re on a private network and the public-IP probe won’t find a usable address.
  • You’re behind NAT and the box’s outbound IP differs from what clients reach.

The value must match what you type into the browser exactly, because it prefixes every advertised instance URL. If clients reach the box on a non-standard port, include it--public-host 127.0.0.1:8443. A host carrying an explicit port is used verbatim; without one, the proxy port is appended. This is what makes a tunnelled setup work, where clients connect to a forwarded local port rather than to the box’s own address:

Terminal window
# clients reach the proxy through `ssh -L 8443:localhost:443`
norsk-ctl config set --public-host 127.0.0.1:8443
Terminal window
sudo bash install.sh --server --license /tmp/license.json --ip auto

The installer probes the public IP by curling these endpoints in order (deployment/install.sh:132-138):

  1. https://api.ipify.org
  2. https://ifconfig.me

Each call has a 5-second timeout. The first one that responds with a non-empty IP wins, and that IP becomes --public-host for init. If both fail, the install aborts with couldn't auto-detect a public IP — pass --ip <host>.

--ip auto is most useful on a public cloud VM where the box has a single public IP and you don’t have a DNS name yet.

If you don’t pass either flag and the install is interactive, it prompts: Public host/IP clients use to reach this box (blank = localhost only). Leave blank for a localhost-only install (useful for evaluation on a desktop with no remote clients).

publicHost lives in config.yaml. Editing it requires re-issuing the TLS cert so its SAN matches the new host:

Terminal window
sudo norsk-ctl init --force --public-host new.example.com --cert-source self-signed

For certbot-issued certs, point at the existing letsencrypt path:

Terminal window
sudo norsk-ctl init --force --public-host new.example.com \
--cert-source certbot --domain new.example.com --cert-email ops@example.com

Ingest ports aren’t a global config — they’re declared per instance when you launch it (in the workflow YAML, or via the Studio UI). The media container --publishes each declared port to the host, so they need to be open in the host firewall.

To see which ingest ports a running instance is using, open the instance overview in the web UI, or query the daemon API:

Terminal window
curl -sf https://<host>/api/instances/<id> | jq '.media.ingestPorts'

(The CLI talks to the daemon via the local :8333 socket; --host <url> lets you point it at a remote one if needed.)