Skip to main content
RunBook Academy

OPNsenseVIII · Management Plane SecurityManagement Plane Security

HTTPS and TLS certificates for the GUI

Intermediate⏱ ~14 minopensslcurlsslyze

What you'll learn

  • Explain why HTTP for the GUI is a production anti-pattern
  • Issue or import a certificate for the GUI from an internal CA or ACME
  • Harden the TLS profile by disabling weak ciphers and old protocols
  • Enable HSTS and recognise its trade-offs for a management endpoint

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

The OPNsense GUI runs over HTTPS by default. That part is easy. What is harder is making the TLS configuration production-grade: a real certificate (not the self-signed default), modern protocol versions only, strong cipher suites only, and the small set of hardening headers that turn a working HTTPS endpoint into a defended one.

This lesson covers why HTTP for the GUI is never acceptable, the certificate choices a production firewall has, the TLS profile that meets a modern security baseline, and the HSTS trade-off specific to a management endpoint.

Why HTTP for the GUI is never acceptable

The OPNsense GUI carries the credentials that control the entire firewall. Every login, every API call, every form submission crosses the TLS connection. If that connection is plaintext, an attacker on the management network path can:

  1. Steal credentials. The login form submits the username and password over the same connection. A passive observer sees the password in cleartext.
  2. Steal the session cookie. The PHPSESSID cookie is the session token. An attacker who captures it can hijack the session without knowing the password.
  3. Inject traffic. Without integrity protection, an attacker on the path can rewrite form submissions, inject JavaScript, or redirect the operator to a phishing login.

HTTP for the GUI is unacceptable even on a private management VLAN. The argument “it is a trusted network” is the same argument that has been wrong for every other internal-only service that ended up breached. Management networks are not as trusted as they look — a compromised jump host, a misconfigured switch, or a misrouted cable can put an attacker on the path.

Certificate choices

Three certificate sources are valid for a production firewall GUI.

Internal CA

The most common production pattern is an internal CA. The operator runs a small CA (OpenSSL, step-ca, Microsoft AD CS, HashiCorp Vault PKI), issues a certificate for the firewall GUI hostname, and distributes the CA certificate to operator workstations via Group Policy, MDM, or manual install.

The internal CA pattern has these properties:

  • Browsers and CLI tools trust the certificate because the CA certificate is in their trust store.
  • The certificate can have a long validity (5–10 years for the CA, 1–2 years for the leaf), reducing renewal pressure.
  • The CA can issue certificates for any hostname that resolves internally — useful for split-horizon DNS.

The certificate request is a standard CSR. OPNsense generates the private key and CSR for you under System → Trust → Certificates.

ACME / Let is Encrypt

ACME (Automated Certificate Management Environment) issues short-lived certificates (90 days) from a public CA. The advantage is zero operator intervention after setup; the disadvantage is that the certificate is for a public hostname that resolves on the public Internet.

ACME for a firewall GUI is awkward because the GUI is usually on a private hostname that is not publicly resolvable. The workarounds:

  • Use a public hostname for the GUI (e.g. fw.example.com) and rely on split-horizon DNS to resolve it to the private IP on the management network. ACME works on the public hostname. The certificate is valid for both contexts.
  • Use ACME DNS-01 challenge if your DNS provider supports it. This works without exposing port 80 to the Internet.

OPNsense ships the os-acme-client plugin for this. The plugin handles renewal automatically.

Public CA manual

For low-volume estates, manually purchasing a certificate from a public CA works but has a renewal overhead that grows quickly. The manual path is fine for a single firewall; it does not scale to a fleet.

Read-only / Safeopenssl s_client
$ openssl s_client -connect fw.example.com:443 -servername fw.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
subject=CN = fw.example.com
issuer=O = Example Internal CA, CN = Example Internal Root
notBefore=Aug  1 00:00:00 2026 GMT
notAfter=Aug  1 00:00:00 2027 GMT

Illustrative output

Hardening the TLS profile

OPNsense default TLS profile is acceptable but not strong. The hardening is to disable old protocols and weak ciphers and to set the cipher order to the server preference.

