Skip to content
SSL certificates Issue, renew and manage TLS certificates — Let's Encrypt, wildcard / DNS-01, Cloudflare Origin and custom paid certs.

SSL certificates

MZPanel issues and renews TLS certificates for the sites on a server, and shows each domain’s certificate state next to its DNS health. It lives in the DNS & TLS section of a server (/servers/:id/dns-tls) — the old /servers/:id/ssl deep-link still redirects here. The agent runs certbot/openssl on the box; the private key never leaves the server. Standard Let’s Encrypt issue and renew are available on all plans.

  1. Open a server and go to DNS & TLS. Each domain shows a combined row: its DNS health (does it resolve here? is it proxied?), its SSL/TLS state (valid / expiring / expired / none), the Certificate issuer + expiry, and toggles for HTTPS (force redirect) and Proxy.
  2. Click a domain to open its Manage drawer. The drawer suggests the right strategy from the DNS signal — direct-to-box domains get Let’s Encrypt, proxied domains get a Cloudflare Origin cert recommendation.
  3. Click Issue certificate. For a domain that points straight at the server, MZPanel obtains a Let’s Encrypt certificate over the HTTP-01 challenge and reloads Nginx.
  4. The row flips to a valid certificate with days-remaining, and auto-renew turns on automatically for Let’s Encrypt certs.
  • Renew now — re-run issuance for a domain immediately. For a Let’s Encrypt cert it’s a real renew; for a self-signed / origin cert the button reads Re-issue (auto) and re-detects the right method.
  • Auto-renew — toggle per domain. It applies only to Let’s Encrypt certs (self-signed / Cloudflare-origin certs don’t renew via certbot, so the toggle is hidden for them).
  • Force HTTPS — the HTTPS toggle redirects HTTP → HTTPS for the domain. It’s disabled until a certificate exists.
  • Delete — remove a domain’s certificate (reversible — you can re-issue any time).
  • Wildcard (*.example.com) — one cert that covers every subdomain via the DNS-01 challenge (HTTP-01 cannot issue wildcards). Wildcards require the domain’s zone connected through a Cloudflare token, and are issued and listed from the fleet-level DNS providers connection, not this per-domain drawer.
  • Advanced — custom or paid certificate (the CustomCertPanel in the Manage drawer, three options):
    • Cloudflare Origin Certificate — free, up to 15-year cert signed by Cloudflare for the edge↔origin hop. Best for proxied domains; needs a connected Cloudflare token.
    • Upload a certificate — paste a cert + key you already hold (migrated / corporate). The key is passed through and never stored by MZPanel.
    • Generate a CSR — the box makes a private key (which stays on the box) and a CSR; you buy a cert from any CA, then paste the signed cert back to install it.
  • Bulk actions — select multiple domains and Renew SSL, or set Force HTTPS / Cloudflare proxy across all selected domains at once, with a live progress count.

The DNS & TLS row list is read from MZPanel’s per-server inventory cache (the ssl inventory kind), so it renders instantly even when the box is offline. Every mutation dispatches an ssl.* job to the agent, which runs it natively:

ActionJobAgent runs
Issuessl.issuessl issue <domain> --json (smart HTTP-01 issuer)
Renewssl.renewssl renew [<domain>] --json
Deletessl.deletessl delete <domain> --json
Auto-renewssl.auto-renewssl auto-renew <domain> on|off --json
Force HTTPSssl.https-redirectssl https-redirect <domain> on|off --json

The smart issuer digs the apex: if it points here, it issues Let’s Encrypt; if it’s Cloudflare-proxied, it installs a self-signed origin cert; otherwise it skips. Certificates and their metadata live on the box (/etc/letsencrypt/, /etc/mz/ssl/<domain>/), and Let’s Encrypt certs auto-renew on the server’s own timer before expiry.

The wildcard, CSR, upload and Cloudflare Origin flows are control-plane orchestrated (routes under /v1/dns/*), because they need a secret that must stay off the box — the Cloudflare token. The key-split keeps each secret where it belongs:

  1. The box generates the private key + CSR (ssl gen-csr <domain> [--wildcard]). The private key never leaves the server.
  2. The control plane runs the ACME order, writing the _acme-challenge TXT record through your Cloudflare connection (which holds the token), validates, and finalizes with the box’s CSR.
  3. Only the signed certificate chain is sent back and installed (ssl install-cert <domain> --b64 <chain>), then Nginx reloads and the temporary challenge record is cleaned up.

Wildcard certs are tracked and auto-renewed by the control plane like any other certificate.

Every SSL action maps to an mz command on the box — the same engine the dashboard drives. SSH in and run them directly, or let an on-box AI (ClaudeCode) run them:

Terminal window
mz ssl list --json # every cert on the box
mz ssl issue example.com --json # Let's Encrypt via HTTP-01
mz ssl renew example.com --json # renew one (omit domain = renew all)
mz ssl auto-renew example.com on --json # toggle auto-renew
mz ssl https-redirect example.com on --json # force HTTP → HTTPS

The wildcard / paid-cert path also has on-box helpers — mz ssl gen-csr <domain> [--wildcard] to make the CSR and mz ssl install-cert <domain> --b64 <chain> to install a signed chain — though the dashboard normally drives these through the control plane so the Cloudflare DNS-01 step is automated. See The mz CLI and the command catalog.

  • DNS first, always. “Certificate won’t issue” is almost always the domain not resolving to this server. Check the DNS column in the row before retrying.
  • Wildcard and Origin certs need a connected Cloudflare token. Without a connected zone, the wildcard / Origin actions are gated with a “connect Cloudflare” prompt rather than failing silently. Cloudflare integration is a paid-tier feature.
  • Auto-renew is Let’s Encrypt-only. For self-signed or Cloudflare-origin certs the toggle is hidden — use Re-issue (auto) to refresh them instead.
  • Force HTTPS needs a cert first. The HTTPS toggle stays disabled until the domain has a valid certificate; issue one, then flip it.
  • Docker app domains fall back. The native engine ports issue/renew/delete for standard WordPress-site vhosts; a domain that resolves to a Docker app (proxy vhost) is handled by a different code path — issuance still works but behaves per the app’s proxy block.
  • Let’s Encrypt rate limits. LE limits issuance per registered domain. If you’re testing repeatedly you’ll hit them; automatic renewals are scheduled to stay well clear.
  • Actions need the agent online. The row list renders from cache when the server is offline, but issuing, renewing and installing certs require a live agent.
  • Sites — the domains whose certificates you manage here.
  • Server overview — at-a-glance HTTPS status per server.
  • The mz CLI — driving the box from the command line.
  • API reference — automating cert flows from the control plane.