SSL certificates can be valid for at most 199 days. By 15 March 2027 the limit becomes 99 days, for DigiCert certificates from 24 February 2027. Read more →

Fortinet ACME certificates: FortiGate, FortiMail and FortiWeb

FortiOS 7.6.3 and later fetches and renews the certificate itself with built-in ACME and EAB. Older FortiGate and FortiMail/FortiWeb get it from a proxy host.

How it works

  1. Check firmware and AutoDNS EAB needs FortiOS 7.6.3 or later. Create the CNAME for _dnsauth pointing to FairSSL AutoDNS.
  2. Create the ACME certificate object Create the certificate object in the FortiGate CLI with the EAB Key ID and HMAC key from the ACME tab in the control panel.
  3. Issue and check FortiGate contacts FairSSL's ACME server and validates via AutoDNS. The certificate object must show Status: OK.
  4. Bind to services Bind the object to SSL VPN and optionally admin HTTPS. The bindings follow on renewal.

← All guides

FortiOS 7.6.3 and later ships a built-in ACME client with External Account Binding, so FortiGate can fetch and renew certificates from FairSSL on its own. Older FortiGate versions use a proxy host running Lego or simple-acme that pushes the certificate in over SSH. Both approaches are covered here.

Supported versions

FortiGateVersionsFortiOS 7.6.3 and newerRuns onThe device itselfACME clientThe device’s built-in ACME client with EAB
FortiGateVersionsFortiOS before 7.6.3Runs onWindows Server 2016 or newer, or 2012/2012 R2 with WMF 5.1 (PowerShell 5.1)ACME clientsimple-acme 2.4.0+ (FairSSL edition, .NET 10 included) + Posh-SSH, CredentialManager
FortiGateVersionsFortiOS before 7.6.3Runs onA Linux server that pushes the certificate to the deviceACME clientlego 5.0.4+
FortiMailVersionsThe guide sets no version limitRuns onWindows Server 2016 or newer, or 2012/2012 R2 with WMF 5.1 (PowerShell 5.1)ACME clientsimple-acme 2.4.0+ (FairSSL edition, .NET 10 included) + Posh-SSH, CredentialManager
FortiMailVersionsThe guide sets no version limitRuns onA Linux server that pushes the certificate to the deviceACME clientlego 5.0.4+
FortiWebVersionsThe guide sets no version limitRuns onWindows Server 2016 or newer, or 2012/2012 R2 with WMF 5.1 (PowerShell 5.1)ACME clientsimple-acme 2.4.0+ (FairSSL edition, .NET 10 included) + FortiWeb REST API, CredentialManager

Which approach should you use?

Recommended FortiOS 7.6.3+

Native ACME on FortiGate

FortiGate runs the ACME client itself. You register a local certificate object with EAB keys and FortiOS handles issuance and automatic renewal. No extra host required.

Go to native setup →
Fallback Anything before 7.6.3

Proxy via Lego or simple-acme

A small Linux or Windows host issues the certificate and pushes it to FortiGate via SSH or REST API. The same pattern also works for FortiMail and older FortiWeb, neither of which has native ACME.

Go to proxy setup →

Native ACME (FortiOS 7.6.3+)

FortiGate's built-in ACME client supports External Account Binding, which is the requirement for fetching certificates from a commercial CA like FairSSL. Everything happens in the CLI.

Step 1: Verify firmware

Log in to FortiGate via SSH or the GUI console and check the version. EAB support requires 7.6.3 or later.

get system status

Step 2: Configure FairSSL AutoDNS

Log in to your FairSSL control panel, go to AutoDNS and create a CNAME for _dnsauth.<your-domain> pointing at the FairSSL DNS server. AutoDNS answers the ACME challenge itself, so FortiGate does not need port 80 open to the internet. See the full AutoDNS guide.

Step 3: Create the local ACME certificate object

Grab the EAB KID and HMAC key from the ACME tab in your FairSSL control panel. Replace the placeholders below and run the commands in the FortiGate CLI.

config vpn certificate local
    edit "fairssl-vpn-cert"
        set enrollment acme
        set acme-ca-url https://fairssl.dk/acme
        set acme-eab-key-id YOUR_EAB_KID
        set acme-eab-key-hmac YOUR_EAB_HMAC
        set acme-email acme-client@fairssl.dk
        set acme-domain vpn.example.com
        set acme-auth-url "http://vpn.example.com/.well-known/acme-challenge"
        set auto-regenerate-days 30
        set auto-regenerate enable
    next
end

auto-regenerate-days 30 means FortiGate will try to renew 30 days before expiry, which is safe for both 90-day and 47-day certificates. Set acme-domain to the exact FQDN the certificate is for. FortiGate's built-in ACME flow is intended for a single FQDN; use the proxy approach for wildcards or multi-SAN.

Step 4: Issue the certificate

execute vpn certificate local generate "fairssl-vpn-cert"

