[GH-ISSUE #1417] Add option for custom ACME CA #1109

Open
opened 2026-02-26 06:35:47 +03:00 by kerem · 23 comments
Owner

Originally created by @ionrover2 on GitHub (Sep 22, 2021).
Original GitHub issue: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1417

Is your feature request related to a problem? Please describe.
I would like this tool to be used with a self signed CA in an internal environment that has an acme compliant server. I'm currently using Step CA for my acme compliant server. I currently don't have the option to use my own acme server without a ton of involved reconfiguration.

Describe the solution you'd like
An advanced configuration option where you can upload a self signed CA and give a custom acme compliant url to be used with a given host.

Describe alternatives you've considered
I am currently using a combination of jwilder/nginx-proxy and the encrypt companion to accomplish the same task with a custom acme CA, but it would be ideal to have a graphical frontend for a reverse proxy that can pull a valid internal cert, route traffic to separate physical hosts as needed and also the underlying containers running on the same machine.

Additional context

Originally created by @ionrover2 on GitHub (Sep 22, 2021). Original GitHub issue: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1417 <!-- Are you in the right place? - If you are looking for support on how to get your upstream server forwarding, please consider asking the community on Reddit. - If you are writing code changes to contribute and need to ask about the internals of the software, Gitter is the best place to ask. - If you think you found a bug with NPM (not Nginx, or your upstream server or MySql) then you are in the *right place.* --> **Is your feature request related to a problem? Please describe.** I would like this tool to be used with a self signed CA in an internal environment that has an acme compliant server. I'm currently using Step CA for my acme compliant server. I currently don't have the option to use my own acme server without a ton of involved reconfiguration. **Describe the solution you'd like** An advanced configuration option where you can upload a self signed CA and give a custom acme compliant url to be used with a given host. **Describe alternatives you've considered** I am currently using a combination of jwilder/nginx-proxy and the encrypt companion to accomplish the same task with a custom acme CA, but it would be ideal to have a graphical frontend for a reverse proxy that can pull a valid internal cert, route traffic to separate physical hosts as needed and also the underlying containers running on the same machine. **Additional context** <!-- Add any other context or screenshots about the feature request here. -->
Author
Owner
<!-- gh-comment-id:1074836566 --> @NetHero-es commented on GitHub (Mar 22, 2022): Are there any plans to integrate this feature? I'm having the exact same requirement. Related to https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1884 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1054 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/301 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/944
Author
Owner

@francescocaponio commented on GitHub (Feb 11, 2023):

I'm using NPM both for intranet traffic and for traffic coming from outside. For the latter, it works amazingly as it is, for the internal, would be nice if it could work with Smallstep CA (ACME and compatible with certbot) and avoid the manual certificate renewal every year for each service!

<!-- gh-comment-id:1426702752 --> @francescocaponio commented on GitHub (Feb 11, 2023): I'm using NPM both for intranet traffic and for traffic coming from outside. For the latter, it works amazingly as it is, for the internal, would be nice if it could work with Smallstep CA (ACME and compatible with certbot) and avoid the manual certificate renewal every year for each service!
Author
Owner

@SantaSpeen commented on GitHub (Jan 6, 2024):

+1

<!-- gh-comment-id:1879835769 --> @SantaSpeen commented on GitHub (Jan 6, 2024): +1
Author
Owner

@lriley2020 commented on GitHub (Feb 17, 2024):

Would love it if this feature was added!

<!-- gh-comment-id:1950409302 --> @lriley2020 commented on GitHub (Feb 17, 2024): Would love it if this feature was added!
Author
Owner

@vshaev commented on GitHub (Feb 18, 2024):

+1

<!-- gh-comment-id:1951033832 --> @vshaev commented on GitHub (Feb 18, 2024): +1
Author
Owner

@charliemaiors commented on GitHub (Feb 21, 2024):

+1

<!-- gh-comment-id:1956879402 --> @charliemaiors commented on GitHub (Feb 21, 2024): +1
Author
Owner

@francescocaponio commented on GitHub (Feb 21, 2024):

Just an update, since during the last days there was some traffic on this thread.

By changing the certbot config file, adding the server directive, we were able to point to a local labca instance instead of let's encrypt. Of course, after this mod, all npm domains will ask the local ACME server instead of let's encrypt.

We were able to make it work, but then we had problems with the renewal of the certificates after three months.

We are waiting for the solution of this issue, if everything works properly, we will share the details on how to edit the file.

By the way, since it's a patch to be applied after the release of the official npm image, it should be reapplied per each new version release until there is no real support for multiple ACME servers together implemented in the webapp.

<!-- gh-comment-id:1957871248 --> @francescocaponio commented on GitHub (Feb 21, 2024): Just an update, since during the last days there was some traffic on this thread. By changing the certbot config file, adding the server directive, we were able to point to a local labca instance instead of let's encrypt. Of course, after this mod, all npm domains will ask the local ACME server instead of let's encrypt. We were able to make it work, but then we had problems with the renewal of the certificates after three months. We are waiting for the solution of [this issue](https://github.com/hakwerk/labca/issues/114), if everything works properly, we will share the details on how to edit the file. By the way, since it's a patch to be applied after the release of the official npm image, it should be reapplied per each new version release until there is no real support for multiple ACME servers together implemented in the webapp.
Author
Owner

@francescocaponio commented on GitHub (Mar 5, 2024):

So, this is my temporary solution:

I create my own container with this Dockerfile for each new version of NPM:

FROM docker.io/jc21/nginx-proxy-manager:2.11.1

RUN curl http://<internal_http_server>.lan/rootca.crt -o rootca.crt \
    && mv rootca.crt /usr/local/share/ca-certificates/rootca.crt \
    && update-ca-certificates

RUN echo -e "\nserver=https://labca.lan/directory\n" >> /etc/letsencrypt.ini

RUN sed -i "s\Let's Encrypt\LabCa\g" /app/frontend/js/*.js

This custom container can only work with the internal CA instance and not with Let's Encrypt. You can't have both. If you need also external domain you must run a second instance of NPM.

After this, I run the container in the same way I did before with the original NPM container, but I'm able to create and renew internal certificates with LabCA:

image
<!-- gh-comment-id:1979284055 --> @francescocaponio commented on GitHub (Mar 5, 2024): So, this is my temporary solution: I create my own container with this Dockerfile for each new version of NPM: ``` FROM docker.io/jc21/nginx-proxy-manager:2.11.1 RUN curl http://<internal_http_server>.lan/rootca.crt -o rootca.crt \ && mv rootca.crt /usr/local/share/ca-certificates/rootca.crt \ && update-ca-certificates RUN echo -e "\nserver=https://labca.lan/directory\n" >> /etc/letsencrypt.ini RUN sed -i "s\Let's Encrypt\LabCa\g" /app/frontend/js/*.js ``` This custom container can only work with the internal CA instance and not with Let's Encrypt. You can't have both. If you need also external domain you must run a second instance of NPM. After this, I run the container in the same way I did before with the original NPM container, but I'm able to create and renew internal certificates with [LabCA](https://github.com/hakwerk/labca/): <img width="949" alt="image" src="https://github.com/NginxProxyManager/nginx-proxy-manager/assets/66728654/73ab96d5-70bc-4ce6-bd0e-6e24c883807b">
Author
Owner

@accessiblepixel commented on GitHub (Mar 8, 2024):

FROM docker.io/jc21/nginx-proxy-manager:2.11.1

RUN curl http://<internal_http_server>.lan/rootca.crt -o rootca.crt
&& mv rootca.crt /usr/local/share/ca-certificates/rootca.crt
&& update-ca-certificates

RUN echo -e "\nserver=https://labca.lan/directory\n" >> /etc/letsencrypt.ini

RUN sed -i "s\Let's Encrypt\LabCa\g" /app/frontend/js/*.js

Hmm. I tried using your solution @francescocaponio but whenever I try to issue a new certificate I get:
Certificate is not valid (Cannot read properties of null (reading '1'))

I'm using stepca as the bases for my ACME server. According to the logs from stepca the certificate gets issued but it seems that nginxproxymanager UI doesn't know what to do with it. Don't suppose you have any ideas?

From the logs it looks like it does indeed get issued...

app_1  | Successfully received certificate.
app_1  | Certificate is saved at: /etc/letsencrypt/live/npm-9/fullchain.pem
app_1  | Key is saved at:         /etc/letsencrypt/live/npm-9/privkey.pem
app_1  | This certificate expires on 2024-03-09.
app_1  | These files will be updated when the certificate renews.
<!-- gh-comment-id:1986150569 --> @accessiblepixel commented on GitHub (Mar 8, 2024): > FROM docker.io/jc21/nginx-proxy-manager:2.11.1 > > RUN curl http://<internal_http_server>.lan/rootca.crt -o rootca.crt \ > && mv rootca.crt /usr/local/share/ca-certificates/rootca.crt \ > && update-ca-certificates > > RUN echo -e "\nserver=https://labca.lan/directory\n" >> /etc/letsencrypt.ini > > RUN sed -i "s\Let's Encrypt\LabCa\g" /app/frontend/js/*.js Hmm. I tried using your solution @francescocaponio but whenever I try to issue a new certificate I get: ``Certificate is not valid (Cannot read properties of null (reading '1'))`` I'm using stepca as the bases for my ACME server. According to the logs from stepca the certificate gets issued but it seems that nginxproxymanager UI doesn't know what to do with it. Don't suppose you have any ideas? From the logs it looks like it does indeed get issued... ``` app_1 | Successfully received certificate. app_1 | Certificate is saved at: /etc/letsencrypt/live/npm-9/fullchain.pem app_1 | Key is saved at: /etc/letsencrypt/live/npm-9/privkey.pem app_1 | This certificate expires on 2024-03-09. app_1 | These files will be updated when the certificate renews. ```
Author
Owner

@francescocaponio commented on GitHub (Mar 8, 2024):

Hi,
I also have the same log

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/npm-15/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/npm-15/privkey.pem
This certificate expires on 2024-06-04.
These files will be updated when the certificate renews.
NEXT STEPS:
...

try to analyze the content of the file /tmp/letsencrypt-log/letsencrypt.log of the npm container for a DEBUG level log of certbot, and check also the stepca logs to understand better where the problem could be.

<!-- gh-comment-id:1986200526 --> @francescocaponio commented on GitHub (Mar 8, 2024): Hi, I also have the same log ``` Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/npm-15/fullchain.pem Key is saved at: /etc/letsencrypt/live/npm-15/privkey.pem This certificate expires on 2024-06-04. These files will be updated when the certificate renews. NEXT STEPS: ... ``` try to analyze the content of the file `/tmp/letsencrypt-log/letsencrypt.log` of the npm container for a DEBUG level log of certbot, and check also the stepca logs to understand better where the problem could be.
Author
Owner

@oldboys92 commented on GitHub (Mar 24, 2024):

@accessiblepixel

Hmm. I tried using your solution @francescocaponio but whenever I try to issue a new certificate I get: Certificate is not valid (Cannot read properties of null (reading '1'))

I'm using stepca as the bases for my ACME server. According to the logs from stepca the certificate gets issued but it seems that nginxproxymanager UI doesn't know what to do with it. Don't suppose you have any ideas?

The problem is caused by npm certbot, which after spending some hours I've just discovered that it removes the subject in the CSR. Also the default Step CA ACME provisioner configuration is not adding a CN/subject, when the CSR has none and this is what the problem is.

To solve you need to add

  "forceCN": true,

in your step-ca config ca.json.

Mine looks now like this and certificates are issued without issues.

                        {
                                "type": "ACME",
                                "name": "acme",
                                "forceCN": true
                        }

Hope this helps you.

<!-- gh-comment-id:2016970067 --> @oldboys92 commented on GitHub (Mar 24, 2024): @accessiblepixel > Hmm. I tried using your solution @francescocaponio but whenever I try to issue a new certificate I get: `Certificate is not valid (Cannot read properties of null (reading '1'))` > > I'm using stepca as the bases for my ACME server. According to the logs from stepca the certificate gets issued but it seems that nginxproxymanager UI doesn't know what to do with it. Don't suppose you have any ideas? The problem is caused by npm `certbot`, which after spending some hours I've just discovered that it removes the `subject` in the CSR. Also the default Step CA ACME provisioner configuration is not adding a `CN`/`subject`, when the CSR has none and this is what the problem is. To solve you need to add ```JSON "forceCN": true, ``` in your step-ca config `ca.json`. Mine looks now like this and certificates are issued without issues. ```JSON { "type": "ACME", "name": "acme", "forceCN": true } ``` Hope this helps you.
Author
Owner

@oldboys92 commented on GitHub (Mar 24, 2024):

@francescocaponio thank you for your cool solution, the workaround is working like a charm 🖖

PS: it cost me some time, till I realized your sed had a small typo. You used \ instead of / for the regex.

<!-- gh-comment-id:2016973993 --> @oldboys92 commented on GitHub (Mar 24, 2024): @francescocaponio thank you for your cool solution, the workaround is working like a charm 🖖 PS: it cost me some time, till I realized your `sed` had a small typo. You used `\` instead of `/` for the regex.
Author
Owner

@lriley2020 commented on GitHub (Mar 24, 2024):

No disrespect to the project, but if you're facing these kinds of challenges, you might be starting to outgrow nginx-proxy-manager! It might be much easier in this scenario to just switch to plain old nginx, or another reverse proxy (eg: caddy). I just switched to caddy a few days ago for the better custom ACME provider support (and several other more advanced features). What you're trying to achieve here can be done in a few lines in a caddyfile:

my.domain.com {
    tls {
        issuer acme {
            dir https://ca.domain.com:8443/acme/acme/directory
	    trusted_roots /data/caddy/custom-certs/step-ca/step-ca.pem
        }
    }
    reverse_proxy * http://myappserver.local:8080
}


That's it! The whole configuration! The certs will auto renew, HTTPS redirect is implicitly enabled, all sorted. However please feel free to ignore me if you're happy with NPM :)

<!-- gh-comment-id:2016974349 --> @lriley2020 commented on GitHub (Mar 24, 2024): No disrespect to the project, but if you're facing these kinds of challenges, you might be starting to outgrow nginx-proxy-manager! It might be much easier in this scenario to just switch to plain old nginx, or another reverse proxy (eg: caddy). I just switched to caddy a few days ago for the better custom ACME provider support (and several other more advanced features). What you're trying to achieve here can be done in a few lines in a caddyfile: ``` my.domain.com { tls { issuer acme { dir https://ca.domain.com:8443/acme/acme/directory trusted_roots /data/caddy/custom-certs/step-ca/step-ca.pem } } reverse_proxy * http://myappserver.local:8080 } ``` That's it! The whole configuration! The certs will auto renew, HTTPS redirect is implicitly enabled, all sorted. However please feel free to ignore me if you're happy with NPM :)
Author
Owner

@oldboys92 commented on GitHub (Mar 25, 2024):

No disrespect to the project, but if you're facing these kinds of challenges, you might be starting to outgrow nginx-proxy-manager! It might be much easier in this scenario to just switch to plain old nginx, or another reverse proxy (eg: caddy). I just switched to caddy a few days ago for the better custom ACME provider support (and several other more advanced features). What you're trying to achieve here can be done in a few lines in a caddyfile:

@lriley2020 you are absolutely right, I had same thoughts too. I will probably switch myself to Caddy, but at least for NPM I wanted to see if there is a chance to get ACME working with another RA/CA, since it looked that, not much was missing. And in my case, the package was already there and was convenient to just use it.

<!-- gh-comment-id:2017835914 --> @oldboys92 commented on GitHub (Mar 25, 2024): > No disrespect to the project, but if you're facing these kinds of challenges, you might be starting to outgrow nginx-proxy-manager! It might be much easier in this scenario to just switch to plain old nginx, or another reverse proxy (eg: caddy). I just switched to caddy a few days ago for the better custom ACME provider support (and several other more advanced features). What you're trying to achieve here can be done in a few lines in a caddyfile: @lriley2020 you are absolutely right, I had same thoughts too. I will probably switch myself to Caddy, but at least for NPM I wanted to see if there is a chance to get ACME working with another RA/CA, since it looked that, not much was missing. And in my case, the package was already there and was convenient to just use it.
Author
Owner

@github-actions[bot] commented on GitHub (Oct 9, 2024):

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

<!-- gh-comment-id:2401125054 --> @github-actions[bot] commented on GitHub (Oct 9, 2024): Issue is now considered stale. If you want to keep it open, please comment :+1:
Author
Owner

@vshaev commented on GitHub (Oct 9, 2024):

+1

<!-- gh-comment-id:2401686734 --> @vshaev commented on GitHub (Oct 9, 2024): +1
Author
Owner

@gpend commented on GitHub (Apr 3, 2025):

+1

<!-- gh-comment-id:2776573838 --> @gpend commented on GitHub (Apr 3, 2025): +1
Author
Owner

@dwydler commented on GitHub (Jun 20, 2025):

+1

<!-- gh-comment-id:2991663791 --> @dwydler commented on GitHub (Jun 20, 2025): +1
Author
Owner

@mrkhachaturov commented on GitHub (Jun 30, 2025):

+1

<!-- gh-comment-id:3017372371 --> @mrkhachaturov commented on GitHub (Jun 30, 2025): +1
Author
Owner

@be-reich commented on GitHub (Jul 23, 2025):

+1

<!-- gh-comment-id:3105968237 --> @be-reich commented on GitHub (Jul 23, 2025): +1
Author
Owner

@SubniC commented on GitHub (Jul 23, 2025):

+1

<!-- gh-comment-id:3109443594 --> @SubniC commented on GitHub (Jul 23, 2025): +1
Author
Owner

@GLeurquin commented on GitHub (Aug 28, 2025):

Nginx introduced native ACME support: https://blog.nginx.org/blog/native-support-for-acme-protocol

This will probably be useful in implementing this feature.

<!-- gh-comment-id:3232128722 --> @GLeurquin commented on GitHub (Aug 28, 2025): Nginx introduced native ACME support: https://blog.nginx.org/blog/native-support-for-acme-protocol This will probably be useful in implementing this feature.
Author
Owner

@t984447 commented on GitHub (Nov 8, 2025):

+1
Looking around for alternatives JUST for this feature but would love it if NPM would allow for ACME towards custom CA .

<!-- gh-comment-id:3506149350 --> @t984447 commented on GitHub (Nov 8, 2025): +1 Looking around for alternatives JUST for this feature but would love it if NPM would allow for ACME towards custom CA .
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/nginx-proxy-manager-NginxProxyManager#1109
No description provided.