Self-hosted service
jlesage/docker-nginx-proxy-manager avatar
jlesage/docker-nginx-proxy-manager

jlesage's Nginx Proxy Manager container treats the image as the product

Docker container for Nginx Proxy Manager

882 stars201 forksShellMIT

At a glance

What is it?
docker-nginx-proxy-manager is an unofficial Docker image for Nginx Proxy Manager that pins every dependency in its Dockerfile and exposes its behaviour through environment variables. It suits a homelab operator who wants a reproducible reverse proxy with free SSL, and it is one layer of trust away from the upstream project.
Who is it for?
jlesage's container suits a homelab operator or a small team that wants Nginx Proxy Manager running as a pinned, reproducible image with the data on a volume and the configuration in environment variables, and who accepts running an unofficial image.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Unofficial, and the README says so twice

The project provides a lightweight and secure Docker container for Nginx Proxy Manager, and the very first note in the README is the one an adopter has to read before anything else. This Docker container is entirely unofficial and not made by the creators of Nginx Proxy Manager.

That statement matters more here than it would for a typical wrapper, because the container is not a thin shim. The Dockerfile pins OpenResty at 1.29.2.5, Nginx Proxy Manager at 2.16.0, the Nginx HTTP GeoIP2 module at 3.3, libmaxminddb at 1.5.0, the bcrypt tool at 1.1.2 and Certbot at 5.3.1. The build then compiles the upstream Nginx Proxy Manager from a source tarball, with the build argument pointing at the GitHub archive for that version.

So the container is a rebuild of the upstream application with a specific set of dependencies, not a pull of an official image. The upstream tarball URL is built from the version argument, and the Nginx Proxy Manager source is copied in from a build directory and compiled by a script.

The motivation for that approach is visible in the rest of the build. The image uses a cross-compilation helper stage, and there is a stage that fetches UPX, the executable packer, with a note that UPX 5.x is not compatible with old kernels such as 3.10 used by some Synology NASes, with a link to the upstream issue. The result is a small, self-contained image with the binary compressed, and the compression stage pinned to a UPX version that works on those older kernels.

The upstream project itself is described in the README in terms of the user: Nginx Proxy Manager enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt. The container's job is to make that experience repeatable on a machine where the operator does not want to manage an Nginx installation.

The quick start publishes three ports and one volume

The quick start is a single docker run command, and the README marks it as an example whose parameters should be adjusted to suit your needs.

shell
docker run -d \
    --name=nginx-proxy-manager \
    -p 8181:8181 \
    -p 8080:8080 \
    -p 4443:4443 \
    -v /docker/appdata/nginx-proxy-manager:/config:rw \
    jlesage/nginx-proxy-manager

Three ports are published. Port 8181 is the management GUI, and the README tells you to browse to http://your-host-ip:8181 to reach it. Ports 8080 and 4443 are the proxy listeners, one for ordinary HTTP and one for the TLS side, and publishing them is what lets the container terminate traffic for your sites.

The volume is the part that matters most in practice. /docker/appdata/nginx-proxy-manager is described as storing the application's configuration, state, logs, and any files requiring persistency, and it is mounted at /config with read and write access. The naming follows the jlesage convention of putting application data under /docker/appdata, which is worth knowing if you are comparing it with the upstream container's layout, because the two do not put their data in the same place.

The general usage pattern is given in the same shorthand:

shell
docker run [-d] \
    --name=nginx-proxy-manager \
    [-e <VARIABLE_NAME>=<VALUE>]... \
    [-v <HOST_DIR>:<CONTAINER_DIR>[:PERMISSIONS]]... \
    [-p <HOST_PORT>:<CONTAINER_PORT>]... \
    jlesage/nginx-proxy-manager

The parameter table that follows is short. -d runs the container in the background rather than the foreground. -e passes an environment variable. -v sets a volume mapping to share a folder or file between the host and the container. -p sets a network port mapping to expose an internal container port to the host.

Environment variables are the configuration surface

The container's behaviour is configured through environment variables, and the table is long enough that it is worth reading before the first run rather than after a problem.

The ownership variables come first. USER_ID is the ID of the user the application runs as, defaulting to 1000, and GROUP_ID does the same for the group, also 1000. SUP_GROUP_IDS takes a comma-separated list of supplementary group IDs, with no default value.

Then there is UMASK, the mask controlling permissions for newly created files and folders, specified in octal notation. The default is 0022, which ensures files and folders are readable by all but writable only by the owner, and the README links a umask calculator. This matters more than it sounds, because a reverse proxy writes certificates and keys into the data directory, and the umask decides who can read them.

The localisation pair is LANG, which sets the locale and the application's language if supported, in the format language[_territory][.codeset], defaulting to en_US.UTF-8, and TZ, the timezone, defaulting to Etc/UTC, with a note that the timezone can also be set by mapping /etc/localtime between the host and the container.

The operational variables follow. KEEP_APP_RUNNING, set to 1, automatically restarts the application if it crashes or terminates, and defaults to 0. APP_NICENESS sets the priority at which the application runs, where -20 is the highest and 19 the lowest, defaulting to 0, with an explicit warning that a negative niceness requires the container to be run with the Docker option --cap-add=SYS_NICE.

