# Installing an Ignition Designer Plugin when spinning up a Docker Container

**URL:** <https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547>\
**Category:** Ignition\
**Tags:** docker\
**Created:** [January 26, 2026, 5:09pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547 "2026-01-26T17:09:59Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [January 26, 2026, 5:09pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/1 "2026-01-26T17:09:59Z")

</div>

I am doing some work with Ignition + Docker + Kubernetes and I wanted to know if it is possible to install a plugin module when spinning up an ignition container? I want to use the Tag CICD plugin to have better source control when working in Designer.

---

<div class="post-metadata">

**Author:** ![kcollins](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kcollins/32/19646_2.png) [@kcollins](https://forum.inductiveautomation.com/u/kcollins)\
**Post date:** [January 27, 2026, 3:13pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/2 "2026-01-27T15:13:03Z")

</div>

Some of this might depend on what version you're using (8.1.x or 8.3.x), but you've got a few options:

1. Build a derived image that places the module into `/usr/local/bin/ignition/user-lib/modules` alongside the other built-in modules. On 8.1.x, it will always be loaded if present. On 8.3.x, it will be loaded on a first-launch (fresh `data` volume) and treated as a built-in module (only able to be disabled, not uninstalled).
2. Use an init container to retrieve the module and place accordingly prior to launch of the main Ignition container. Again, your approach may vary based on version--Ignition 8.3.x uses a `data/modules.json` to define which modules should be loaded/enabled on startup.
3. On Docker only, you can simply bind-mount the module file directly into place.

With Ignition 8.3.x, you also have [new environment variables](https://docs.inductiveautomation.com/docs/8.3/appendix/reference-pages/platform-environment-variables) such as `ACCEPT_MODULE_LICENSES` and `ACCEPT_MODULE_CERTS` to automate auto-acceptance of third-party modules. If you're needing to integrate third-party modules in 8.1.x, you might find useful information in my [ignition-derived-example](https://github.com/thirdgen88/ignition-derived-example) repo.

Let me know if you'd like more information on any of these options based on what you think you need.

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [February 10, 2026, 1:08am UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/3 "2026-02-10T01:08:06Z")

</div>

Thank you, the links and this information is really helpful.

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [March 6, 2026, 4:14am UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/4 "2026-03-06T04:14:46Z")

</div>

Currently I have a docker compose file that is copying the third party module in along with updating the modules.json, so that ignition will be-able to detect it. The issue I am running into now is ignition is not automatically accepting the cert and license even though I am passing an environment variable with the module identifier. What do i need to do to automatically accept the licenses and certs?

```python
services:
  io-gateway:
    image: inductiveautomation/ignition:8.3.1
    container_name: mqtt-gw
    user: "0:0"
    ports:
      - "8088:8088"
      - "8043:8043"
    environment:
      ACCEPT_IGNITION_EULA: "Y"
      IGNITION_EDITION: "standard"
      DISABLE_QUICKSTART: "true"
      ACCEPT_MODULE_LICENSES: "com.cirruslink.mqtt.transmission.gateway"
      ACCEPT_MODULE_CERTS: "com.cirruslink.mqtt.transmission.gateway"

    command: ["-n", "io-gw","-m","2048","--","wrapper.java.initmemory=2048"]

    volumes:
      - ./modules/MQTT-Transmission-signed.modl:/usr/local/bin/ignition/data/local/modl/MQTT-Transmission-signed.modl
      - ./modules/modules.json:/usr/local/bin/ignition/data/modules.json

    restart: unless-stopped

```

---

<div class="post-metadata">

**Author:** ![kcollins](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kcollins/32/19646_2.png) [@kcollins](https://forum.inductiveautomation.com/u/kcollins)\
**Post date:** [March 6, 2026, 2:34pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/5 "2026-03-06T14:34:29Z")

</div>

First thing I'll mention is that ~~we~~ @hunterdg observed a documentation error with respect to the [location of user-installed modules](https://docs.inductiveautomation.com/docs/8.3/appendix/reference-pages/gateway-configuration-file-reference/gateway-and-gateway-network-parameters#docker-image-external-modules-folder) in the Ignition 8.3 Docker image. The correct location is `/usr/local/bin/ignition/data/var/ignition/modl`. Modules in this location will be automatically enabled on a fresh launch.

That said, if you're bind-mounting the module into place, you actually probably want to just put it in the standard location under `/usr/local/bin/ignition/user-lib/modules` since it is by-nature unremovable with that bind-mount.

Nonetheless, I'm guessing that something in the `modules.json` that you're linking into place is interfering with the auto-accept. Try making the location adjust above and removing the bind-mount of `modules.json`.

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [March 6, 2026, 7:57pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/6 "2026-03-06T19:57:58Z")

</div>

After changing the module path, ignition isn’t detecting the module. I tried composing with both `/usr/local/bin/ignition/data/var/ignition/modl` and `/usr/local/bin/ignition/user-lib/modules` and ignition still wouldn’t detect it. I checked the container with `docker exec -it mqtt-gw /bin/bash` and I can see the file is inside the container. The reason I was copying in the modules.json was to automatically add a reference to the third party module. That worked with getting ignition to detect it, but it didn’t work for automatically accepting the licenses and certs.

---

<div class="post-metadata">

**Author:** ![kcollins](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kcollins/32/19646_2.png) [@kcollins](https://forum.inductiveautomation.com/u/kcollins)\
**Post date:** [March 6, 2026, 8:14pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/7 "2026-03-06T20:14:31Z")

</div>

Is the compose snippet you posted complete? I didn't see a data volume, which means that it should integrate any of the .modl files from either of those folders on first-launch (since there won't be a pre-existing `data/modules.json`).

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [March 6, 2026, 9:22pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/8 "2026-03-06T21:22:32Z")

</div>

Ahh the compose snippet above is a previous version. this is the snippet I’ve been using:

```python
services:
  io-gateway:
    image: inductiveautomation/ignition:8.3.1
    container_name: mqtt-gw
    user: "0:0"
    ports:
      - "8088:8088"
      - "8043:8043"
    environment:
      ACCEPT_IGNITION_EULA: "Y"
      IGNITION_EDITION: "standard"
      DISABLE_QUICKSTART: "true"
      ACCEPT_MODULE_LICENSES: "com.cirruslink.mqtt.transmission.gateway"
      ACCEPT_MODULE_CERTS: "com.cirruslink.mqtt.transmission.gateway"
    command: ["-n", "io-gw","-m","2048","--","wrapper.java.initmemory=2048"]
    volumes:
      - ./io/mqtt/data:/usr/local/bin/ignition/data
      - ./modules/MQTT-Transmission-signed.modl:/usr/local/bin/ignition/user-lib/modules/MQTT-Transmission-signed.modl

    restart: unless-stopped

```

When I removed the data volume reference from the compose and ignition did detect and verify the custom module.

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [March 12, 2026, 5:58pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/9 "2026-03-12T17:58:30Z")

</div>

For anyone else that is looking for a solution to adding Third-Party modules, here is the docker-compose that worked for me.

```python
services:
  io-gateway:
    image: inductiveautomation/ignition:8.3.1
    container_name: mqtt-gw
    user: "0:0"
    ports:
      - "8088:8088"
      - "8043:8043"
    environment:
      ACCEPT_IGNITION_EULA: "Y"
      IGNITION_EDITION: "standard"
      DISABLE_QUICKSTART: "true"
      ACCEPT_MODULE_LICENSES: "com.cirruslink.mqtt.transmission.gateway"
      ACCEPT_MODULE_CERTS: "com.cirruslink.mqtt.transmission.gateway"
    command: ["-n", "io-gw","-m","2048","--","wrapper.java.initmemory=2048"]
    volumes:
      - ./io/mqtt/data:/usr/local/bin/ignition/data
      - ./modules/MQTT-Transmission-signed.modl:/usr/local/bin/ignition/user-lib/modules/MQTT-Transmission-signed.modl

    restart: unless-stopped

```

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [May 13, 2026, 7:35pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/10 "2026-05-13T19:35:53Z")

</div>

> [@kcollins](#):
>
> The correct location is `/usr/local/bin/ignition/data/var/ignition/modl`

in OrbStack on mac, bind-mounting to this errors with the following. I get it, because the bind is creating the path with different permissions than the gateway init, but is that a bug?

```python
The Ignition Gateway has failed to successfully start.
Reason: java.nio.file.AccessDeniedException: /usr/local/bin/ignition/data/var/ignition/designer. Check the logs for more details.

```

```python
  volumes:
    - ./modules:/usr/local/bin/ignition/data/var/ignition/modl
    - ignition-data:/usr/local/bin/ignition/data

```

---

<div class="post-metadata">

**Author:** ![derek.delizo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/derek.delizo/32/84136_2.png) [@derek.delizo](https://forum.inductiveautomation.com/u/derek.delizo)\
**Post date:** [May 13, 2026, 9:28pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/11 "2026-05-13T21:28:49Z")

</div>

In your docker-compose do you set your user to root? `user: "0:0"`

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [May 13, 2026, 11:29pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/12 "2026-05-13T23:29:00Z")

</div>

well that "fixes" the issue, but no, I run it unprivileged and have sidecar containers that handle the unprivileged nature via this:

```python
  user: "2003:2003" # match ignition container
  group_add:
    - 65533 # allow writing to /git

```

this wouldn't be the first time I've seen behavior differ between OrbStack and Linux (specifically with permission mapping), but in this case I think it's not the culprit. I've always been curious why only parts of the container file system are in the image vs generated on init, so leaning toward this just not being fully "baked" 😆 (e.g. `data/config/resources` exists at boot (understandably) but my sidecar must sleep while waiting for `data/projects`)

FYI, you don't need `user: "0:0"` if you mount `- ./modules/MQTT-Transmission-signed.modl:/usr/local/bin/ignition/user-lib/modules/MQTT-Transmission-signed.modl` like in your last example.

I just want to make use of the other path

---

<div class="post-metadata">

**Author:** ![kcollins](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kcollins/32/19646_2.png) [@kcollins](https://forum.inductiveautomation.com/u/kcollins)\
**Post date:** [May 14, 2026, 2:53pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/13 "2026-05-14T14:53:41Z")

</div>

I tried this simple Compose stack on both Docker Desktop and OrbStack and didn't encounter any issues:

```python
services:
  gateway:
   image: inductiveautomation/ignition:8.3.6
   ports:
     - 9088:8088
   env_file: ~/Docker/basic.env
   command: >
     -n forum-113547
   volumes:
     - ./modules:/usr/local/bin/ignition/data/var/ignition/modl
     - ignition-data:/usr/local/bin/ignition/data

volumes:
  ignition-data:

```

> [@hunterdg](#):
>
> I've always been curious why only parts of the container file system are in the image vs generated on init

As to why certain paths exist within the image, they're there to enable bind-mounting to direct subfolders under those paths. If you bind-mount to a folder whose parent folders don't exist in the image, those interim folders are [unfortunately] created with `root` ownership and thus cause permissions issues.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [May 14, 2026, 8:08pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/14 "2026-05-14T20:08:46Z")

</div>

heh. looks like 8.3.6 fixed it, but doesn't seem to be explcitly called out in the release notes.

regarding file system - I'm more curious why some paths (like /data/projects) _aren't_ in the image. I feel like I may have answered that question myself at some point when poking around in `docker-entrypoint.sh`, but `maybe_seed_data_volume()` doesn't seem to be the culprit after another quick look

([I can't mount two named volumes separately to data/config and data/projects](https://forum.inductiveautomation.com/t/guide-for-version-control-with-ignition/84004/56))

also FYI the 8.3 "Warning" blurb has changed since 8.3 - it now points to the 8.1 upgrade guide

8.3:  
_ **WARNING:** If you are upgrading to Ignition 8.3, you must read the upgrade guide first before installing Ignition 8.3. Visit the following URL for more information before installing: [Ignition 8.1 to 8.3 Upgrade Guide](https://docs.inductiveautomation.com/docs/8.3/getting-started/installing-and-upgrading/ignition-8-upgrade-guide/81to83-upgrade-guide/)_

8.4+:  
_ **WARNING:** If you are upgrading to Ignition 8 from any previous version of Ignition you must read the upgrade guide first before installing Ignition 8. Visit the following URL for more information before installing: [Ignition 8 Upgrade Guide](https://docs.inductiveautomation.com/display/DOC80/Ignition+8+Upgrade+Guide)_

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [May 14, 2026, 8:28pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/15 "2026-05-14T20:28:45Z")

</div>

> [@kcollins](#):
>
> First thing I'll mention is that we observed a documentation error with respect to the [location of user-installed modules](https://docs.inductiveautomation.com/docs/8.3/appendix/reference-pages/gateway-configuration-file-reference/gateway-and-gateway-network-parameters#docker-image-external-modules-folder) in the Ignition 8.3 Docker image.

😁 - [Merging wrapper arguments in Docker - #5 by hunterdg](https://forum.inductiveautomation.com/t/merging-wrapper-arguments-in-docker/67112/5)

---

<div class="post-metadata">

**Author:** ![kcollins](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kcollins/32/19646_2.png) [@kcollins](https://forum.inductiveautomation.com/u/kcollins)\
**Post date:** [May 14, 2026, 10:40pm UTC](https://forum.inductiveautomation.com/t/installing-an-ignition-designer-plugin-when-spinning-up-a-docker-container/113547/16 "2026-05-14T22:40:30Z")

</div>

Yeah, so somehow I completed missed your reply in that thread.. :sorry: .. Glad it got sorted in the end though 🤷. I fixed my comment above 😃
