Let's Encrypt Problem Switching from DynDNS to FreeDNS

  • Nextcloud Server version (e.g., 29.x.x):
    • 33.0.3.2
  • Operating system and version (e.g., Ubuntu 24.04):
    • NextCloudPi v1.57.1 (Debian GNU/Linex 12 (bookworm) 6.1.21-v8+ (aarch64))
  • Web server and version (e.g, Apache 2.4.25):
    • Apache2 (no idea of version)
  • Reverse proxy and version _(e.g. nginx 1.27.2)
    • No idea
  • PHP version (e.g, 8.3):
    • No idea
  • Is this the first time you’ve seen this error? (Yes / No):
    • Yes
  • When did this problem seem to first start?
    • Over the last couple of weeks or so, maybe more
  • Installation method (e.g. AlO, NCP, Bare Metal/Archive, etc.)
    • NextCloudPi Image install
  • Are you using CloudfIare, mod_security, or similar? (Yes / No)
    • No

Summary of the issue you are facing:

Previously I was using DynDNS for free dynamic DNS services, but that seems to have gone paid and stopped working. So I’m trying to shift to FreeDNS.

That has been set up successfully within NC, and I can access my system by it. But if I try and use Let’s Encrypt update for it, it fails with a 404 error (which I also get if I try and access the URL manually.

The error is below, with the FreeDNS username and update hash redacted.

[ letsencrypt ] (Sun May 17 17:33:37 BST 2026)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for <username>.uk.to

Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
Domain: <username>.uk.to
Type: unauthorized
Detail: 78.147.81.137: Invalid response from http://<username>.uk.to/.well-known/acme-challenge/<update hash redacted>: 404

If I use the freeDNS URL in a browser it brings up my NC login page correctly, but if I do the same using the local IP address of the Pi I get the default Apache2 webpage (the positive test page you get directly after installing Apache2).

Can anyone suggest why Let’s Encrypt is failing, or what I can do to get it working?

As the administrator of your own server, you should know the answer to this rather important question. Any reverse proxy you may have in place is likely to be affecting your problem.

You’ve mentioned a debug log file. So why don’t you show us what’s in that log file from the time of your last attempt to renew your certificates?

You also mention a domain that can be accessed via HTTP. Unfortunately, you don’t make it clear whether this is the current (old) domain or the new one that will be used.

You should also be aware that, in order to renew the certificates, the server must be accessible via HTTP rather than HTTPS (unlike Nextcloud itself).

I myself switched DynDNS providers once in the past because the old one didn’t support IPv6 and I wanted to make my NC server accessible via IPv6 as well.

I clearly remember that I also had to modify the cron job script that triggers the regular renewal of the certificates. Did you also think about making that necessary adjustment?

404

means not found. Do you forward port 80?

Sure! But may not only mean not accessible via HTTP (tcp 80) but may also mean the let’s encrypt script will still want to renew old DynDNS-Address

Yes, port 80 is forwarded (I can access the freedns domain by http using a browser or the mobile app using the DDNS).

I’ve changed the letsencrypt domain in the web panel from the spdns address to the freedns one - is there some other change that may be needed for the switch?

I haven’t any reverse proxy in place, unless one has been set up as part of the install process. I’m just port-forwarding on my router to the Pi running the NC instance.

Can you give more info about the cron job script - where is that found and accessed? Generally I just access via the Nextcloud panel (on port 4443) and of course general user access (on port 80).

No, i can’t since most likely i do use a different script. I do not use NextCloudPi Image install but a so called bare metal installation and i do use Let’s Encrypt/acme.sh to renew certificates.

From infos you provide so far i suspect you use another script.

But you need to know from what you provide so far whether this:

is the current (old) domain or the new one that will be used. If it is the old one you need to modify the script if it is the new one it seems to be modified yet.

Also you can use the infos from that line to check whether the named IPv4-Adress points to your current (new) domain. Use nslookup for that purpose.

Hi @DarrenHill,

The existing answers are on the right track, but since you’re on NextCloudPi there are a few NCP-specific things worth checking that may cause exactly this symptom.


1. Did you update the domain in the NCP panel, or only in Nextcloud?

In NCP, Let’s Encrypt is managed exclusively through the NCP panel under NETWORKING → letsencrypt — not through the Nextcloud admin panel. The panel has a Domain field, an Email field, and an Apply button (screenshot in the NCP README). If you updated the domain somewhere in Nextcloud’s own settings (overwrite.cli.url, trusted domains, etc.) but did not re-run letsencrypt via the NCP panel with the new FreeDNS domain, the certificate is still issued for your old DynDNS domain and certbot still tries to renew that old domain.

To fix: open the NCP panel → NETWORKING → letsencrypt, set the Domain field to your new FreeDNS hostname, and click Apply. This re-runs certbot for the new domain.


2. The renewal cron may still be trying to renew the old DynDNS certificate

NCP’s renewal cron (/etc/cron.weekly/letsencrypt-ncp) runs:

letsencrypt renew --quiet

This renews every certificate that certbot knows about — including any lingering renewal configuration for your old DynDNS domain stored in /etc/letsencrypt/renewal/. Since your DynDNS subscription has expired and that hostname no longer points to your server, certbot’s challenge for the old domain fails with 404.

After you successfully issue a certificate for the new FreeDNS domain via the NCP panel (step 1), check what renewal configs exist:

ls /etc/letsencrypt/renewal/

If you see a .conf file for your old DynDNS domain there, you can remove it:

sudo certbot delete --cert-name <old-dyndns-domain>

This stops the cron from repeatedly trying (and failing) to renew the dead certificate.


3. Port 80 is already confirmed open — the 404 proves it

One point worth clarifying from the other replies: the 404 you are seeing is not a sign that port 80 is blocked. Quite the opposite — Let’s Encrypt’s servers are reaching your server on port 80, Apache is responding, but the challenge file is simply not there. A closed or firewalled port 80 would produce a connection timeout or refused error, not a 404. So port forwarding for port 80 is not the issue here.


4. DNS propagation for the new FreeDNS domain

Before certbot can succeed, your new FreeDNS hostname must resolve to your current public IP. FreeDNS subdomain updates can take a few minutes to propagate. You can verify with:

nslookup <your-freedns-domain> 8.8.8.8

The returned IP must match your router’s current public IP.


Summary of what to check in order:

  1. NCP panel → NETWORKING → letsencrypt: confirm the Domain field shows your FreeDNS hostname, then click Apply.
  2. ls /etc/letsencrypt/renewal/ — remove the old DynDNS cert with sudo certbot delete --cert-name <old-domain> if present.
  3. Confirm DNS for the new domain resolves to your current IP from an external resolver.
  4. Port 80 is not the problem — the 404 you see proves it is reachable from the outside.

If step 1 fails with a 404, paste the full output of /var/log/letsencrypt/letsencrypt.log — it will show which domain certbot is actually trying to validate and which URL it uses for the challenge.


I don’t run NCP myself — this analysis is based on reading the NCP source code and general knowledge of how certbot and Apache work, so I may be wrong on some details.


h.t.h.


ernolf

Firstly thanks to you both for the replies and support.

To answer the last email first (as it should include the other one as well) - it’s step 1 above that’s currently failing me. On that Let’s Encrypt screen on the NCP I confirm I have the correct (new) domain, plus the email address too. I’ve set up FreeDNS in the relevant entry in the same networking section in NCP, and I’ve deactivated spDNS (DynDNS) also in the same section.

When I click on the apply button on the Let’s Encrypt sub-screen, it gives the failure 404 response I posted above. I confirm that the public IP address shown is correct, as is the freedns domain and the update hash within that URL.

The DNS look-up via Google also resolves correctly to my public IP address, and as noted I can access my NCP installation via the freeDNS domain using http or https (via https it gets intercepted as an untrustworthy website by my AV but if I tell it to continue it securely connects).

I’ll look into getting the letsencrypt.log and see what that shows - give me a little while on that.

The tail end of the log is here - Let's Encrypt Log - Pastebin.com

I redacted the private information again within <>, but everything there is what I expect it to be based on my public IP address, FreeDNS domain and FreeDNS update hash.

There was an old certificate in the /etc/letsencrypt/renewal folder, which I removed using your command above. But the issuing of the new certificate is still failing, same error as before.

The log is clear: certbot writes the challenge file to /var/www/nextcloud/.well-known/acme-challenge/ successfully, but Let’s Encrypt gets HTTP 404 when trying to download it. The most likely cause is that the port 80 VirtualHost is redirecting everything to HTTPS before Apache can serve the challenge file.

Step 1 — Try the simplest fix first

In the NCP panel under CONFIG, there is an nc-httpsonly option. Try disabling it temporarily, then run Let’s Encrypt from the NCP panel again. If the certificate is issued successfully, re-enable httpsonly afterwards.

If that works, you’re done. If not, we need to look deeper.


Step 2 — If it still fails: collect diagnostics

Please provide the output of:

sudo cat /etc/apache2/sites-available/000-default.conf
sudo apache2ctl -S
sudo certbot certificates
sudo cat /etc/letsencrypt/renewal/darrenhill.uk.to.conf
sudo ls /etc/letsencrypt/live/
sudo ls /etc/letsencrypt/archive/

This will show us the port 80 Apache configuration, the certbot renewal settings, and whether there are leftover files from the old domain certificate that might be causing interference.


ernolf

Tried switching off https, and it didn’t help (text reported given below).

Interestingly I note there are a couple of errors when I tried the force https change, one relating to the old spdns (DynDNS) domain.

I’ll start work on gathering the other information now.

[ nc-httpsonly ] (Tue May 19 17:19:22 BST 2026)
sed: can't read /etc/apache2/sites-available/000-default.conf: No such file or directory
AH00526: Syntax error on line 11 of /etc/apache2/sites-enabled/001-nextcloud.conf:
SSLCertificateFile: file '/etc/letsencrypt/live/<spdns domain>/fullchain.pem' does not exist or is empty
Action '-k graceful' failed.
The Apache error log may have more information.
Forcing HTTPS Off




[ letsencrypt ] (Tue May 19 17:21:16 BST 2026)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for <FreeDNS domain>

Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
Domain: <FreeDNS domain>
Type: unauthorized
Detail: <public IP>: Invalid response from http://darrenhill.uk.to/.well-known/acme-challenge/<FreeDNS update hash>: 404

Hint: The Certificate Authority failed to download the temporary challenge files created by Certbot. Ensure that the listed domains serve their content from the provided --webroot-path/-w and that files created there can be downloaded from the internet.

Some challenges have failed.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

Looks like there’s a lot of stuff missing/empty, and at least one reference to the old spdns domain. There is no 000-default.conf, but there is a 000-default.conf.bak which I cat’d below.

sudo cat /etc/apache2/sites-available/000-default.conf

cat: /etc/apache2/sites-available/000-default.conf: No such file or directory



ls /etc/apache2/sites-available

000-default.conf.bak  000-default.conf.dpkg-dist  001-nextcloud.conf  default-ssl.conf  ncp-activation.conf  ncp.conf



sudo cat 000-default.conf.bak

<VirtualHost _default_:80>
  DocumentRoot /var/www/nextcloud
  <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^.well-known/acme-challenge/ - [L]
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
  </IfModule>
  <Directory /var/www/nextcloud/>
    Options +FollowSymlinks
    AllowOverride All
    <IfModule mod_dav.c>
      Dav off
    </IfModule>
    LimitRequestBody 0
  </Directory>
</VirtualHost>



sudo apache2ctl -S

VirtualHost configuration:
*:443                  darrenhill.spdns.eu (/etc/apache2/sites-enabled/001-nextcloud.conf:4)
*:4443                 localhost (/etc/apache2/sites-enabled/ncp.conf:2)
ServerRoot: "/etc/apache2"
Main DocumentRoot: "/var/www/html"
Main ErrorLog: "/var/log/apache2/error.log"
Mutex rewrite-map: using_defaults
Mutex ssl-stapling-refresh: using_defaults
Mutex ssl-stapling: using_defaults
Mutex proxy: using_defaults
Mutex ssl-cache: using_defaults
Mutex default: dir="/var/run/apache2/" mechanism=default
Mutex watchdog-callback: using_defaults
PidFile: "/var/run/apache2/apache2.pid"
Define: DUMP_VHOSTS
Define: DUMP_RUN_CFG
User: name="www-data" id=33
Group: name="www-data" id=33



sudo certbot certificates

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
No certificates found.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



sudo cat /etc/letsencrypt/renewal/darrenhill.uk.to.conf

cat: /etc/letsencrypt/renewal/darrenhill.uk.to.conf: No such file or directory



sudo ls /etc/letsencrypt/live/

README



sudo ls /etc/letsencrypt/archive/

Nothing (the folder is empty)

Hi @DarrenHill,

The diagnosis is now complete.

  • Why the 404

    Port 80 is reaching your server — a 404 means Apache responded, just from the wrong directory. apache2ctl -S shows no port-80 VirtualHost is active. Without one, Apache falls back to its built-in defaults with DocumentRoot /var/www/html. Certbot writes the challenge file to /var/www/nextcloud/.well-known/acme-challenge/ — a different directory entirely — so Apache returns 404.

    The root cause: 000-default.conf is missing from sites-available. NCP creates this file during installation (nc-nextcloud.sh) and it must always be present — nc-httpsonly edits it with sed and assumes it exists, which is exactly why you got sed: can't read. The .bak copy you have contains the correct NCP-generated content.

  • Why Apache cannot reload

    001-nextcloud.conf still references the old spdns domain and its certificate. That certificate no longer exists on disk — certbot certificates returned nothing, /etc/letsencrypt/live/ is empty. Apache is currently running from the state it was in before the cert disappeared, but it cannot reload or restart.

    This happened because NCP’s letsencrypt.sh only updates 001-nextcloud.conf when certbot succeeds. When certbot fails (as it did here, because port 80 was broken), the script returns without touching the Apache config. So 001-nextcloud.conf is stuck with the old spdns domain.

The fix — three steps (steps 1 and 3 through the NCP panel, step 2 on the command line)

  1. let NCP repair 001-nextcloud.conf

    In the NCP panel, go to Let’s Encrypt and set it to disabled. When you apply, NCP regenerates 001-nextcloud.conf using its own template (nextcloud.conf.sh), which automatically falls back to the Debian snakeoil self-signed certificate when no Let’s Encrypt certificate is present. Apache can then reload successfully.

  2. restore the port-80 VirtualHost

    sudo cp /etc/apache2/sites-available/000-default.conf.bak /etc/apache2/sites-available/000-default.conf
    sudo a2ensite 000-default
    sudo apachectl -k graceful
    

    After this, Apache serves port 80 from /var/www/nextcloud/ with the ACME challenge passthrough rule in place.

  3. enable Let’s Encrypt with the new domain

    In the NCP panel, go to Let’s Encrypt, enter your FreeDNS domain, and enable it. NCP will run certbot — which can now authenticate successfully — and update 001-nextcloud.conf with the new certificate and domain.


Disclaimer: I don’t run NCP myself, so everything above is based on reading the source scripts rather than hands-on testing. I’m reasonably confident in the diagnosis — it follows directly from the code — but I can’t guarantee every panel interaction behaves exactly as the scripts suggest. If something doesn’t go as expected, please report back. Don’t blame me too hard. :slightly_smiling_face:


ernolf

And we have a winner :smiley:

Following your instructions above worked, although at the end of step 2 it said I should use systemctl reload apache2 which I added after your third command (I just include mention here in case anyone else needs this in the future).

But I now have the certificate, and will keep an eye on it that it updates properly at the appropriate time.

Thanks again for the support in fixing this up!

I opened an Issue for this: