Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added built-in certificates autorenewal #35

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,30 @@ and keys in shared memory, then set variable with the zone name.

## Automatic Certificate Renewal

NGINX and NJS do not yet have a mechanism for running code on a time interval, which presents a challenge for certificate renewal. One workaround to this is to set something up to periodically request `/acme/auto` from the NGINX server.
Certificate renewal is automatically managed through active healthchecks to send a `GET` request to `/acme/auto` every 90 seconds. The relevant configuration section is

If running directly on a host, you can use `cron` to schedule a periodic request. When deploying in Kubernetes you can use a [liveness-check](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-http-request). If you are running in a `docker` context, you can use Docker's `healthcheck:` functionality to do this.
```nginx
# Internal upstream for automated certificates renewal
upstream acme_auto_renewal {
zone acme_auto_renewal 64k;
server 127.0.0.1:8000;
}

## Internal certificates renewal server
# GETs 127.0.0.1:8000/acme/auto every 90 seconds to automatically renews certificates
server {
location /internal_auto_renewal {
internal;

health_check interval=90;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea @fabriziofiorucci ! When I try this on my server (nginx-1.25.1) I get this error:

web-proxy-nginx-1  | nginx: [emerg] unknown directive "health_check" in /etc/nginx/nginx.conf:49

Looks like this may only be a non-OSS feature?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Active health checks are a NGINX Plus feature only and I found a bug in this, fixing now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Targeting OSS users is an important part of this project. NGINX is losing mindshare/marketshare due to the relative difficulty of doing basic things like HTTPS and auto-cert-renewal in OSS.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, there could be a fully automated option for those who wanted to use NGINX Plus, while OSS users might rely on k8s/crontab.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some NJS features nearing release that will let us run JS code on a time interval, so I think that solution will work for all :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can offer to add a separate plus-specific file under examples/nginx_plus.conf and have a separate section about the differences between OSS and plus wrt this auto-acme configuration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah IMO we should be OSS-first in our solution posture here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ivanitskiy @zsteinkamp if that works for you I can amend this PR with a dedicated nginx_plus.conf file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to separate OSS and Plus and don't mix them in a single example. (e.g. in Plus we can use KV instead of shared_dict and so on...)

health_check uri=/acme/auto;
proxy_pass http://acme_auto_renewal;
}
}

```

As an alternative you can comment out this section and use `cron` to schedule a periodic request. When deploying in Kubernetes you can use a [liveness-check](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-http-request). If you are running in a `docker` context, you can use Docker's `healthcheck:` functionality to do this.

Here is an example using `docker compose`:

Expand Down
20 changes: 19 additions & 1 deletion examples/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ events {
}

http {
# Internal upstream for automated certificates renewal
upstream acme_auto_renewal {
zone acme_auto_renewal 64k;
server 127.0.0.1:8000;
}

## Internal certificates renewal server
# GETs 127.0.0.1:8000/acme/auto every 90 seconds to automatically renews certificates
server {
location /internal_auto_renewal {
internal;

health_check interval=90;
health_check uri=/acme/auto;
proxy_pass http://acme_auto_renewal;
}
}

js_path "/usr/lib/nginx/njs_modules/";
js_fetch_trusted_certificate /etc/ssl/certs/ISRG_Root_X1.pem;

Expand All @@ -28,7 +46,7 @@ http {
js_shared_dict_zone zone=acme:1m;

server {
listen 0.0.0.0:8000; # testing with 8000 should be 80 in prod, pebble usees httpPort in dev/pebble/config.json
listen 0.0.0.0:8000; # testing with 8000 should be 80 in prod, pebble uses httpPort in dev/pebble/config.json
listen 443 ssl;
server_name proxy.nginx.com;

Expand Down