All chapters

Deployment

Huntress is one self-contained program. The web server, the database, the listeners, the Pulse app, the video tools and the detection model are all inside the executable, so there is nothing else to install: no database server, no message broker, no runtime. You decide where it runs.

Platforms#

Supported platforms
PlatformRuns asTypical use
Linux x64A systemd serviceServers, virtual machines, mini PCs
Linux arm64A systemd serviceRaspberry Pi-class computers, mostly as a Huntress Edge
Windows x64A Windows serviceServers and workstations; PowerShell 7 for the installer

There is no official container image. The program is self-contained and keeps all state under one directory (HUNTRESS_DATA_DIR), so it can be run in a container if you provide the image and a persistent volume; this is not tested or supported.

Installing#

The installers verify the release before installing anything: the channel manifest carries an ECDSA signature and every archive a SHA-256 hash. They set up the program as a service, the updater as a second service, and a versioned folder layout that makes updates and rollbacks safe.

Linux#

sudo ./install.sh                       # a server, from the stable channel
sudo ./install.sh --role edge           # a Huntress Edge
sudo ./install.sh --channel beta        # another release channel
sudo ./install.sh --bundle /path/to/dir # offline: a folder with manifest.json, manifest.json.sig and the archive

It needs systemd, curl (unless offline), openssl, tar, python3 and sha256sum. It creates a huntress user that is a member of the serial-port group so a Zigbee dongle can be used, enables huntress (or huntress-edge) and huntress-updater, and waits for the health check. An older flat install is migrated.

Windows#

./Install-Huntress.ps1                  # a server
./Install-Huntress.ps1 -Role edge       # a Huntress Edge
./Install-Huntress.ps1 -Bundle D:\huntress-1.4.0   # offline

Run it in PowerShell 7 as administrator. The services are Huntress (or HuntressEdge) and HuntressUpdater. Releases are not yet code-signed for Windows, so SmartScreen may warn the first time.

Folders#

Folder layout
ItemLinuxWindows
Releases/opt/huntress/releases/<version>/C:\Program Files\Huntress\releases\<version>\
Active release/opt/huntress/current (a link)C:\Program Files\Huntress\current (a junction)
Configuration/etc/huntress/C:\ProgramData\Huntress\config\
Data/var/lib/huntress/C:\ProgramData\Huntress\data\

Updates replace only releases and the link. Your configuration and data are never touched. HUNTRESS_CONFIG_DIR and HUNTRESS_DATA_DIR move them elsewhere.

