Web & Networking

Google Trust Services Certificates with acme.sh: A 2026 Guide

Issue and renew a Google Trust Services certificate with acme.sh, Google Public CA EAB credentials, and a scoped Cloudflare DNS token.

4 min readUpdated Sunday, Aug 16, 2026
#ssl#tls#acme.sh#google-cloud#certificates

A mountain landscape beneath a dark sky

Google Cloud Certificate Manager Public CA issues publicly trusted Google Trust Services certificates through ACME. Unlike a typical public ACME endpoint, it requires External Account Binding (EAB) to associate the ACME account with a Google Cloud project.

This guide uses acme.sh, DNS-01, and Cloudflare. The Google account-registration steps also work with other DNS providers supported by acme.sh.

Updated August 2026. The old version used gcloud beta, a Cloudflare Global API Key, and manual certificate paths. Those instructions have been replaced.

What you need

  • A Google Cloud project where you can enable publicca.googleapis.com and create an EAB key.
  • A domain whose DNS provider has an acme.sh DNS hook.
  • A host that can run acme.sh on a schedule.
  • A service reload command that fails when its configuration is invalid.

Google’s production ACME directory is https://dv.acme-v02.api.pki.goog/directory. Its staging directory is https://dv.acme-v02.test-api.pki.goog/directory; staging certificates are not publicly trusted. Test automation there, then create a separate EAB secret for production.

1. Enable Public CA and create an EAB secret

Select the intended project and enable the API:

gcloud config set project YOUR_PROJECT_ID
gcloud services enable publicca.googleapis.com

The identity creating the secret needs permission such as the dedicated roles/publicca.externalAccountKeyCreator role.

Create the EAB secret and save the response to a protected file:

umask 077
gcloud publicca external-account-keys create \
  --key-output-file=./google-public-ca-eab.json

The output contains keyId and b64MacKey. Treat both as credentials. Google states that an EAB secret must be used within seven days, can register one ACME account, and becomes invalid after that registration. The registered ACME account itself does not expire merely because the EAB secret does.

Do not commit the file. Remove the one-time secret after successful registration and after documenting which project owns the account.

2. Install or update acme.sh

Use the project’s documented installer and include an account email:

curl https://get.acme.sh | sh -s email=admin@example.com

Open a new shell or call the installed script explicitly:

~/.acme.sh/acme.sh --version
~/.acme.sh/acme.sh --upgrade

The installer normally creates a daily cron entry. The client runs daily but only renews certificates when due.

3. Register the Google Public CA account

Read keyId and b64MacKey from the EAB file, then register once:

~/.acme.sh/acme.sh --register-account \
  --server google \
  --accountemail admin@example.com \
  --eab-kid 'YOUR_KEY_ID' \
  --eab-hmac-key 'YOUR_B64_MAC_KEY'

google is an official acme.sh alias for the production directory. Keeping --server google on issue commands is clearer than changing the global default when one host uses more than one CA.

4. Create a narrow Cloudflare token

In Cloudflare, create an API token limited to the zone being validated. Grant DNS edit access for that zone; if the client must discover the zone ID, grant zone read access too. Avoid the account-wide Global API Key.

Supply the token and preferably the exact zone ID:

read -rsp 'Cloudflare API token: ' CF_Token
echo
export CF_Token
export CF_Zone_ID='YOUR_ZONE_ID'

The dns_cf hook persists the credentials needed for renewal. Protect ~/.acme.sh/account.conf, keep it out of unencrypted backups, and rotate the token if exposed.

5. Issue an apex and wildcard certificate

Request both names because *.example.com does not cover example.com:

~/.acme.sh/acme.sh --issue \
  --server google \
  --dns dns_cf \
  --keylength ec-256 \
  -d example.com \
  -d '*.example.com'

DNS-01 allows unattended wildcard renewal when the DNS API remains available. Manual DNS requires fresh TXT records on renewal and is therefore a poor fit for automation.

If validation fails, check the authoritative DNS answer rather than only a cached resolver:

dig +short NS example.com
dig +short TXT _acme-challenge.example.com

6. Install into stable service paths

Do not point Nginx directly at files under ~/.acme.sh; that directory is internal client state. Use --install-cert so renewals copy files to stable paths and run the saved reload command.

sudo install -d -m 0750 /etc/nginx/ssl/example.com

~/.acme.sh/acme.sh --install-cert \
  --ecc \
  -d example.com \
  --key-file /etc/nginx/ssl/example.com/privkey.pem \
  --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
  --reloadcmd 'sudo nginx -t && sudo systemctl reload nginx'

The renewal account must be able to write those destinations and execute the narrowly defined reload command. Configure Nginx to use the installed paths, then inspect what the public endpoint actually serves:

openssl s_client \
  -connect example.com:443 \
  -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates -serial

7. Check renewal end to end

crontab -l | grep acme.sh
~/.acme.sh/acme.sh --info -d example.com

Avoid repeatedly forcing production issuance as a test. Use staging during development and monitor the live certificate from another machine. A successful renewal is incomplete if installation or service reload fails.

References