Let's Encrypt Certificate Renewal Failure

I have a Pritunl Enterprise VPN server that has been in production use since Mar 7, 2019. Starting last week it can no longer renew the Let’s Encrypt certificate. When trying to renew the following error shows in the log:

[patient-waterfall-1365][2025-11-18 17:21:24,737][ERROR] Failed to get LetsEncrypt cert
Traceback (most recent call last):
  File "/usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/handlers/settings.py", line 1112, in settings_put
    acme.update_acme_cert()
  File "/usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/acme.py", line 73, in update_acme_cert
    cert = get_acme_cert(settings.app.acme_key, csr, cmdline)
  File "/usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/acme.py", line 45, in get_acme_cert
    certificate = acmetiny.get_crt(
  File "/usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/acmetiny.py", line 138, in get_crt
    raise ValueError("Challenge did not pass for {0}: {1}".format(domain, authorization))
ValueError: Challenge did not pass for vpn.server.hostname.tld: {'identifier': {'type': 'dns', 'value': 'vpn.server.hostname.tld'}, 'status': 'invalid', 'expires': '2025-11-25T22:21:21Z', 'challenges': [{'type': 'http-01', 'url': 'https://acme-v02.api.letsencrypt.org/acme/chall/2810300146/614933220256/CHk61A', 'status': 'invalid', 'validated': '2025-11-18T22:21:22Z', 'error': {'type': 'urn:ietf:params:acme:error:unauthorized', 'detail': 'During secondary validation: xxx.xxx.xxx.xxx: Invalid response from http://vpn.server.hostname.tld/.well-known/acme-challenge/YUUYdx_VaV5Rmw-c2X4oZ84TJ4RkoBUfoRruEn_8oZo: 403', 'status': 403}, 'token': 'YUUYdx_VaV5Rmw-c2X4oZ84TJ4RkoBUfoRruEn_8oZo', 'validationRecord': [{'url': 'http://vpn.server.hostname.tld/.well-known/acme-challenge/YUUYdx_VaV5Rmw-c2X4oZ84TJ4RkoBUfoRruEn_8oZo', 'hostname': 'vpn.server.hostname.tld', 'port': '80', 'addressesResolved': ['xxx.xxx.xxx.xxx'], 'addressUsed': 'xxx.xxx.xxx.xxx'}]}]}
  acme_domain = "vpn.server.hostname.tld"

Note: I have replaced the actual hostname and IP address with vpn.server.hostname.tld and xxx.xxx.xxx.xxx respectively.

In troubleshooting I have:

  • verified there is available space on the disks
  • restarted the pritunlservice
  • ran the command pritunl reset-ssl-cert to reinstall a self-signed certificate
  • checked there are no updates available with dnf update
  • rebooted the server

The server is running Oracle Linux 8.10 and the latest pritunl is installed: pritunl v1.32.4400.99

Prior to this, certificate renewals have functioned automatically as expected. All existing client sessions appear to be still functional and users can connect, but any new sessions/users get an error in the pritunl client about a self-signed certificate and cannot connect.

Last week I sent an email to priority@pritunl.com that is listed on support.pritunl.com but I have yet to receive a response. How can I resolve this error and get certificate renewal functioning again?

I also have manually visited the validation URL shown in the logs from multiple systems without issue, all return 200 and the expected validation text.

Verify it’s working on port 80 and verify port 80 is open. The Pritunl web server shouldn’t return a 403 error at that path even if the token doesn’t exist so it’s likely a load balancer issue.

Yes, it is on port 80 and working when I manually browse to that URL. There is no load balancer.

Here is a connection to the URL from an external network using curl:

Try running sudo pritunl renew-ssl-cert to manually trigger a certificate renewal. Then verify the addressesResolved in the error is the IP address of the Pritunl server.

Running that command gives the following error:

Server does not have Lets Encrypt domain configured

I’m sure this is because I ran pritunl reset-ssl-cert previously in my attempt to troubleshoot the issue. Is there any way to manually set the domain outside the UI since when I try to set it there it attempts to renew the certificate and fails so the domain is not saved.

I found the setting in the source: pritunl set app.acme_domain

I have run the command you gave and verified the addressResolved is the correct IP address

Test the request on another system, it’s possible there is some WAF in front of the server. There isn’t likely any other cause the pritunl web server has no code to return a 403 error for this path.

Also run the commands below to add a log message to the acme_token_get function as shown below then watch to see if it is received in the top right log output.

sudo nano /usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/app.py

@app.route('/.well-known/acme-challenge/<token>', methods=['GET'])
@auth.open_auth
def acme_token_get(token):
    logger.info('Acme challenge', 'app',
        token=token,
    )
    token = utils.filter_str(token[:96])
    authorization = acme.get_authorization(token)
    if authorization:
        return flask.Response(authorization, mimetype='text/plain')
    return flask.abort(404)

sudo systemctl restart pritunl

I added the logger and it definitely isn’t reaching there. I had noticed while looking through the source for how to manually set the domain that there was no code to return a 403. The server is behind a hardware firewall in the data center of course but that shouldn’t return a 403 either. If it was denying access it would just drop the packets. I’m really confused where the request from Let’s Encrypt is getting routed to. For now I have used certbot to generate a manual request with DNS validation and have added the new certificate and key to the UI. This has allowed us to get back to a usable state while I try to figure out what is going on.

Thanks for your help.