Skip to content
Betts BoardHome
Docs navigation

Getting started

HTTPS

Push notifications, PWA install, and the camera scanner need a secure context. Three ways to get one.

The board works over plain HTTP on your LAN, and most of it works well that way. Three features do not, because browsers gate them behind a secure context.

What needs a secure context

Feature Why the browser requires HTTPS
Push notifications Service workers and the Web Push API are secure-context only
Installing to a home screen (PWA) The install prompt requires a secure context
Camera barcode scanner getUserMedia is secure-context only

Everything else — the calendar, chores, recipes, meal planning, shopping lists, photos, wish lists, TV mode, the API — works fine over http://your-server:3000.

localhost counts as a secure context, but that only helps the machine running the board. The kitchen tablet reaching it over the LAN does not get the exemption.

One related setting: when you do serve the board over HTTPS, set NUXT_SESSION_COOKIE_SECURE to true so the session cookie is only ever sent encrypted. It defaults to false because LAN deployments are plain HTTP. See Configuration.

Option 1: the Caddy sidecar

docker-compose.yml ships with a commented-out Caddy service. Uncomment it, set your domain, and uncomment the caddy-data volume at the bottom:

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports: ["80:80", "443:443"]
    command: caddy reverse-proxy --from board.example.com --to betts-board:3000
    volumes:
      - caddy-data:/data

volumes:
  betts-data:
  caddy-data:

Then:

docker compose up -d

Caddy obtains and renews certificates automatically. This needs a real domain name pointing at the host, and ports 80 and 443 reachable for the ACME challenge.

Option 2: an existing reverse proxy

If you already run Traefik, Nginx Proxy Manager, or Caddy in front of other services, point it at port 3000 and let it terminate TLS. Nothing in the board needs to know it is behind a proxy.

One exception, and only one: if that proxy is the sole route to the container, you may set BETTS_TRUSTED_PROXY=1 so the unlock rate limit reads the client address from the last X-Forwarded-For element instead of the socket. Leave it unset if the container is also reachable directly — the header is client-writable, and an attacker who can choose their own rate-limit bucket has no rate limit at all.

Option 3: Tailscale, with no domain

If you do not have a domain and do not want one, Tailscale gives every device on your tailnet an HTTPS-capable address with no certificate work:

tailscale serve --bg 3000

Devices on the tailnet reach the board over HTTPS. This is the least infrastructure of the three, at the cost of the board being reachable only from the tailnet.

Verifying it worked

Load the board over https:// and check the three gated features:

  • The browser offers Add to Home Screen or an install button.
  • Settings → Notifications offers Notify on this device instead of saying push notifications aren't available here.
  • The barcode scanner in the pantry opens the camera rather than reporting it is unavailable.

On iOS specifically, notifications only work once the board has been added to the home screen — Safari does not deliver web push to a normal tab.

If any of these still misbehave, see Troubleshooting.

Edit this page on GitHub