Knowing when something breaks

Warn yourself before an SSL certificate or domain expires, with n8n

An expired certificate puts a full-page browser warning in front of every visitor. A lapsed domain is worse. Both are entirely preventable and both still happen constantly.

Build time
An hour
Difficulty
Intermediate
Template
7 nodes

What you need before you start

  • A self-hosted n8n, for the certificate half. The guide explains the cloud workaround.
  • A list of every domain you own, which is the hard part.
  • Somewhere for the warning to land.
  • Nothing paid. Both checks use free public services.

An expired certificate does not degrade the site. It puts a full-page red warning in front of every visitor telling them your site may be trying to steal from them, and most of them leave.

An expired domain is worse, because for a while you do not have a website at all, and after long enough somebody else can have your name.

Both are dates in a calendar. Both still happen to real businesses every week.

Why automatic renewal is not enough

Almost everyone reading this has Let’s Encrypt certificates that renew themselves, and mostly they do.

Renewal breaks when the path it uses changes. Somebody puts a proxy in front of the origin and the validation request no longer reaches the right place. A DNS record moves. A redirect gets added that catches the challenge URL along with everything else. The renewal job carries on running and carries on failing, and nothing in front of you changes until the day the certificate runs out.

That is the day this check exists for. Not the day you forget, the day the automation you trusted stopped working without saying so.

Reading the actual certificate

The reliable way to check a certificate is to open a connection and read the one being served. Not a third-party opinion, not a cached report. The real thing.

On a self-hosted n8n you can do this in a Code node, once Node’s tls module is allowed. Set this on the n8n container or process:

NODE_FUNCTION_ALLOW_BUILTIN=tls

Restart n8n and the module is available inside Code nodes. If you already allow builtins for something else, add tls to the list with a comma.

On n8n Cloud you cannot set that, so the fallback is a public checking service over HTTP. It works, and it makes your certificate monitoring depend on a free service you do not control, which is a slightly odd shape for a reliability tool. Self-hosting the check is better where you have the option.

The build, seven nodes

1. Schedule Trigger. Daily, early. There is no reason to check more than once a day and every reason not to make it hourly.

2. Code node, called Domains. Your list. Keep it here rather than in a sheet, so the check has no dependency that can itself fail:

return ['loadoff.uk', 'book.loadoff.uk', 'yourotherdomain.co.uk']
  .map((host) => ({ json: { host } }));

3. Code node, called Certificate. Connect, read, count the days:

const tls = require('tls');
const host = $json.host;

const cert = await new Promise((resolve, reject) => {
  const socket = tls.connect(
    { host, port: 443, servername: host, timeout: 8000 },
    () => { const c = socket.getPeerCertificate(); socket.end(); resolve(c); }
  );
  socket.on('error', reject);
  socket.on('timeout', () => { socket.destroy(); reject(new Error('timeout')); });
});

const expires = new Date(cert.valid_to);
return [{ json: {
  host,
  cert_expires: expires.toISOString().slice(0, 10),
  cert_days: Math.round((expires - Date.now()) / 86400000),
  issuer: cert.issuer && cert.issuer.O,
}}];

Run that against your own site once and you should get something like Google Trust Services and a number in the 50s or 60s if you are on a 90-day certificate that renewed recently. Ours reported 58 days when this guide was written, which is exactly where a healthy 90-day certificate should sit.

Set the node to continue on fail. A host that will not answer is information rather than a reason to stop checking the other five.

4. HTTP Request, called Domain Expiry. RDAP, which is the JSON replacement for WHOIS:

GET https://rdap.org/domain/{{ $json.host.split('.').slice(-2).join('.') }}

That expression strips a subdomain, because book.loadoff.uk is not separately registered and asking about it gets you nothing. Two labels is right for .com and for most .uk domains.

Follow redirects, which n8n does by default. rdap.org bounces you to whichever registry actually holds the domain, and Nominet answers for .uk.