First start#

  1. Copy your public address into AppBaseUrl (for example https://huntress.example.com). Password-reset links, Pulse links and passkeys are built from it, never from the request.
  2. Set Registration:InvitationKey to a long random value. Registration is closed while it is empty.
  3. Put a TLS reverse proxy in front (next section).
  4. Open the site, register, and sign in. The first organisation is the system organisation (System:AdminTenantId, 1 by default): its Owners and Admins approve updates.
  5. Configure outbound mail (Notifications:Smtp) if you want rule e-mails and password resets.

Put these in appsettings.Production.json in the configuration folder, or in environment variables with __ for each level (Registration__InvitationKey). Do not put secrets in the shipped appsettings.json. See Configuration.

Network and ports#

Ports
PortWhatNotes
5000Web interface, Hunt API, edge linksListens on 127.0.0.1 in the shipped service, for the reverse proxy.
443The same, through your reverse proxyTLS ends here.
1883MQTT brokerPlain TCP. HuntressMqtt:Enabled.
25SMTP receiverPlain TCP. Needs CAP_NET_BIND_SERVICE on Linux (the unit grants it). HuntressSmtp:Enabled.
2000SIA DC-09Plain TCP. HuntressTcp:Enabled, HuntressTcp:SiaPort.
2001Contact IDPlain TCP. HuntressTcp:CidPort.

A listener that cannot bind its port (in use, or no permission for port 25) is reported on /health and does not stop the server.

Reverse proxy and TLS#

Put a proxy that terminates TLS in front of the web port. It is not optional in practice: the sign-in cookie is Secure, API keys require HTTPS, and browsers allow passkeys, installing Pulse, location and service workers only on HTTPS.

  • A ready Caddy configuration is in deploy/Caddyfile. It terminates TLS with automatic certificates and holds requests for up to 30 seconds while Huntress restarts, so an update is a short pause instead of an error page.
  • Other proxies must pass WebSocket upgrades and allow connections that stay open for hours: the interface, edge links and live video all use them.
  • Set AppBaseUrl to the public address and AllowedHosts to its host name.
  • The proxy on the same machine is trusted to set X-Forwarded-For and -Proto. A proxy on another machine must be listed in ForwardedHeaders:KnownProxies or KnownNetworks; headers from anyone else are ignored, so clients cannot spoof their address. Real client addresses matter for logs and rate limits.

Huntress Edge#

A Huntress Edge is the same program, started with --edge on a small computer at a remote site. It makes only outbound connections to your server, over WebSocket (wss when the server address is https), so nothing needs opening on the site's firewall. It is how Huntress reaches cameras, Zigbee dongles and devices on a private network.

What an edge does
JobHow it works
CamerasPulls each camera's RTSP stream locally and sends the server the live video and snapshots. The server tells the edge each camera's address and settings after it connects.
Object detection and clipsAnalyses snapshots on the edge when the server asks and the edge can, and keeps the clip ring locally, uploading only the clip. See Object detection.
ZigbeeRuns a coordinator dongle at the site and relays it to the server.
HTTP relayMakes the web calls of HTTP outputs on the site's own network for the server.
UpdatesFollows its own server, never ahead of it; by default it updates itself between 02:00 and 05:00 and waits while someone is watching a camera.

Setting up an edge#

  1. On the server, create the camera (a Live Camera sensor with its RTSP URL) and generate its edge secret on its settings page. For Zigbee or an HTTP relay, create the coordinator or relay on the Devices page.
  2. On the edge computer, install with the edge role (see above).
  3. Write the connection in appsettings.Production.json in the edge's configuration folder (below) and restart huntress-edge.
  4. Open the camera in the interface: it should go from Connecting to Live.

The edge's configuration; keep only the sections you need

{
  "HuntressEdge": {
    "HuntressUrl": "https://huntress.example.com",
    "Cameras": [
      { "Token": "<camera sensor token>", "Secret": "<edge secret>" }
    ],
    "ZigbeeGateways": [
      { "Token": "<coordinator token>", "Secret": "<edge secret>", "SerialPort": "/dev/ttyUSB0" }
    ],
    "HttpRelays": [
      { "Token": "<relay token>", "Secret": "<edge secret>", "AllowedHosts": [ "192.168.1.50" ] }
    ]
  }
}
  • Each camera is served by one edge at a time; a second connection for the same camera is refused. The secret is sent as X-Edge-Secret and checked in constant time before the connection opens.
  • Limits. HuntressEdge:Snapshots shapes the pictures (MaxWidth 1280, JpegQuality 4); HuntressEdge:Clips caps the memory of clip rings (MaxRingMegabytes 24, MaxRingSeconds 60, MaxConcurrentUploads 2).
  • When the link drops the edge reconnects by itself, waiting 2 seconds, then longer, up to 60. It does not queue events: live video is dropped while it is disconnected, only the newest snapshot is kept, and Zigbee reports during an outage are lost. The radio and the cameras keep running.
  • Health. On the edge, http://127.0.0.1:5080/edge-health is Unhealthy when no camera has been connected for five minutes, and /edge-status shows version, viewers and the detector.
  • An edge that serves only Zigbee or HTTP relays and no camera cannot yet update itself through its server; update it with the installer.

One server, many sites#

The usual shape for a service provider or a multi-site operator is one central server and an edge at each site that has cameras or devices behind NAT. Set LocalEdge:Enabled=false on a server in a data centre so it never opens RTSP streams itself; a camera with an edge secret is always left to its edge anyway. Each site's people and operators use the one server's web address. There is no replication between servers.

Running without internet#

The server and its interface run entirely without internet access: every script, style and font is bundled, and nothing phones home. Four things are worth planning for:

  • Maps draw their base layer from OpenStreetMap, loaded by the viewer's browser. Offline the base map is blank; markers and zones still draw. Camera-image regions need no map.
  • Updates poll a release channel on GitHub. Set Updates:Mode=Off, point Updates:ManifestUrl at an internal location, or install from an offline bundle: put manifest.json, manifest.json.sig and the archive in <DataDir>/update/inbox/. The signature is still verified.
  • E-mail needs an SMTP server you can reach, and password resets and rule e-mails need it.
  • Clocks must agree. Encrypted DC-09 frames must be stamped within seconds of the server's time, schedules and rules use it, and an edge refuses requests past their expiry.

Storage planning#

  • Pictures. At the default archive interval (every 30 seconds) a camera stores roughly 0.3 GB a day, about 10 GB over the default 30 days of retention. Every second would be about 30 times that.
  • Clips. Capped by Clips:MaxTotalGigabytes (20 by default); no new clip is started below Clips:MinFreeDiskMegabytes (2,048).
  • Readings and events. Small, kept 90 days by default.
  • Detection uses processor time rather than storage; it is capped at half of a processor by default.

Command-line modes#

Command line
CommandWhat it does
HuntressRuns the server.
Huntress --edgeRuns a Huntress Edge: cameras, Zigbee and HTTP relays, no interface and no database.
Huntress --updaterRuns the privileged update service.
Huntress --backup [dir] [--include-blobs]Writes a consistent copy of the database. See Operations.
Huntress --preflightMigrates a copy of the database, health-checks, and exits. The updater uses it before switching versions.
Huntress --version, --version-jsonPrints the version, the schema level and the edge protocol.
Connection lost
Attempting to reconnect…