# Deploy rootless using Docker Compose Type of document: How-to guide Product: NGINX Instance Manager > Deploy F5 NGINX Instance Manager in a rootless Docker environment using Docker Compose, with runtime configuration injection using environment variables. --- ## Overview This guide shows you how to deploy F5 NGINX Instance Manager using Docker Compose in a **rootless** configuration. In this setup, all container processes run as a non-root user (`nms`), following the principle of least privilege for production environments. A key capability of this deployment is **runtime configuration injection**: you can change NGINX Instance Manager settings by editing environment variable files and restarting the stack. You don't need to rebuild the Docker image. Key characteristics of this deployment: - **Rootless by design** — All processes run as `nms` (non-root), reducing the attack surface and satisfying security hardening requirements. - **Runtime configuration** — Change NGINX Instance Manager settings by updating `.env` and `docker-compose.yaml`. You don't need to rebuild the image. - **Production-hardened** — Startup scripts are idempotent and avoid fragile patterns such as recursive permission changes. - **Flexible licensing** — Supports both connected and disconnected license modes, switchable at runtime. --- ## What you need Before you begin, make sure you have the following: - [Docker Engine](https://docs.docker.com/get-docker/) 20.10 or later installed on a Linux host (amd64 or arm64). - Docker Compose plugin v2 or later. - A valid NGINX Instance Manager license file, base64-encoded. - An NGINX certificate and private key, required to download NGINX Instance Manager packages during image build. - Basic familiarity with Docker Compose and YAML syntax. --- ## Before you start Clone the deployment repository to your host machine: ```shell git clone https://github.com/nginx/nginx-demos.git cd nginx-demos/nginx-instance-manager/docker-deployment ``` --- ## Build the NGINX Instance Manager image Run the build script, supplying your NGINX certificate, key, and a name for the resulting image: ```shell ./build.sh -C -K -t ``` Replace the placeholders: - `` — Path to your NGINX TLS certificate file. - `` — Path to your NGINX TLS private key file. - `` — Your preferred Docker image tag (for example, `nim:latest`). The build script downloads NGINX Instance Manager packages from the NGINX repository using your certificate and key, and produces a self-contained rootless image. --- ## Configure environment variables Edit `docker-compose/.env` and set the following values: ```shell NIM_IMAGE= NIM_LICENSE= NIM_USERNAME= NIM_PASSWORD= NIM_CLICKHOUSE_ADDRESSPORT=docker-compose-clickhouse-1:9000 NIM_CLICKHOUSE_USERNAME= NIM_CLICKHOUSE_PASSWORD= NIM_LICENSE_MODE_OF_OPERATION=connected ``` Replace `` with the tag used in the build step, and `` with your base64-encoded NGINX Instance Manager license. Set `NIM_LICENSE_MODE_OF_OPERATION` to `connected` or `disconnected` depending on your environment (see [License modes](#license-modes) below). **Note:** Change `NIM_USERNAME` and `NIM_PASSWORD` to values appropriate for your environment before deploying to production. --- ## Verify docker-compose.yaml environment mappings Open `docker-compose.yaml` and confirm that the `nim` service passes all required variables into the container: ```yaml environment: - NIM_LICENSE=${NIM_LICENSE} - NIM_USERNAME=${NIM_USERNAME} - NIM_PASSWORD=${NIM_PASSWORD} - NIM_CLICKHOUSE_ADDRESSPORT=${NIM_CLICKHOUSE_ADDRESSPORT} - NIM_CLICKHOUSE_USERNAME=${NIM_CLICKHOUSE_USERNAME} - NIM_CLICKHOUSE_PASSWORD=${NIM_CLICKHOUSE_PASSWORD} - NIM_LICENSE_MODE_OF_OPERATION=${NIM_LICENSE_MODE_OF_OPERATION} ``` If you add new configuration variables later, add a corresponding line here to make the value available inside the container. --- ## Start the stack Start NGINX Instance Manager and its dependencies (including ClickHouse) with: ```shell docker compose -f docker-compose.yaml up -d ``` --- ## Access the NGINX Instance Manager web interface When the containers are running, open a browser and go to: ```text https://localhost/ ``` Accept the self-signed TLS certificate warning if prompted. Log in using the `NIM_USERNAME` and `NIM_PASSWORD` values you set in `.env`. --- ## How runtime configuration injection works When the NGINX Instance Manager container starts, `startNIM.sh` reads the environment variables that Docker Compose passes in. It writes their values into the NGINX Instance Manager configuration files using `yq`, a YAML processor. The two configuration files are: - `/etc/nms/nms.conf` - `/etc/nms/nms-sm-conf.yaml` This means NGINX Instance Manager applies fresh configuration on every container start. You change a setting by updating the variable in `.env` and restarting the stack. You don't need to rebuild the image. The script exposes two helper functions: - `set_nms_conf` — writes a value to a key path in `nms.conf`. - `set_nms_sm` — writes a value to a key path in `nms-sm-conf.yaml`. --- ## Add or change NGINX Instance Manager configuration To inject a new or changed configuration value, complete these steps: 1. **Add the variable to `.env`** ```shell MY_NEW_SETTING=myvalue ``` 2. **Pass the variable into the container in `docker-compose.yaml`** ```yaml environment: - MY_NEW_SETTING=${MY_NEW_SETTING} ``` 3. **Map the variable to a config key in `startNIM.sh`** ```shell # For nms.conf: set_nms_conf '.path.to.config.key' MY_NEW_SETTING # For nms-sm-conf.yaml: set_nms_sm '.path.to.config.key' MY_NEW_SETTING ``` Then restart the stack to apply the change: ```shell docker compose -f docker-compose.yaml up -d ``` You don't need to rebuild the image. --- ## License modes {#license-modes} NGINX Instance Manager supports two license operating modes. The correct choice depends on whether your host has outbound internet access to the NGINX licensing service. ### Connected mode NGINX Instance Manager contacts the NGINX licensing service directly over the internet. Use this mode when the host has reliable outbound HTTPS access. Set in `.env`: ```shell NIM_LICENSE_MODE_OF_OPERATION=connected ``` ### Disconnected mode NGINX Instance Manager operates without outbound internet access and validates the license locally. Use this mode for air-gapped or restricted environments. Set in `.env`: ```shell NIM_LICENSE_MODE_OF_OPERATION=disconnected ``` ### Switch modes at runtime To change the license mode without rebuilding the image: 1. Update `NIM_LICENSE_MODE_OF_OPERATION` in `docker-compose/.env`. 2. Confirm the variable is listed under `environment:` in the `nim` service in `docker-compose.yaml`. 3. Confirm the mapping exists in `startNIM.sh`: ```shell set_nms_conf '.integrations.license.mode_of_operation' NIM_LICENSE_MODE_OF_OPERATION ``` 4. Restart the stack: ```shell docker compose -f docker-compose.yaml up -d ``` --- ## Stop or remove services To stop the running stack: ```shell docker compose -f docker-compose.yaml stop ``` To stop and remove containers and networks: ```shell docker compose -f docker-compose.yaml down ``` --- ## Troubleshooting ### Permission errors on startup All processes run as the `nms` non-root user. If you see permission errors, check that any host-mounted volumes are readable and writable by the `nms` user. Avoid using recursive `chown` or `chmod` commands, because these can interfere with rootless operation. ### Configuration changes not taking effect If an updated variable has no effect after a restart, verify all three steps were completed: - The variable is defined in `.env` with the correct value. - The variable is listed under `environment:` in the `nim` service in `docker-compose.yaml`. - A `set_nms_conf` or `set_nms_sm` call for that variable exists in `startNIM.sh`. - The stack was fully restarted (`docker compose up -d` re-creates containers on config change). ### View container logs To inspect startup output and verify configuration injection ran successfully: ```shell docker compose -f docker-compose.yaml logs nim docker compose -f docker-compose.yaml logs clickhouse ``` ### Check running container state ```shell docker compose -f docker-compose.yaml ps ``` --- ## See also - [Deploy using Docker Compose](nim/deploy/docker/deploy-nginx-instance-manager-docker-compose.md) — Standard (non-rootless) Docker Compose deployment. - [NGINX Instance Manager Documentation](https://docs.nginx.com/nginx-instance-manager/) - [yq YAML Processor](https://mikefarah.gitbook.io/yq/) - [Docker Compose Documentation](https://docs.docker.com/compose/)