FortiGate contacts the FairSSL ACME server, validates ownership via AutoDNS and fetches the certificate. The whole flow normally finishes in under 30 seconds.

Step 5: Verify status

get vpn certificate local | grep -A 3 "fairssl-vpn-cert"

Expect Status: OK and a validity period matching the certificate lifetime (typically 47-90 days).

Step 6: Bind the certificate to services

Use the local certificate object for SSL VPN, admin HTTPS or other services. You can bind the same object to multiple services. All bindings get the renewed certificate automatically.

# SSL VPN
config vpn ssl settings
    set servercert "fairssl-vpn-cert"
end

# Admin HTTPS (optional)
config system global
    set admin-server-cert "fairssl-vpn-cert"
end

Verify with FairSSL's SSL scanner that the right certificate is being served on the public FQDN.

Proxy setup (FortiGate < 7.6.3, FortiMail, older FortiWeb)

When the appliance cannot run ACME itself, we issue the certificate on a separate Linux or Windows host and push it over via SSH or REST API. The Linux + Lego variant is the most flexible and is also used for FortiMail and older FortiWeb.

Linux host with Lego and SSH

A small Linux server (Debian, Ubuntu or RHEL) issues the certificate via Lego v5.0.4+ and pushes the PEM files to FortiGate over SSH using sshpass. FairSSL's commands require Lego v5.0.4 or newer: early v5 versions had registration and hook problems, and older v4 commands do not match these examples.

# 1. Install Lego and sshpass

arch=$(dpkg --print-architecture)
case "$arch" in amd64|arm64) ;; *) echo "Adjust arch"; exit 1 ;; esac
version=$(curl -fsSL https://api.github.com/repos/go-acme/lego/releases/latest \
  | sed -n 's/.*"tag_name": "\(v[^"]*\)".*/\1/p' | head -1)
curl -fL "https://github.com/go-acme/lego/releases/download/${version}/lego_${version}_linux_${arch}.tar.gz" \
  | sudo tar -xz -C /usr/local/bin lego
sudo apt-get install -y sshpass
sudo install -d -m 0700 /etc/ssl/fortigate

# 2. Create deploy script (save as /usr/local/bin/fortigate-deploy.sh)

#!/bin/bash
set -euo pipefail
FGT_IP="10.0.0.1"
FGT_USER="admin"
FGT_PASS="YOUR_SSH_PASSWORD"
CERT_NAME="fairssl-vpn-cert"

CERT=$(cat "$LEGO_HOOK_CERT_PATH")
KEY=$(cat "$LEGO_HOOK_CERT_KEY_PATH")
SSH="sshpass -p $FGT_PASS ssh -T -o StrictHostKeyChecking=no $FGT_USER@$FGT_IP"

$SSH <<EOF
config vpn certificate local
edit "$CERT_NAME"
set private-key "$KEY"
set certificate "$CERT"
next
end
config vpn ssl settings
set servercert "$CERT_NAME"
end
EOF

# 3. Issue the certificate (EAB keys only needed on first run)

sudo /usr/local/bin/lego run \
  --domains "vpn.example.com" \
  --server https://fairssl.dk/acme \
  --eab --eab.kid YOUR_EAB_KID --eab.hmac YOUR_EAB_HMAC \
  --accept-tos --email acme-client@fairssl.dk \
  --http --http.webroot "/var/www/html" \
  --path "/etc/ssl/fortigate" \
  --deploy-hook "/usr/local/bin/fortigate-deploy.sh"

# 4. Cron renewal, run daily at a random time

# /etc/cron.d/lego-fortigate (example)
17 04 * * * root /usr/local/bin/lego run \
  --domains "vpn.example.com" \
  --server https://fairssl.dk/acme \
  --accept-tos --email acme-client@fairssl.dk \
  --http --http.webroot "/var/www/html" \
  --path "/etc/ssl/fortigate" \
  --renew-days 7 \
  --deploy-hook "/usr/local/bin/fortigate-deploy.sh"

Lego v5+ runs run daily and uses ARI to decide when to renew. If the ACME server is unreachable or ARI does not flag a renewal, it falls back to renewing when 7 days remain. The deploy hook only fires when an actual renewal happens.

Windows host with simple-acme

If you do not have a Linux server, run the setup on Windows with simple-acme and Posh-SSH. Install FairSSL's simple-acme build (pre-configured with the right settings and ships Deploy-FortiGate.ps1 in the Scripts folder).

# PowerShell, Run as Administrator

Install-Module Posh-SSH, CredentialManager -Force -Scope CurrentUser

