# Network & remote access

## Ports

Fregata's default listeners:

| Port | Service | Bound to | Notes |
| --- | --- | --- | --- |
| `8971` | nginx → Frigate web UI + HTTP API | `0.0.0.0` | **HTTPS** by default (self-signed cert). Set `tls.enabled: false` in `config.yml` for plain HTTP. |
| `5000` | nginx → Frigate API (internal) | `127.0.0.1` (default) or `0.0.0.0` | Loopback-only by default. Set `FREGATA_EXPOSE_INTERNAL_PORT=1` to expose to your LAN. Plain HTTP, **no authentication**. If port 5000 is already taken (e.g. by macOS AirPlay Receiver), Fregata automatically uses port `5050` instead — see below. |
| `1984` | go2rtc admin UI | `127.0.0.1` (default) or `0.0.0.0` | Loopback-only by default. Set `FREGATA_EXPOSE_GO2RTC_PORT=1` to expose to your LAN. Plain HTTP, **no authentication**. |
| `8554` | go2rtc RTSP re-stream | `0.0.0.0` (default) or `127.0.0.1` | LAN-exposed by default. Set `FREGATA_EXPOSE_RTSP_PORT=0` to lock it to loopback-only. Plain RTSP, **no authentication by default** — see below to add a username/password. |
| `8555` | go2rtc WebRTC | `0.0.0.0` | Needed for low-latency live view from outside the Mac. |

The HA integration only needs `8971`. Most users don't think about
the others.

:::caution[For Port 5000: Use `127.0.0.1:5000`, not `localhost:5000`]
Fregata's port 5000 listener binds only
`127.0.0.1` (IPv4) by default. If macOS's **AirPlay Receiver** is enabled
`http://localhost:5000/...` can silently land on AirPlay Receiver
instead of Fregata, while `http://127.0.0.1:5000/...` reaches Fregata
correctly. Always use the explicit `127.0.0.1` address — never
`localhost` — when scripting against this port.
:::

## Reaching it from another device on your LAN

Fregata is happy to serve `8971` to anything on your LAN. Just open
`https://<mac-ip>:8971` from a different device — the first visit shows
a self-signed-certificate warning (the same one you click through on
`localhost`). To avoid the warning on a trusted LAN, set
`tls.enabled: false` in `config.yml` and use `http://<mac-ip>:8971`.

A couple of practical notes:

- **Use a hostname, not an IP.** Bonjour gives you `<mac-name>.local`
  for free; bookmarking that survives DHCP shuffles. Set the
  hostname in **System Settings → General → Sharing → Local
  hostname**.
- **macOS firewall.** If you've enabled it
  (**System Settings → Network → Firewall**), the first inbound
  connection to Fregata triggers the standard "allow incoming
  connections" prompt. Allow it once and the rule sticks.

## Putting Fregata behind a reverse proxy

A common setup: Caddy or Traefik on a NAS or small Linux box,
terminating TLS, and proxying to the Mac. The minimum Caddyfile:

```
cameras.your-house.example {
    reverse_proxy http://10.0.1.42:8971
}
```

Caddy gets you a Let's Encrypt cert, HTTP/2, websocket upgrade
(needed for live MSE/WebRTC), and a clean URL.