The configuration lives under System → Settings → Administration → SSL Certificate and System → Settings → Administration → SSL Cipher Suites. The production baseline:

  • Protocols: TLS 1.2 and TLS 1.3 only. Disable TLS 1.0 and TLS 1.1 (deprecated by IETF in RFC 8996). Disable SSLv3 and SSLv2 (long deprecated).
  • Ciphers (TLS 1.2): AEAD ciphers only — AES-GCM and ChaCha20-Poly1305. Disable CBC ciphers (vulnerable to BEAST, Lucky 13). Disable RC4, 3DES, and any export-grade cipher.
  • Ciphers (TLS 1.3): the TLS 1.3 cipher suites are negotiated by the client and the server preference order applies only to the few choices that exist (AES-GCM, ChaCha20-Poly1305). The defaults are fine.
  • Forward secrecy: required. PFS means the session key is derived from an ephemeral key exchange (ECDHE) so a leaked server private key does not decrypt past sessions. All modern TLS 1.2 ciphers support ECDHE; the configuration is to prefer them.
  • OCSP stapling: enable. OCSP stapling lets the firewall fetch the certificate revocation status from the CA and staple the response into the TLS handshake. This avoids the privacy and latency cost of the browser doing the OCSP lookup.

The verification after hardening is to scan the GUI with a tool like sslyze or testssl.sh and confirm the result. The expected output:

TLS 1.2: enabled
TLS 1.3: enabled
TLS 1.0: not offered
TLS 1.1: not offered
Certificate: trusted, hostname matches, not expired
OCSP stapling: supported

If the scan shows any weak cipher, an old protocol, or an untrusted certificate, the hardening is incomplete.

HSTS for a management endpoint

HTTP Strict Transport Security (HSTS, RFC 6797) tells the browser: “for this domain, never speak HTTP”. The browser remembers the HSTS policy for the configured max-age and refuses to connect over HTTP, even if the user types http:// or follows an HTTP link.

For a public website, HSTS is uncontroversial. For a management endpoint, the trade-off is different:

  • Benefit: an attacker cannot downgrade the connection to HTTP via a man-in-the-middle that strips the Location: https:// redirect.
  • Cost: if the certificate expires or the configuration breaks, browsers refuse to connect at all. There is no way to fall back to HTTP to recover. An operator with a certificate problem cannot reach the GUI from a browser that has cached HSTS for the domain.

The production pattern is to enable HSTS with a moderate max-age (e.g. 6 months) and to keep an out-of-band recovery path (console access, SSH, or serial) that does not depend on HTTPS working. The HSTS policy should never include includeSubDomains unless every subdomain of the management hostname has working HTTPS.

The browser-side warning for HSTS errors is explicit. An operator who sees “NET::ERR_CERT_AUTHORITY_INVALID” with HSTS enforced cannot click through — the browser will not let them. This is the intended behaviour and it is why recovery paths matter.

Summary

  • HTTP for the GUI is never acceptable. Even on a private management network, the management network is not as trusted as it looks.
  • Replace the self-signed certificate with one that chains to a trusted CA — internal CA, ACME, or a public CA.
  • Harden the TLS profile: TLS 1.2 and 1.3 only, AEAD ciphers only, forward secrecy, OCSP stapling.
  • Enable HSTS with a moderate max-age. Keep an out-of-band recovery path that does not depend on HTTPS.
  • Verify with openssl s_client and a TLS scanner after every configuration change.

Knowledge check · 4 questions

  1. Q1. You have an OPNsense firewall with the default self-signed GUI certificate. Operators routinely click through the browser warning because the firewall is theirs. What is the most important reason to replace the self-signed certificate?

  2. Q2. HTTP for the OPNsense GUI on a private management VLAN is acceptable because the management VLAN is trusted.

  3. Q3. Which of the following are valid certificate sources for a production OPNsense GUI? Select all that apply.

  4. Q4. You enable HSTS on the OPNsense GUI with max-age of one year and includeSubDomains. The certificate for the management hostname expires before you can renew it. What is the consequence?

Passing score: 75%. Answers are checked in this browser.