New-StoredCredential -Target "FortiGate-acme-user" `
  -UserName "admin" -Password "YOUR_SSH_PASSWORD" -Persist LocalMachine

cd C:\simple-acme
wacs.exe --verbose --baseuri "https://fairssl.dk/acme" `
  --eab-key-identifier YOUR_EAB_KID --eab-key YOUR_EAB_HMAC --accepttos `
  --source manual --host "vpn.example.com" --validation none `
  --store pemfiles --pemfilespath "C:\simple-acme\Certificates" `
  --pemfilesname "vpn-example-com" --friendlyname "fairssl-vpn-cert" `
  --installation script --script ".\Scripts\Deploy-FortiGate.ps1" `
  --scriptparameters "-StorePath 'C:\simple-acme\Certificates' -FilePrefix 'vpn-example-com' -FirewallHost '10.0.0.1' -CertLabel 'fairssl-vpn-cert' -CredentialTarget 'FortiGate-acme-user'"

Add -UpdateAdmin inside --scriptparameters if admin HTTPS should use the certificate as well. simple-acme creates a scheduled task that runs daily and renews when ARI says so or when fewer than 7 days remain.

FortiMail and FortiWeb

FortiMail and older FortiWeb use the same pattern as FortiGate proxy: an external host issues the certificate and a deploy hook pushes it in via the REST API. The ACME Easy Guides section of the FairSSL control panel ships finished scripts for FortiMail (Linux + Windows) and FortiWeb (Windows). The logic and structure mirror the FortiGate examples above; only the concrete API calls and the install endpoint differ.

Troubleshooting

Status stays Pending

Check that _dnsauth.<domain> is set up as a CNAME pointing to FairSSL's DNS server. Verify with dig _dnsauth.your-domain.com CNAME. Retry with execute vpn certificate local renew <name>.

Lego returns account does not exist

Most likely an old Lego version. Upgrade to v5.0.4+ and re-run the issuance command with the same --path. If the error persists, delete /etc/ssl/fortigate/accounts and re-run step 3 with the EAB keys.

SSH deploy fails with Host key verification failed

First time round you have to accept FortiGate's SSH host key. Run ssh admin@<fortigate-ip> manually from the deploy host and confirm the fingerprint. Or add the host key to ~/.ssh/known_hosts ahead of time.

SSL VPN still shows the old certificate after deploy

SSL VPN caches the certificate in memory. FairSSL's full deploy script in the control panel handles this by setting servercert to self-sign first and then back to the new certificate. If you use a simpler script of your own, the same swap has to be in there too.

Certificates on many servers and appliances

A publicly trusted SSL certificate can be valid for at most 199 days now, 99 days by 15 March 2027 and 46 days by 15 March 2029. Each certificate then has to be replaced at least twice a year now and at least eight times a year from 2029, on every server, firewall and load balancer that uses it. sslbrain from FairSSL runs as an appliance in your own network and renews and installs the certificates from one place, including on devices without an agent.

How sslbrain renews and installs certificates on FortiGate(opens sslbrain.com in a new tab)

Frequently asked questions

Find answers to the most common questions about SSL certificates and FairSSL.

Native ACME with External Account Binding requires FortiOS 7.6.3 or later. Earlier 7.6 releases had ACME but no EAB, which makes them unusable with commercial CAs like FairSSL. Older FortiGate devices (anything before 7.6.3) need the proxy approach with a Linux or Windows host.
No. FairSSL AutoDNS validates the domain via DNS-01 on our side, so FortiGate never has to expose port 80. The acme-auth-url field still has to be set because the FortiOS CLI requires it, but the HTTP-01 flow is never actually used as long as the domain is set to AutoDNS validation in your FairSSL control panel.
Run get vpn certificate local in the CLI. The status should read Status: OK with a valid expiry date. If it stays Pending, check that the domain is set up correctly under AutoDNS in your FairSSL control panel, then run execute vpn certificate local renew <name>.
FortiOS 7.6.3 supports standard ACME, but ARI support is still limited. If you set auto-regenerate-days to 30, FortiGate renews the certificate 30 days before expiry, which is safe for both 90-day and 47-day certificates. For full ARI awareness the proxy approach via Lego or simple-acme is still more flexible.
FortiMail has no native ACME support and always uses the proxy approach. FortiWeb 8.0.3 and later has native ACME with EAB, so the proxy approach is mainly relevant for older FortiWeb versions or when you want to drive the install from FairSSL's ready-made deploy scripts. Both expose well-documented REST APIs, so an external host can issue the certificate via Lego or simple-acme and push it over via the API. We ship example scripts for both in the FairSSL control panel under "ACME Easy Guides".
You only need them for the first registration. FortiGate stores the ACME account internally, and future renewals reuse it. The proxy approach is the same: Lego or simple-acme stores the account locally under the directory given to --path. Keep the EAB keys in a safe place as a backup anyway, in case you ever need to rebuild the setup.
Yes. FortiGate can bind the same local certificate object to multiple services. SSL VPN: config vpn ssl settings, set servercert "name", end. Admin HTTPS: config system global, set admin-server-cert "name", end. When the certificate is renewed, both bindings get the new one automatically.

Ready to automate FortiGate certificates?

Create a free account and order your first certificate. A DV certificate is issued in under 2 minutes.