:::tip[Turn Fregata's own TLS off behind a proxy]
Fregata serves HTTPS with a **self-signed** cert by default, and you
don't want two layers of TLS. Set `tls.enabled: false` in
`~/Fregata/config/config.yml` and restart, so Fregata serves plain
HTTP on `8971` (reachable only by your proxy and `localhost`) and the
proxy terminates real TLS — that's what makes the `http://…:8971`
upstream above correct.

If you'd rather leave Fregata on HTTPS, point the upstream at
`https://…:8971` and tell the proxy to skip upstream cert
verification — the cert is self-signed (Caddy:
`transport http { tls_insecure_skip_verify }`).
:::

## Exposing it to the public internet

Short answer: **don't, unless you absolutely mean to**.

Long answer: if you do, the bare minimum:

1. Put it behind a real reverse proxy with TLS (Caddy, Traefik,
   Cloudflare Tunnel).
2. Keep Frigate's authentication on. It's enabled by default, and the
   admin password was set in the welcome wizard (see
   [Your dashboard sign-in](/getting-started/installation/#your-dashboard-sign-in)).
   You can confirm it in `config.yml`:
   ```yaml
   auth:
     enabled: true
   ```
3. Restrict by source IP at the proxy if you can.
4. Don't expose `8554` (RTSP) or `1984` (go2rtc admin) to the
   internet under any circumstance. Neither has authentication by
   default.

The reasonable middle path for "I want to check my cameras from my
phone" is **Tailscale or a similar mesh VPN**: install on the Mac
and on your phone, hit `https://<tailscale-ip>:8971` from anywhere
(click through the self-signed warning once). The Tailscale tunnel is
already encrypted end-to-end, so if you'd rather skip the warning, set
`tls.enabled: false` and use `http://<tailscale-ip>:8971`. No public
exposure, near-zero attack surface.

## Mac sleep and Wake-On-Demand

**Fregata keeps the system awake while it's running.** As soon as
the menu-bar status reads *Running*, the supervisor takes a
`ProcessInfo` activity assertion with `.idleSystemSleepDisabled`
and holds it until Frigate stops, errors out, or you quit the app.
You don't need to touch System Settings; the display is still free
to sleep, only the system itself stays awake.

This means the boring 24/7 install case — [Mac mini](https://www.amazon.com/Apple-2024-Desktop-Computer-10%E2%80%91core/dp/B0DLBTPDCS) in a closet,
Fregata launched at login, never restarted — just works.

Caveats worth knowing about:

- **A laptop that closes its lid still sleeps.** Lid closure is a
  hardware-level signal that overrides every software assertion.
  If you need 24/7 detection, run on a desktop or use clamshell
  mode with an external display attached.
- **The activity is released on `.error` and `.stopping`.** A
  Fregata that crashed or was stopped by you doesn't strand the
  Mac awake.
- **Belt-and-braces:** if you want the same behavior even when
  Fregata isn't running, **System Settings → Energy Saver /
  Battery → "Prevent automatic sleeping when display is off"**
  (desktop) or "Prevent automatic sleeping on power adapter"
  (laptop).
- **`caffeinate` command or the `Amphetamine` app** are still useful to prevent your Mac from sleeping when Fregata isn't yet running.

## Using the API from local automation tools

Tools like [Node-RED](https://nodered.org/) or custom scripts that run on your
LAN can talk to Fregata's HTTP API. There are two ways to do it:

### Option A — Port 8971 with a Bearer token (recommended)

This is the standard path and keeps authentication in place.

1. POST to `http://<mac-ip>:8971/api/login` with your credentials:
   ```json
   { "user": "admin", "password": "your-password" }
   ```
2. The response body contains a JWT. Store it in a Node-RED flow variable
   or script environment.
3. Add `Authorization: Bearer <token>` to every subsequent request.

Tokens are valid for 24 hours by default. To keep a script running
indefinitely, re-POST to `/api/login` on a timer (every 23 hours is safe).

Alternatively, set `auth.enabled: false` in `config.yml` — port 8971
then requires no credentials at all, which may be simpler if the network
is fully trusted.

### Option B — Port 5000 with `FREGATA_EXPOSE_INTERNAL_PORT=1`

Port 5000 is nginx's internal proxy. It has no authentication middleware —
requests arrive at the API already labelled as admin. By default it only
accepts connections from the same Mac. Setting the environment variable
opens it to your whole LAN.

:::danger[No authentication — everyone on your LAN gets admin access]
Any device that can reach port 5000 can read your recordings, change your
config, and control your cameras with no login. Only enable this on a
private network you fully control (home LAN behind a router). Do **not**
enable it on shared, public, or semi-trusted networks.
:::

To enable, add `FREGATA_EXPOSE_INTERNAL_PORT=1` in
**Settings → Environment Variables** and restart Fregata. A warning
appears in the Fregata log every time Fregata starts while the flag is set,
so you always have a visible reminder that the port is open.

Point your automation tool at `http://<mac-ip>:5000/api/…` — no
`Authorization` header needed.

:::note[Port 5000 already in use? Check for AirPlay Receiver]
macOS's **AirPlay Receiver** (System Settings → General → AirDrop & Handoff)
permanently binds port 5000 — and 7000 — on all interfaces whenever it's
turned on, which collides with the LAN-exposed listener above. You do
**not** need to disable AirPlay Receiver to work around this: Fregata
detects the conflict at startup and automatically serves the same
unauthenticated endpoint on **port `5050`** instead, while port 5000 itself
stays loopback-only.

This automatic fallback only applies when `FREGATA_EXPOSE_INTERNAL_PORT=1`
is set. Without it, port 5000 stays loopback-only and there's no bind
conflict to detect — but AirPlay Receiver can still shadow it on the
IPv6 side; see [Use `127.0.0.1:5000`, not `localhost:5000`](#ports) above.

Check the Fregata log for a line like:

```
FREGATA_EXPOSE_INTERNAL_PORT is set, but port 5000 is already bound by
<process> (commonly macOS's AirPlay Receiver). Falling back to port 5050
for LAN-exposed unauthenticated access instead; port 5000 itself stays
loopback-only.
```

If that line appears, point your automation tool at port `5050` instead of
`5000` — everything else (no `Authorization` header needed) stays the same.
If `5050` is also taken on your network, set `FREGATA_INTERNAL_PORT_FALLBACK`
to a free port of your choice in **Settings → Environment Variables** (it
can't be a port Fregata uses internally — see the
[environment variables reference](/reference/environment-variables/#fregata_internal_port_fallback)
for the full list).
:::

### Option C — Port 1984 with `FREGATA_EXPOSE_GO2RTC_PORT=1`

This one's for tools that need to talk to **go2rtc directly** — reading or
changing restream config, or pulling an RTSP/WebRTC feed — rather than
going through Frigate's API. Most automation should use Option A or B
instead; reach for this only if go2rtc itself is what you need.

:::danger[No authentication on go2rtc's admin API]
go2rtc has no login of its own. Anyone who can reach port 1984 can read
and change your stream configuration and pull camera feeds directly. Only
enable this on a private network you fully control.
:::

To enable, add `FREGATA_EXPOSE_GO2RTC_PORT=1` in
**Settings → Environment Variables** and restart Fregata, then point your
tool at `http://<mac-ip>:1984/api/…`. Unlike port 5000, there's no
conflict fallback to worry about — go2rtc runs as its own process, so a
failed bind only affects go2rtc, and port 1984 isn't known to collide with
anything on macOS.

### Option D — Port 8554, locking it down with `FREGATA_EXPOSE_RTSP_PORT=0`

Port 8554 is go2rtc's RTSP restream, and unlike the other ports on this
page it's **open to your LAN by default** — tools that want to **pull the
RTSP restream directly** (VLC, Home Assistant's RTSP camera platform,
another NVR) can connect to `rtsp://<mac-ip>:8554/<camera_name>` with no
extra configuration.

:::danger[No authentication on the RTSP restream, by default]
The RTSP feed has no login of its own by default. Anyone who can reach
port 8554 can watch (and, for cameras with two-way talk configured,
potentially control) your camera streams directly. If you don't need this
from another machine, lock it down; if you do need LAN access, add a
username/password (below) instead of leaving it open.
:::

To restrict it to loopback-only, add `FREGATA_EXPOSE_RTSP_PORT=0` in
**Settings → Environment Variables** and restart Fregata. A warning
appears in the Fregata log every time Fregata starts while the port is
locked down, so you always have a visible reminder. Same posture as port
1984 — no conflict fallback to worry about, since go2rtc runs as its own
process and port 8554 isn't known to collide with anything on macOS.

To add a username/password instead of locking the port down entirely, set
`go2rtc.rtsp.username`/`password` in `config.yml`:

```yaml
go2rtc:
  rtsp:
    username: "admin"
    password: "pass"
```

Clients then connect with `rtsp://admin:pass@<mac-ip>:8554/<camera_name>`.
This is go2rtc's own credential check, independent of Frigate's
`auth.enabled` and separate from the username/password your cameras use
upstream.

## Custom go2rtc stream sources

go2rtc can build a stream by running a command on your Mac — an `exec:`
source (usually a custom `ffmpeg` pipeline), or an `echo:`/`expr:` source
that shells out to compute the stream URL. These enable genuinely useful
setups: splitting a dual-fisheye camera, burning in a `drawtext` timestamp,
or GPU-accelerated rotation (go2rtc's built-in `#rotate` is CPU-only, so
rotation is done with a VideoToolbox `exec:` pipeline). By design, though,
they run arbitrary local commands.

:::danger[Restricted by default]
Fregata **rejects `exec:`, `echo:`, and `expr:` stream sources by default**,
matching upstream Frigate. If your `config.yml` defines one, that stream is
**removed from the generated go2rtc config** and a line is written to the
Frigate log naming it — so a camera that quietly disappears from live view
after you add a custom source has a matching explanation in the log:

```text
go2rtc stream 'my_cam' uses a restricted source (echo/expr/exec), disabled
by default for security; removing it. Set GO2RTC_ALLOW_ARBITRARY_EXEC=true
to allow.
```

The same default-deny covers the `{ url: … }` map form and the
`PUT /go2rtc/streams` admin API.
:::

### Allowing custom sources

If you genuinely need one, set
[`GO2RTC_ALLOW_ARBITRARY_EXEC=true`](/reference/environment-variables/#go2rtc_allow_arbitrary_exec)
in **Settings → Environment Variables** (menu-bar tray), then restart Fregata
— environment-variable changes take effect only when Frigate starts. This is
the Fregata equivalent of the `environment:` block you'd use with Frigate on
Docker.

The `exec:` streams Fregata generates for *itself* — the birdseye restream
and the adaptive-live rungs — are always allowed; this switch gates only the
sources you write into `go2rtc.streams`.

### The `{{output}}` token and brace-doubling

Stream values are expanded with Python's `str.format()` before go2rtc sees
them, so you can reference `{FRIGATE_*}` environment variables directly (this
is upstream Frigate's behavior). The catch: **every literal `{` or `}` in the
value must be doubled.** That is why go2rtc's RTSP output placeholder is
written `{{output}}` — it collapses to the `{output}` token go2rtc fills in —
and why an ffmpeg expansion like `drawtext`'s `%{localtime}` has to be written
`%{{localtime}}`.

```yaml
go2rtc:
  streams:
    front_custom:
      # {{output}} -> {output}; {FRIGATE_CAM_PW} is filled from the environment
      - "exec:ffmpeg -hwaccel videotoolbox -i rtsp://user:{FRIGATE_CAM_PW}@10.0.0.5/main -c:v h264_videotoolbox -f rtsp {{output}}"
```

A value that isn't a valid format string — an un-doubled `{output}`, a bare
`%{localtime}`, an empty `{}` — is dropped with an explanatory log line rather
than passed through raw (an un-collapsed brace would reach ffmpeg literally and
the camera would silently 404-loop). Brace-doubling is required whether or not
`GO2RTC_ALLOW_ARBITRARY_EXEC` is set — the env var only decides whether a
successfully-expanded restricted source is kept.

## Ports for Home Assistant

If you're running HA on a different host, see the
[Home Assistant guide](/guides/home-assistant/) — the integration
needs to reach `8971` and (if you've enabled it) MQTT on whatever
broker you're using.
