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.
Defaults
Section titled “Defaults”The proxy port depends on the network mode. From shared/src/derived-settings.ts:
| Network mode | Default proxy port | Notes |
|---|---|---|
docker (default) | 443 | The default for install.sh --server |
hybrid | 443 | Same 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:
| Port | Service | Direction | Notes |
|---|---|---|---|
| 8333 | norsk-ctl daemon API + /mcp | Local-only | CLI 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 |
| 22 | SSH | Inbound | To run the installer and operate the box. |
| 80 | HTTP→HTTPS redirect + Let’s Encrypt issuance | Inbound | Bound 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 ingest | Inbound | SRT/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. |
How to change the proxy port
Section titled “How to change the proxy port”The proxy port lives in the proxyPort field of config.yaml. Two ways to set it:
At install or init — --proxy-port N
Section titled “At install or init — --proxy-port N”sudo bash install.sh --server --license /tmp/license.json --ip auto --proxy-port 8443# or, post-install:norsk-ctl init --proxy-port 8443Writes proxyPort: 8443 into config.yaml. The defaults above don’t apply once proxyPort is set.
Edit config.yaml
Section titled “Edit config.yaml”# /etc/norsk-ctl/config.yaml (or ~/.norsk-ctl/config.yaml for --local installs)proxyPort: 8443sudo systemctl restart norsk-ctlPublic host and --ip auto
Section titled “Public host and --ip auto”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:
--public-host <name> (explicit)
Section titled “--public-host <name> (explicit)”Use the exact string you’ll type into the browser — DNS name or IP:
sudo bash install.sh --server --license /tmp/license.json --public-host norsk.example.comPrefer 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:
# clients reach the proxy through `ssh -L 8443:localhost:443`norsk-ctl config set --public-host 127.0.0.1:8443--ip auto (autodetect)
Section titled “--ip auto (autodetect)”sudo bash install.sh --server --license /tmp/license.json --ip autoThe installer probes the public IP by curling these endpoints in order (deployment/install.sh:132-138):
https://api.ipify.orghttps://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.
Neither (prompt)
Section titled “Neither (prompt)”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).
Changing the public host later
Section titled “Changing the public host later”publicHost lives in config.yaml. Editing it requires re-issuing the TLS cert so its SAN matches the new host:
sudo norsk-ctl init --force --public-host new.example.com --cert-source self-signedFor certbot-issued certs, point at the existing letsencrypt path:
sudo norsk-ctl init --force --public-host new.example.com \ --cert-source certbot --domain new.example.com --cert-email ops@example.comPer-instance ingest ports
Section titled “Per-instance ingest ports”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:
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.)