5. Code node, called Merge. Pull the expiry out of the RDAP events array and put it alongside the certificate numbers:

const events = $json.events || [];
const exp = events.find((e) => e.eventAction === 'expiration');
const days = exp
  ? Math.round((new Date(exp.eventDate) - Date.now()) / 86400000)
  : null;
return [{ json: { ...$('Certificate').item.json, domain_days: days } }];

6. Filter, called Warn. Keep anything where the certificate has fewer than 30 days left, or the domain has fewer than 60.

Sixty on the domain rather than thirty is deliberate. Domain renewals sometimes need a payment method updating or a registrar account somebody left the company with access to, and that is not a two-day job.

7. Telegram, Slack or email. One message listing everything that needs attention, rather than one message per domain. Six separate notifications on the same morning is how an alert becomes noise.

The domain you have forgotten

This is the real hole and no tool closes it.

The check watches what you point it at. The domain that catches people out is the one somebody registered in 2019 to stop a competitor having it, or the misspelling that redirects to your main site, or the old trading name still pointing at your current one. Nobody is watching those because nobody remembers they exist, and the first sign is a customer typing the old address and getting a parked page full of adverts.

Half an hour, once: log into every registrar account you have, list everything, and put the list somewhere that is not one person’s memory. Then paste it into the Domains node.

That half hour is worth more than the workflow.

What to do when it fires

For a certificate, the question is not “renew it”, it is “why did renewal stop”. Renewing by hand fixes today and leaves you in exactly the same position in 90 days, except that next time you will have learned to ignore the warning at 30 days because last time it was fine.

Find the reason. It is nearly always something added in front of the origin: a proxy, a redirect, a firewall rule, a DNS change made for an unrelated reason.

For a domain, renew it, and while you are in the registrar turn on auto-renew and check the card on file has not expired. A card expiring is the most common cause of a domain lapsing, and it is a failure with no alert attached to it at all.

Published 28 August 2026. Written by the people who run this sort of thing for clients, on n8n, including our own lead pipeline.

Next in knowing when something breaks: The new review alert. Or go back to all 4 in this category.

Questions about this build

Do Let's Encrypt certificates not renew themselves?

They are meant to, and mostly they do. Renewal breaks when the validation path changes: a DNS record moved, a redirect added in front of the challenge URL, a firewall rule, a proxy put in front of the origin. The automation carries on reporting success right up until the certificate has 30 days left and then 3 and then none. The check exists for the day the renewal stops working rather than for the day you forget.

How do I check an SSL certificate expiry date programmatically?

Open a TLS connection and read the certificate. In n8n's Code node on a self-hosted instance you can require Node's built-in tls module once NODE_FUNCTION_ALLOW_BUILTIN includes it, connect to the host on port 443, and read valid_to off the peer certificate. That is the real served certificate rather than what a third party thinks it is, which is what you want.

How do I check when a domain expires?

RDAP, which is the modern replacement for WHOIS and returns JSON. A request to rdap.org for your domain redirects to the right registry and comes back with an events array containing an expiration entry. It is free, it needs no account, and it works for .uk through Nominet as well as for the generic domains.

When should the warning fire?

Thirty days and seven days. Thirty gives you time to work out why an automatic renewal stopped without rushing. Seven is the one that catches you when you ignored the first, and it should be loud enough to be annoying, because at that point it is about to be.

What about domains I forgot I own?

This is the real gap and no tool solves it. The check watches what you point it at, and the domain that catches people out is the one somebody registered years ago that has been redirecting to your main site ever since. Go through your registrar accounts once, list everything, and put the list somewhere that is not one person's memory.

The next step

Stop losing leads.Let's fix it this week.

Tell us what keeps slipping and we'll scope something around it. You'll be talking to Max, who runs the work, not a sales team. Most clients are live within 48–72 hours of that first conversation.

30-day rolling retainers. No lock-in. Cancel anytime.