TLS and certificates
Agents verify the server's certificate on every call, as they should. That makes the certificate, and the names and addresses it covers, the most common reason an agent install fails. This page covers what the installer makes, switching encryption on and off, repairing a certificate that misses an address, and giving enrolled agents a new certificate.
HTTPS and lab mode
HTTPS is the default: nginx serves the console, the API and the agents on port 443. Lab mode serves plain HTTP on ports 3000 and 8000, so passwords and tokens cross the network in clear text; it is for an isolated lab only. Agents refuse a plain-HTTP server unless their installer is given --insecure (-Insecure on Windows), which exists for lab use.
Switch encryption on and off
sudo ./lawliet tls status
sudo ./lawliet tls off # asks first; --yes skips the question
sudo ./lawliet tls on
An agent cannot be told a new server address, so the server keeps both doors open and no agent is reinstalled in either direction:
| Encryption on (default) | Encryption off | |
|---|---|---|
| Console and API | https://<address> | http://<address> on port 80 |
| Port 80 | Sends browsers to HTTPS. Still answers the agent API, only for agents that enrolled over plain HTTP. | The whole console and API |
| Port 443 | The console and API | Still up with the same certificate, so agents enrolled over HTTPS keep working |
| New install commands and deployments | https://, with the certificate arguments if it is self-signed | http:// |
Each switch saves .env, the deployment settings and the certificate first, restarts only nginx and the backend, checks the result, and puts the saved configuration back if the check fails. ./lawliet update keeps the state. A plain-HTTP installation (ports 3000 and 8000) is moved behind nginx by tls on, keeping its data, secrets and agents.
- While encryption is off, every console page and the sign-in page carry a red line saying so, the notification centre has a critical item, and
statusanddoctorwarn. Each switch is in the audit trail with who ran it and when. - Turning encryption back on offers to sign every user out and to rotate the agent enrolment secret (both default yes), since both crossed the network in clear. API keys used while it was off should be revoked and reissued.
- Agents still on plain HTTP while encryption is on are a critical finding: an agent's token also signs the commands sent to it. The Agents page lists them; reinstall each with the HTTPS command from
./lawliet token.
Self-signed or your own certificate
./lawliet install asks for the address users and agents will reach, then for a certificate:
- Your own certificate. Give the full chain and the key, in PEM. The installer checks that they match and shows the expiry date.
- Self-signed. RSA-2048, valid 825 days. It names the address you gave,
localhostand this server's own IPv4 addresses (not Docker's bridge addresses). The installer lists what the certificate covers, and warns straight away if the address you gave is a loopback address, which no agent can reach. Browsers warn about a self-signed certificate until it is replaced, and agents must be given a copy of it. - A certificate already present in the deployment is used as it is.
Servers reached by IP address
When an agent connects by IP address, it checks that the certificate carries that address as an IP entry (an IP subjectAltName). A certificate issued only for a host name fails that check, and the install stops with curl error 60, "no alternative certificate subject name matches target ipv4 address". So a certificate for a server reached by IP must list every address agents use, each as an IP: entry, and any host name as a DNS: entry.
./lawliet status, ./lawliet doctor and ./lawliet start list each address the certificate does not cover: certificate does not cover <ip>; run: sudo ./lawliet tls repair. The console's certificate card shows the same.
Repair a certificate with ./lawliet tls repair
sudo ./lawliet tls repair # asks first when agents are enrolled
sudo ./lawliet tls repair --yes # no question, for scripts
It re-issues a self-signed certificate for every address this server is reached by: the deployment address, the server's own IPv4 addresses (container bridges and loopback left out) and localhost, keeping every name the old certificate had. The new certificate is installed the way ./lawliet tls installs one: nginx tests it and reloads, and a pair nginx refuses is replaced by the previous one. The previous pair is kept as a backup readable by its owner only, and the addresses are added to TRUSTED_HOSTS. When nothing is missing it says certificate already covers ... and changes nothing. A self-signed certificate that has expired, or expires within 30 days, is re-issued the same way.
- Agents already enrolled trust the exact certificate they were installed with, and no TLS client accepts a different self-signed certificate in its place. So repair counts them first: with none, it repairs; with some, it lists them, says they will be offline until each is given the new certificate, and asks (default no). Afterwards it prints the command for each host; see below.
- A certificate from a certificate authority is never re-issued. Repair names the missing addresses; ask the CA for a certificate that includes them (an
IP:entry for each address agents use) and install it withsudo ./lawliet tls. - After an update from 1.5.11.s on, the certificate is checked automatically: with no agents enrolled a self-signed certificate is repaired; with agents enrolled the gap is only reported. The check never fails the update and never touches a CA-issued certificate;
--no-cert-repairskips it. - With encryption off, repair still works, because 443 keeps serving the certificate to agents that enrolled over HTTPS; encryption stays off.
Trusted host names and addresses
The server answers only requests addressed to a name or address listed in TRUSTED_HOSTS in .env; any other request gets 403 "Invalid host header". The installer sets it to the address you gave and this server's own IPv4 addresses. ./lawliet tls and ./lawliet tls repair add the names and addresses the certificate covers.
If users or agents reach the server by another name, add it to TRUSTED_HOSTS (and to CORS_ORIGINS for the console) and run ./lawliet start.
Install your own certificate with ./lawliet tls
./lawliet tls shows the current certificate and replaces it with the certificate and key you give it, in PEM. A running nginx tests the new pair (nginx -t) and reloads without dropping connections, and the certificate's names and addresses are added to TRUSTED_HOSTS. If nginx refuses the new pair, the previous certificate and key are put back, nginx goes on serving them, and the command stops with nginx's reason.
For a self-signed certificate, use sudo ./lawliet tls repair instead of making one by hand.
Give agents the certificate
./lawliet tls --export writes lawliet-server.pem. Copy it to each host and pass it to the installer with --ca-cert <path> (-CaCert <path> on Windows). The commands that ./lawliet token and the console's Install agent print already carry the flag when the server uses a self-signed certificate, and an offline package carries the certificate itself. The agent then trusts exactly that certificate, and verification stays on.
Hosts enrolled before a certificate change
Hosts already enrolled show as offline once the server presents a new certificate. Give each the new one without reinstalling: export it with sudo ./lawliet tls --export, copy lawliet-server.pem to the host and run the installer the server serves with the refresh option.
| Host | Command (as root or Administrator) |
|---|---|
| Linux | sudo bash install.sh --refresh-ca --ca-cert /path/to/lawliet-server.pem |
| Windows | powershell -ExecutionPolicy Bypass -File install.ps1 -RefreshCa -CaCert C:\path\to\lawliet-server.pem |
| macOS | Copy the file over /etc/lawliet/server-ca.pem, then sudo launchctl kickstart -k system/com.lawliet.agent |
The refresh checks the agent's server with the new certificate first and changes nothing if that fails, then replaces the agent's trust file (keeping the old one as server-ca.pem.previous) and restarts the agent. The agent keeps its identity; nothing is re-enrolled.

