Skip to content
Browse the docs

Self-hosting

TLS and the root certificate

How an on-premises Crunu server gets a TLS certificate without the internet, how to hand out the root certificate to browsers and agents, and what to protect.

Last updated

On this page

An on-premises server needs a TLS certificate that the computers of your network trust, without asking a public certificate authority on the internet. The installer gives you two ways: the internal certificate authority of Caddy, which is the default, or a certificate your company issues.

Available from Crunu 6.3.0. Read Install Crunu in your own network first.

The internal certificate authority

With --tls internal, Caddy, the proxy in front of the server, runs its own certificate authority. It issues the certificate for the server's name, or for its IP address, and renews it by itself. Nothing goes to the internet.

Browsers and agents trust the server only once they trust the root certificate of that authority. The installer exports it to deploy/crunu-root.crt. To export it again, or into another file:

Shell
sh deploy/export-ca.sh --env-file deploy/.env --out crunu-root.crt

It prints the SHA-256 fingerprint of the root and the commands that install it on each system:

Text
Root certificate: crunu-root.crt
SHA-256 fingerprint: 3F:A9:52:0B:…:6E:C2:71 — compare it on every machine before you install the certificate there.

Install the root on each system

Compare the fingerprint on every machine before you install the file there:

Shell
openssl x509 -in crunu-root.crt -noout -fingerprint -sha256
SystemCommand
Debian, Ubuntusudo cp crunu-root.crt /usr/local/share/ca-certificates/crunu-root.crt && sudo update-ca-certificates
RHEL, Fedorasudo cp crunu-root.crt /etc/pki/ca-trust/source/anchors/ && sudo update-ca-trust
macOSsudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain crunu-root.crt
Windows, as administratorcertutil -addstore -f Root crunu-root.crt
Chrome on Linuxcertutil -d sql:$HOME/.pki/nssdb -A -t C,, -n crunu-root -i crunu-root.crt
Firefoximport it in the certificate settings, or set security.enterprise_roots.enabled to use the system roots
crunu agentinstall.sh … --ca-file crunu-root.crt, or CRUNU_CA_FILE
The server itselfCA_FILE in deploy/.env

Check from any computer of the network:

Shell
curl --cacert crunu-root.crt https://vault.kiteline.example/releases/latest

It prints the version. Without --cacert, before the root is installed, curl stops with error 60: the certificate can't be verified.

Clocks matter

The internal certificate authority issues certificates for 12 hours and renews them well before they expire. A machine whose clock is off by hours rejects a valid certificate. Keep the server and every machine synchronized with the time server of your network.

doctor judges the certificate by its lifetime: for a 12-hour certificate it warns under about three hours left and fails under about an hour, and shows the time left to the minute. Sign-in also fails when the server clock is more than 2 minutes off; the Server clock line of doctor reports it. See Monitoring and doctor.

A certificate of your company

When your company issues server certificates, give the installer the certificate and its key:

Shell
sh install.sh --origin https://vault.kiteline.example \
  --tls file --tls-cert /etc/crunu/tls/cert.pem --tls-key /etc/crunu/tls/key.pem \
  --ca-file /etc/crunu/tls/company-ca.pem
  • The certificate is a PEM file with its chain, and it must cover the name of --origin. The settings check reports it otherwise.
  • The key is a PEM file without a passphrase. It must belong to root and have mode 600.
  • Caddy doesn't renew a certificate you supply. Replace the files before it expires and restart Caddy with docker compose restart caddy.
  • --ca-file names the root of your company's certificate authority. The server trusts it for its own HTTPS requests, such as webhooks and the keys of a CI system in your network, and the agent command the installer prints carries it.

Hand out the root of your company only if the machines don't trust it yet.

Passkeys need a name

If --origin uses an IP address, everything works except passkeys: browsers allow them only for a DNS name. People sign in with their password and an authenticator app instead. Give the server a name in your network's DNS to use passkeys.