NginxProxyManager / nginx-proxy-manager

Docker container for managing Nginx proxy hosts with a simple, powerful interface
https://nginxproxymanager.com
MIT License
22.19k stars 2.56k forks source link

Customize SSL cert renewing interval to avoid reloading nginx every hour #677

Open niklasdahlheimer opened 3 years ago

niklasdahlheimer commented 3 years ago

Is your feature request related to a problem? Please describe. First of all: great tool! Setting up reverse poxies is really fun with this one :)

According to the docker logs, npm is checking for expired certificates every hour:

[10/26/2020] [1:26:22 AM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[10/26/2020] [1:26:24 AM] [Nginx    ] › ℹ  info      Reloading Nginx
[10/26/2020] [1:26:24 AM] [SSL      ] › ℹ  info      Renew Complete
[10/26/2020] [2:26:22 AM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[10/26/2020] [2:26:24 AM] [Nginx    ] › ℹ  info      Reloading Nginx
[10/26/2020] [2:26:24 AM] [SSL      ] › ℹ  info      Renew Complete
[10/26/2020] [3:26:22 AM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[10/26/2020] [3:26:23 AM] [Nginx    ] › ℹ  info      Reloading Nginx
[10/26/2020] [3:26:23 AM] [SSL      ] › ℹ  info      Renew Complete
[...]

I think reloading nginx every hour could lead to problems in the business times of our web services (e.g. downloads buffered by nginx ..)

Is there a way to customize the cron job which triggers the cert renewing every hour to start the renewing only once a day or so?

Describe the solution you'd like some way (UI or production.config) to customize the renewal interval

tophee commented 3 years ago

I don't quite understand why the renewing interval is set to such a short period in the first place. I think, letsencrypt certs are usually valid for three months or so. Why do 2160 checks during that period?

niklasdahlheimer commented 3 years ago

probably it's just changing https://github.com/jc21/nginx-proxy-manager/blob/4f10d129c20cc82494b95cc94b97f859dbd4b54d/backend/internal/certificate.js#L24 to intervalTimeout: (process.env.CERTIFICATE_RENEWAL_INTERVAL_IN_SECONDS * 1000) || (1000 * 60 * 60), // 1 hour

Than the environment variable CERTIFICATE_RENEWAL_INTERVAL_IN_SECONDS could be used to set the preferred interval.

Sadly I'm not able to setup a working build environment to test it to create a pull request :/

CorvetteCole commented 3 years ago

this really need to be changed, I'm sure lets encrypt doesn't particularly appreciate it either

chaptergy commented 3 years ago

Letsencrypt does not notice this, as it is only checked locally whether a certificate is due to expire within a month, and only then a request to letsencrypt ist made. The only "issue" this high renewal rate causes is a slightly higher than necessary CPU consumption every hour. So NPM would be made more efficient by changing this, but this is not very urgent. Which does not mean that it should not be changed.

niklasdahlheimer commented 3 years ago

@chaptergy I agree with you that certbot will only contact letsEncrypt if a certificate really expires within the next 30 days: "[...]Since renew only renews certificates that are near expiry it can be run as frequently as you want - since it will usually take no action.[...]" https://certbot.eff.org/docs/using.html?highlight=renew#renewing-certificates

But my concerns where more about the reload of nginx, which, I think, is triggered every time the task is run, so every hour. See https://github.com/jc21/nginx-proxy-manager/blob/5c679084605a79d98661a65eb272a06fc8cb5669/backend/internal/certificate.js#L55

I'm not so much into nginx but couldn't this might cause running connections to "hickup" or result in a denial of service if you do a request just in this reload interval? Either way, this hourly reload is not nescessary and I think it's easy to avoid it by implementing a environment variable, just like I suggested above. ...Or just increase the interval...Actually every value below 30 days should be enough

chaptergy commented 3 years ago

It seems the original intention was to not run certbot at boot since you can't execute other certbot commands while it is running. And to make sure certbot runs even if you restart frequently, the hourly interval was chosen.

tophee commented 3 years ago

Thanks for the explanation. At least it makes some sense now. But the same could also be achieved by running certbot exactly once an hour after boot and thereafter once every couple of weeks or so.

marcb1387 commented 2 years ago

I'm having this same thing occur and getting 522 error on my pages around the time when it reloads nginx. All of my certs are months off from expiration. If this could be scheduled during off time one a day it would be great.

[2/7/2022] [9:05:39 PM] [SSL ] › ℹ info Renewing SSL certs close to expiry... [2/7/2022] [9:05:41 PM] [Nginx ] › ℹ info Reloading Nginx [2/7/2022] [9:05:41 PM] [SSL ] › ℹ info Renew Complete

RafaelSchridi commented 2 years ago

Since it renews when expiry is <30 days I see absolutely no reason to run this so often, should be at the minimum a 1 day interval.

LucidityCrash commented 2 years ago

this issues an nginx reload not a restart ... reload doesn't kill existing connections :

    nginx -s reload

Once the master process receives the signal to reload configuration, it checks the syntax validity of the
new configuration file and tries to apply the configuration provided in it. If this is a success, the master
process starts new worker processes and sends messages to old worker processes, requesting them to
shut down. Otherwise, the master process rolls back the changes and continues to work with the old 
configuration. Old worker processes, receiving a command to shut down, stop accepting new connections
and continue to service current requests until all such requests are serviced. After that, the old worker
processes exit. 
frabnet commented 2 years ago

Customizing renew interval can be also useful to improve security or avoid unwanted network traffic. Now the port 80 tcp is opened in every moment since we don't know when the renew will happen. If the renew is running in a scheduled moment, we can open the 80 port only on (for example) Sunday from 23:25 to 23:35. It's not a big security problem but the 80 port is much common, surely we can avoid some potential problems. Anyway, I'm open to suggestions.

LucidityCrash commented 2 years ago

Now the port 80 tcp is opened in every moment since we don't know when the renew will happen.

Is it really opening port 80 though ... I don't claim to be an expert but it doesn't make sense to me for it to be attaching to port 80 if there isn't a certificate to renew ... that said I use the cloudflare dns method so it never opens port 80 and I can't test either

however from the certbot docs :

certbot renew

This command attempts to renew any previously-obtained certificates that expire in less than 30 days. 
The same plugin and options that were used at the time the certificate was originally issued will be used
for the renewal attempt, unless you specify other plugins or options. Unlike certonly, renew acts on
multiple certificates and always takes into account whether each one is near expiry. Because of this, 
renew is suitable (and designed) for automated use, to allow your system to automatically renew each
certificate when appropriate. Since renew only renews certificates that are near expiry it can be run as
frequently as you want - since it will usually take no action.

Note this bit it can be run as frequently as you want - since it will usually take no action It really does seem to suggest that this is not doing what you seem to believe it is doing.

frabnet commented 2 years ago

I don't want to criticize, just clarify: I assure you that the port 80 is always opened and always responsive, even when a renew is not needed:

frab@test:~$ curl --head http://website
HTTP/1.1 301 Moved Permanently
Server: openresty
Date: Wed, 04 May 2022 07:37:15 GMT
Content-Type: text/html
Content-Length: 166
Connection: keep-alive
Location: https://website/

With a scheduled renew timing, it could be closed by the user firewall (it can be a hardware firewall or iptables rule in the container).

UPDATE: I just found Let's Encrypt suggest to keep the 80 port open: https://letsencrypt.org/docs/allow-port-80/ I'm still convinced it's not a good way of managing it, but wathever :bow:

LucidityCrash commented 2 years ago

I'm really confused here, I certainly don't think you are critizing, I just think we seem to have a missunderstanding :)

The points I've made are that

  1. NPM does an nginx reload which wont interrupt a existing connection
  2. certbot only actually actually does the renew process when there is something to renew.

Looking at the cert code in NPM : Initial cert request - https://github.com/NginxProxyManager/nginx-proxy-manager/blob/14b889a85f2f8af9a13ed6122f5a0a91d64ecc36/backend/internal/certificate.js#L835 and renewal - https://github.com/NginxProxyManager/nginx-proxy-manager/blob/14b889a85f2f8af9a13ed6122f5a0a91d64ecc36/backend/internal/certificate.js#L42 (renews are done with the same authenticator as the initial request)

I can see that if you do not use the DNS challenge method then it will use certbot with the webroot auth method with certonly ... this means that the web service, in this case nginx, is not restarted. certbot adds files to specific paths for the auth process - https://eff-certbot.readthedocs.io/en/stable/using.html?highlight=renew#webroot

So in short even if you don't use dns challenge for LE your sites should never be unavailable (slight caveat on that - https://github.com/NginxProxyManager/nginx-proxy-manager/blob/14b889a85f2f8af9a13ed6122f5a0a91d64ecc36/backend/internal/certificate.js#L131 if you create a new certificate that has a domain name in that is already in another cert then the site using that other cert gets disabled while the new cert is being created)

I'm rereading what you are saying and I think I understand what you are saying Port 80 is always listening and you'd like to be able to disable port 80 completely (except for cert renewals) ?

If that is the case then I don't think this is done because of LE ... this is simply the way NPM sets up its server config files you kinda have have to have it listening on port 80 else how would you serve up sites that you don't want SSLd ? and if you enable "force SSL" on a site then extra config is injected for that site that puts in that redirect you posted.

OK you could argue that in this day and age why would you not SSL everything but this is a generic Proxy, you have to account for all use cases and as you pointed out yourself having port 80 open is no real security threat - though changing the default site to something other than the Congratulations and 404 page is probably a good idea as both of those give hints as to what is running ... the custom page option does too as it sets the server header :( But that doesn't really increase the attack surface just gives them a little more info that will save them all of 10 seconds.

waytosahil commented 2 years ago

I see it is mentioned in above thread that request is sent to Let's Encrypt only if the cert is due for renewal and renewal check done locally (my understanding from above thread).

One observation from my setup, I have 19 certs installed and I can see in the last 24 hrs ~700 requests were made by NPM to lencr.org , which are too many request in my opinion for certs with expiry time > 2 Months. May be if we can have an option to manage it would really help optimize things.

pShota commented 1 year ago

(bump) may I ask any update on this?

kirby12bit commented 1 year ago

I would like to add to this thread (know it's old but it's still open) this is causing a hiccup with using streams. I am running minecraft servers and this is causing external connections to drop during each reload.

sercanyaldiz commented 1 year ago

Any update on this?

My certificate expires 11th July 2023, 2:45 am

Why does NPM renew my SSL cert every 1 hour?

[5/4/2023] [3:19:54 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[5/4/2023] [3:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [3:19:54 PM] [SSL      ] › ℹ  info      Renew Complete
[5/4/2023] [4:19:54 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[5/4/2023] [4:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [4:19:54 PM] [SSL      ] › ℹ  info      Renew Complete
[5/4/2023] [5:19:54 PM] [IP Ranges] › ℹ  info      Fetching IP Ranges from online services...
[5/4/2023] [5:19:54 PM] [IP Ranges] › ℹ  info      Fetching https://ip-ranges.amazonaws.com/ip-ranges.json
[5/4/2023] [5:19:54 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[5/4/2023] [5:19:54 PM] [IP Ranges] › ℹ  info      Fetching https://www.cloudflare.com/ips-v4
[5/4/2023] [5:19:54 PM] [IP Ranges] › ℹ  info      Fetching https://www.cloudflare.com/ips-v6
[5/4/2023] [5:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [5:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [5:19:54 PM] [SSL      ] › ℹ  info      Renew Complete
[5/4/2023] [6:19:54 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[5/4/2023] [6:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [6:19:54 PM] [SSL      ] › ℹ  info      Renew Complete
[5/4/2023] [7:19:54 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[5/4/2023] [7:19:54 PM] [Nginx    ] › ℹ  info      Reloading Nginx
[5/4/2023] [7:19:54 PM] [SSL      ] › ℹ  info      Renew Complete
JOHLC commented 1 year ago

I also agree that a configurable renewal period would be a good feature. I have multiple instances requesting certs, every hour seems excessive.

MyCleverGirl commented 1 year ago

ugh im having the same issues, every hour all domains go offline untill its done and reloads, i tried to change the (1000 60 60) to 30 days and i get a sqlite error in docker logs and system breaks till i re- add (1000 60 60). im thinking of looking for alternative software, its a great program but this issue makes me wanna go elese were. they need to have a area in the online portal to allow us to change this based off user needs.

fullmetalbrackets commented 1 year ago

This issue has been open since 2020, will it ever be resolved or even acknowledged by the maintainers? I don't even use SSL certificates, I only proxy my Docker containers to *.home.arpa locally via http, and it still does this renewal every hour on the hour. There aren't even any SSL certificates to renew!

HomemadeAdvanced commented 1 year ago

Nginx Proxy Manager V3 will be released. It is in development since two years. So it is obvious that the developers invest not that much afford into the NPM V2 anymore. https://github.com/NginxProxyManager/nginx-proxy-manager/discussions/1202

github-actions[bot] commented 6 months ago

Issue is now considered stale. If you want to keep it open, please comment :+1:

HomemadeAdvanced commented 6 months ago

Is still an issue.