Skip to content

HTTPS and certificates

Plugboard handles student records, staff credentials and password resets. It should not be served over plain HTTP to anything except localhost during a first look.

Start it with no certificate and it serves plain HTTP and says so. Silence would be worse.

Whatever route you take, set the address people actually type:

Terminal window
PUBLIC_URL=https://helpdesk.yourschool.org
PUBLIC_HOST=helpdesk.yourschool.org

This is not cosmetic. It is the base for every link the product emails, the single sign-on return address, and the list of addresses the browser is allowed to talk to. Set it to an internal name and you will send tracking links your families cannot open.

https://x, https://x/ and http://x count as three different values, so copy it exactly.

In order of how little work they are.

Your situationDo this
Publicly reachable, ports 80 and 443 openUse the bundled Caddy option. It gets a free certificate and renews it, with nothing further to do
School network you do not control, no inbound portsUse the bundled Cloudflare Tunnel option. Nothing is opened; it dials out
You already have a wildcard certificatePoint Plugboard at the file
Your school runs its own certificate authorityPoint Plugboard at the file
You already run nginx, IIS or similarKeep using it, and send traffic to Plugboard

One command each, on the Docker stack:

Terminal window
# Free certificate, renewed automatically
docker compose --env-file .env -f docker-compose.prod.yml --profile caddy up -d
Terminal window
# No inbound ports at all
docker compose --env-file .env -f docker-compose.prod.yml --profile tunnel up -d

The tunnel is the one to reach for on a school network where opening a port means a change request. Set TUNNEL_TOKEN first.

Point Plugboard at the files and restart. Both forms are read from disk at startup, so renewing means replacing the file and restarting.

A PKCS#12 file, which is what Active Directory Certificate Services and most Windows tooling produce:

Terminal window
TLS_PFX_FILE=C:\certs\helpdesk.pfx
TLS_PFX_PASSWORD=...

Or PEM, from an internal authority or a purchased wildcard:

Terminal window
TLS_CERT_FILE=/etc/ssl/certs/helpdesk.crt
TLS_KEY_FILE=/etc/ssl/private/helpdesk.key
TLS_CA_FILE=/etc/ssl/certs/chain.crt

Include the chain file if your issuer gives you one. Without it a site usually works in a desktop browser and fails on Android and on phones, which is a confusing thing to be debugging six months later when nobody remembers the install.

TLS 1.2 is the floor, HTTP redirects to HTTPS, and the strict-transport header is sent.

If your school already runs nginx, IIS or an appliance, keep using it. Start Plugboard with no ingress option so it listens internally, then send it traffic:

  • /api/ to the API on port 4000
  • everything else to the web app on port 3000

One setting matters. The path /api/events/ carries the desk’s live updates. Your proxy must pass it through without buffering, or updates arrive in bursts every thirty seconds instead of immediately and the product looks broken. In nginx that is proxy_buffering off; for that location, with a long read timeout. In IIS, turn off response buffering for that path in the Application Request Routing settings.

Plugboard trusts the standard forwarded-protocol headers, so it knows it is behind HTTPS.

The usual free-certificate check needs port 80 reachable from the internet, which a lot of school networks will not allow. Two ways round it:

  • Cloudflare Tunnel, which needs no inbound ports at all.
  • A DNS-based check, which proves you control the domain with a DNS record instead. Caddy supports this with the module for your DNS provider.

If the desk should not be reachable from outside the school, point the name at a private address inside and at nothing outside. Use your own certificate authority, or the DNS-based check, since the port 80 method needs to be publicly reachable.

You will also want ALLOW_PRIVATE_EGRESS=1 so service monitors can check addresses on your own network. Plugboard blocks those by default so a monitor cannot be pointed somewhere it should not go.

  • PUBLIC_URL set to the address people type, with https://
  • Certificate in place, including the chain file if you were given one
  • HTTP redirects to HTTPS
  • /api/events/ not buffered, if you run your own proxy
  • Renewal handled. The bundled options renew themselves; your own certificate needs a diary entry
  • Tested from a machine that is not the server, and from a phone
SymptomCause
Browser warns about the certificateSelf-signed, or the chain is missing
Works on a desktop, fails on AndroidMissing chain. Same fix
The console loads but never updatesA proxy is buffering /api/events/
Errors in the browser about blocked requestsPUBLIC_URL does not match the address bar exactly
Emails link to the wrong addressPUBLIC_URL still points at the old one. Restart after changing it
“HTTPS not started” in the logWrong certificate path, or wrong PFX password. The log names the file it tried
Certificate never issuesPort 80 is not reachable. Use the tunnel or a DNS-based check