This is the production deployment guide for a HomeBrain hub with Caddy as the public edge.
These instructions are valid for a Jetson Orin Nano Super running a supported Ubuntu-based JetPack release. The Jetson path is just the Linux installer with HOMEBRAIN_HOST_PROFILE=jetson, so the same Caddy/MongoDB/systemd flow applies on ARM64.
Jetson Orin Nano:
git clone <your-public-repo-url> HomeBrain
cd HomeBrain
bash scripts/install-jetson.shOther Ubuntu/Debian host:
git clone <your-public-repo-url> HomeBrain
cd HomeBrain
bash scripts/install-linux.shThe installer now:
- installs system packages
- installs Node.js
22.x - installs MongoDB
6.0 - creates
server/.envfromserver/.env.example - backfills required keys into an existing
server/.envon upgrade installs - generates fresh local JWT secrets
- sets
CADDY_ADMIN_URL=http://127.0.0.1:2019 - defaults
ACME_ENVtoproductionfor already-public deployments and tostagingfor first-time local/testing installs - stops
homebrainfirst if it is already running on the host - installs npm dependencies
- ensures native server modules are rebuilt for the active Node.js runtime after a Node major-version change
- repairs
client/distownership before the production build if an earlier deploy left it root-owned - builds the production web app
- optionally bootstraps wake-word training dependencies
- creates and enables
homebrain - installs and enables
caddy-api - seeds the reverse-proxy database state for Caddy management
- seeds the HomeBrain OIDC identity state for the default Axiom SSO client
- configures the HomeBrain Ollama helper, sudoers entry, and service override so the UI can manage Ollama updates and host-side service restarts safely
HomeBrain no longer owns public 80/443. Caddy is the intended public ingress.
After installation:
- Find the hub IP address.
hostname -I- Open HomeBrain locally.
http://<hub-ip>:3000
- Create the first account.
- Continue with
docs/configuration.md.
Once the hub is live, the two main room-hardware paths are:
- Linux voice listeners:
remote-device/README.md - ELECROW ESP32 wall panels:
docs/elecrow-wall-panel.md
Use the Linux listener path for microphones, speakers, and wake-word audio. Use the ELECROW wall panel path for always-on touch and rotary room control over Wi-Fi.
Production:
3000/tcp: internal HomeBrain UI/API upstream80/tcp: Caddy public HTTP ingress443/tcp: Caddy public HTTPS ingress12345/udp: listener auto-discovery
Development only:
5173/tcp: Vite frontend dev server
Check status:
bash scripts/setup-services.sh statusFollow logs:
bash scripts/setup-services.sh logs followShow Caddy logs only:
bash scripts/setup-services.sh logs caddyRestart HomeBrain:
bash scripts/setup-services.sh restartRe-run Caddy bootstrap if needed:
bash scripts/setup-services.sh setup-caddyHealth check:
bash scripts/setup-services.sh healthRepair HomeBrain's privileged helper access for Ollama management:
bash scripts/setup-services.sh refresh-privilegesOn Linux and Jetson hosts, HomeBrain treats Ollama as a host-level dependency with a HomeBrain-managed runtime. The UI uses a narrow privileged helper to install, update, and stop Ollama when needed, then starts a single managed ollama serve process again.
Important paths:
- helper:
/usr/local/lib/homebrain/ollama-host-control.sh - sudoers:
/etc/sudoers.d/homebrain-deploy - systemd override:
/etc/systemd/system/homebrain.service.d/99-ollama-helper.conf
If a host was installed before this flow existed, run bash scripts/setup-services.sh refresh-privileges once, then restart homebrain.
More detail:
The installer creates:
At minimum, verify:
DATABASE_URLJWT_SECRETREFRESH_TOKEN_SECRETCADDY_ADMIN_URLACME_ENV
Recommended additions for public deployment:
HOMEBRAIN_PUBLIC_BASE_URL=https://freestonefamily.com
HOMEBRAIN_EXPECTED_PUBLIC_IP=<your-public-ip>Optional if you want HomeBrain accessible only through Caddy:
HOMEBRAIN_BIND_HOST=127.0.0.1If you still want direct LAN access on :3000, leave HOMEBRAIN_BIND_HOST unset or 0.0.0.0.
Template file:
The repository now also advertises its runtime preference directly:
.nvmrcprefers Node22- root, server, and client
package.jsonfiles declare^20.19.0 || >=22.12.0
For Jetson deployment, Node 22.x is the intended production runtime.
If a Node 22 upgrade leaves serialport unable to load, HomeBrain will now warn but continue. That module is only needed for Node-side direct serial access; the Insteon service can still use its local Python serial-bridge fallback when configured.
This is the recommended production path for the current HomeBrain domain set and future Axiom routing.
On the hub:
bash scripts/setup-services.sh statusYou want both homebrain and caddy-api running.
Edit server/.env:
HOMEBRAIN_PUBLIC_BASE_URL=https://freestonefamily.com
HOMEBRAIN_EXPECTED_PUBLIC_IP=<your-public-ip>Then restart HomeBrain:
bash scripts/setup-services.sh restartCreate or update DNS records so they resolve to the same public IP:
freestonefamily.comwww.freestonefamily.commail.freestonefamily.com
That mail.freestonefamily.com record is the future Axiom hostname. It can exist now even before the Axiom service is live.
Forward public 80 and 443 from your router/firewall to the HomeBrain host.
Open HomeBrain locally at http://<hub-ip>:3000, then go to:
Reverse Proxy / Domains
In the settings card:
- leave
Caddy Admin URLashttp://127.0.0.1:2019 - keep
ACME modeatstagingfirst - set
Expected Public IPv4to your public IP - leave
On-Demand TLSdisabled unless you explicitly need it
Save the settings.
The installer and deploy paths now seed these routes automatically if they do not already exist. In Reverse Proxy / Domains, confirm these records are present and enabled:
-
freestonefamily.com- Platform:
HomeBrain - Upstream:
http://127.0.0.1:3000 - Health check:
/ping - TLS mode:
automatic - Enabled:
true
- Platform:
-
www.freestonefamily.com- Platform:
HomeBrain - Upstream:
http://127.0.0.1:3000 - Health check:
/ping - TLS mode:
automatic - Enabled:
true
- Platform:
Run Validate.
If validation reports DNS or upstream issues, fix those first.
Still in Reverse Proxy / Domains:
- click
Apply Caddy Config - wait for the Caddy status to remain reachable
- browse to
https://freestonefamily.com
Because ACME_ENV=staging, you should expect staging certificates during this test phase.
Browsers will typically show a certificate warning or a Not Secure label in this mode. That is expected until you switch to production ACME.
When staging validation looks correct:
- change
ACME modetoproduction - confirm the mode switch
- save settings
- click
Validate - click
Apply Caddy Configagain
After that, https://freestonefamily.com and https://www.freestonefamily.com should serve through Caddy with production certificates. HomeBrain now pins production ACME issuance to the Let's Encrypt production directory explicitly.
HomeBrain is now ready for Axiom routing even though the Axiom app is not part of this repository.
When the Axiom service exists, run it on an internal upstream such as:
127.0.0.1:3001
Then create or enable this route in Reverse Proxy / Domains:
- Hostname:
mail.freestonefamily.com - Platform:
Axiom - Upstream:
http://127.0.0.1:3001 - Health check:
/ - TLS mode:
automatic - Enabled:
true
Run Validate, then Apply Caddy Config.
At that point:
https://freestonefamily.comroutes to HomeBrainhttps://mail.freestonefamily.comroutes to Axiom
Both can share the same public IP because Caddy routes by hostname.
HomeBrain now acts as an OIDC provider for Axiom. The installer, setup-services.sh update, and Platform Deploy all seed the default Axiom client automatically.
Use these Axiom OIDC settings:
- Issuer:
https://freestonefamily.com - Discovery document:
https://freestonefamily.com/.well-known/openid-configuration - Client ID:
homebrain-axiom - Redirect URI:
https://mail.freestonefamily.com/api/identity/homebrain/callback - Grant type:
authorization_code - Client auth: public client with PKCE
- PKCE: required
- Requested scopes:
openid profile email
What this gives you:
- if you are already signed into HomeBrain in the browser, Axiom can bounce through HomeBrain and come back authenticated without a second password prompt
- if you go directly to Axiom while signed out, HomeBrain will send you to its login page, then resume the authorization request automatically after sign-in
HomeBrain exposes these OIDC endpoints:
/.well-known/openid-configuration/.well-known/jwks.json/oauth/authorize/oauth/token/oauth/userinfo
Terminal path:
bash scripts/setup-services.sh updateThat update path now waits for HomeBrain to come back and re-seeds both reverse-proxy state and OIDC identity state if new managed fields or clients were added by the release.
UI path:
- Open
Platform Deploy - Choose a preset
- Start the deploy job
- Review the job log and health cards
Platform Deploy still works after these Caddy changes because it still restarts only the homebrain app service. During the deploy job it now bootstraps both reverse-proxy state and OIDC identity state before the final restart, while Caddy remains in front and keeps owning public ingress.
- Run the installer.
- Confirm
homebrainandcaddy-apiare running. - Open
http://<hub-ip>:3000. - Create an account.
- Set
HOMEBRAIN_PUBLIC_BASE_URLand your expected public IP. - Point DNS for
freestonefamily.com,www.freestonefamily.com, andmail.freestonefamily.com. - Forward router ports
80and443. - Configure routes from
Reverse Proxy / Domains. - Validate and apply in
staging. - Switch ACME to
production, re-apply, and verify HTTPS.