Then there is the package installation pair. INSTALL_PACKAGES takes a space-separated list of packages to install during container startup, with a link to the Alpine Linux package index, and PACKAGES_MIRROR sets the mirror to use, with a link to the mirror list. Both have no default value.

And there are two switches for diagnosis. CONTAINER_DEBUG, set to 1, enables debug logging, and DISABLE_IPV6, set to 1, disables IPv6 support, which the README says is needed when IPv6 is not enabled or supported on the host.

Running as a specific user, and the operational trade-off

The section on user and group IDs exists because a container that runs as root leaves files in your data directory that root owns, and the next container start as a different user cannot write them. The USER_ID and GROUP_ID variables exist to avoid that, and the README is explicit that they must be decided before the first run rather than adjusted later, because the files already written to the volume carry the ownership of whoever created them.

That is the central operational difference between this image and a typical upstream container, and it is worth weighing alongside the fact that the environment variable table offers no equivalent of the upstream options for automatic certificate renewal. A reverse proxy that issues certificates is a process that holds private keys and contacts an ACME endpoint on a schedule, and how much of that you want to configure from the environment rather than from the application interface is a judgement the user has to make.

The debugging and access features are grouped in the same way. There is a section on shell access, one on accessing the GUI, and one on accessibility from the internet, which is the one to read carefully if the management interface is going to be reachable from outside the local network, since that interface can create hosts and certificates and therefore must not be exposed carelessly. There is also a section on changing parameters of a running container, which is a real constraint of the environment variable model: a variable is read at startup, so changing it means recreating the container, not reloading it.

The troubleshooting section has a password reset procedure, which tells you the management interface stores its own credentials in the data volume, and a support section for the container itself. The distinction between the two is worth keeping straight, because a problem with certificate renewal is an upstream matter and a problem with the container refusing to start is not.

Image tags follow the calendar, and the base is Alpine

The image versioning scheme is unusual enough to be worth reading. The recent releases are v26.10.1 on 2026-10-05, v26.09.1 on 2026-09-22 and v26.08.2 on 2026-08-17, so the tag carries the year and the month rather than a semver version. The Dockerfile also refers to a DOCKER_IMAGE_VERSION build argument, and the DOCKERHUB.md file at the root of the repository is presumably the Docker Hub landing page.

A calendar-based tag is a reasonable choice for a container whose purpose is to track a moving upstream, and it tells an operator exactly how old their image is. The cost is that there is no indication of whether a given tag contains a breaking change, and an operator who wants reproducibility has to pin an exact tag rather than a major version.

The build base is Alpine, on version 3.23 as of the Dockerfile in the repository, and the packer stage and the build stage both use it. The cross-compilation helper comes from the tonistiigi/xx image, and the pattern of running the build under the build platform while targeting another is the standard way to produce a multi-architecture image without emulation.

There is a companion set of files in the rootfs and src directories, and an appdefs.yml, which is the file format used to describe an application to the LinuxServer.io-style app definition tooling, along with the DOCKERHUB.md. The repository is a GitHub Actions workflow for building the image, and the build status badge points at build-image.yml on the master branch.

On maintenance, the facts are that the repository is not archived, the last push was on 2026-10-05, and the release cadence is a monthly image. The licence is MIT with a LICENSE file at the root, and the Donate badge points at a PayPal link, so the project is maintained by one person as a personal contribution rather than by the upstream project.

Editorial conclusion

jlesage's container suits a homelab operator or a small team that wants Nginx Proxy Manager running as a pinned, reproducible image with the data on a volume and the configuration in environment variables, and who accepts running an unofficial image. It is the wrong tool if you need the upstream project behind the container, since the README is explicit that this image is entirely unofficial and not made by the creators of Nginx Proxy Manager, and it is the wrong tool if you need automatic certificate renewal across many domains with a supported upstream. Before you adopt it, read the environment variable table in full, because the defaults are not the ones an upstream container would use, and decide on the user and group IDs before the first run, since changing them later means rewriting ownership on the data directory.

Frequently asked questions

How do I start the jlesage Nginx Proxy Manager container?

The README gives a docker run command publishing ports 8181, 8080 and 4443 and mounting /docker/appdata/nginx-proxy-manager at /config with read and write access, using the jlesage/nginx-proxy-manager image. You then reach the management interface at http://your-host-ip:8181.

Is this Nginx Proxy Manager container official?

No. The README states that this Docker container is entirely unofficial and not made by the creators of Nginx Proxy Manager, and the project is published under the jlesage organisation as a separate community effort.

Which user and group does the container run as?

The USER_ID and GROUP_ID environment variables set the user and group the application runs as, and both default to 1000. The README also documents SUP_GROUP_IDS for supplementary group IDs and UMASK, which defaults to 0022 so files are readable by all but writable only by the owner.

How are the Docker image tags versioned?

By calendar rather than semver. The recent releases are v26.10.1, v26.09.1 and v26.08.2, so the tag carries the year and month of the build, and the Dockerfile takes the image version through a DOCKER_IMAGE_VERSION build argument.

Official sources

  1. Issues
  2. jlesage/docker-nginx-proxy-manager on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jlesage-docker-nginx-proxy-manager.svg)](https://hysenlabs.com/projects/jlesage-docker-nginx-proxy-manager)

Was this useful?