├── .dockerignore ├── .github ├── DISCUSSION_TEMPLATE │ ├── Help.yml │ └── Ideas.yml └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── .gitignore ├── Dockerfile ├── Dockerfile.chromium ├── Dockerfile.v5.x ├── KNOWN_ISSUES.md ├── README.md ├── README_DOCKER_HUB.md ├── README_v3_and_v4.md ├── SUPPORT_INFO.md ├── docker-compose.yml ├── docker-compose_bridge.yml ├── entrypoint-5.x.sh ├── entrypoint-rootless.sh ├── external_mongodb ├── README.md ├── kubernetes │ ├── mongodb │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── _helpers.tpl │ │ │ └── external-secrets.yaml │ │ ├── values-customized.yaml │ │ └── values.yaml │ └── omada-controller │ │ ├── base │ │ ├── configmap-env.yaml │ │ ├── deployment.yml │ │ ├── kustomization.yaml │ │ ├── pvc-omada-data.yml │ │ ├── pvc-omada-logs.yml │ │ └── service.yml │ │ └── production │ │ ├── certificate.yaml │ │ ├── ingress.yml │ │ ├── kustomization.yaml │ │ └── overlays │ │ └── service.yml └── omada.js ├── healthcheck.sh ├── install.sh └── k8s ├── deployment.yaml ├── pvc.yaml └── service.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .git 3 | .DS_Store 4 | *.md 5 | k8s/ 6 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/Help.yml: -------------------------------------------------------------------------------- 1 | title: "[Help]: " 2 | labels: ["Help"] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | ## Read Me First! 8 | 9 | Thanks for using my image! Hopefully it's helpful to you. If you're looking for help with this container image, related to the packaging or function of this Docker image, you're in the right place. If you have a bug with the software that is not related to this Docker image, file an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582). If you're not sure if it is a problem with the Docker image or the software, we can figure that out so go ahead and start a discussion. If you are certain you have found a bug in the packaging or function of this image, go ahead and create a [Bug Report Issue](https://github.com/mbentley/docker-omada-controller/issues/new/choose). In order to better help you, it would be great if you can provide as much information as you can below. 10 | 11 | If you are not sure how to gather some of the requested information, please check out the [support info](https://github.com/mbentley/docker-omada-controller/blob/master/SUPPORT_INFO.md) README. 12 | - type: input 13 | id: controller-version 14 | attributes: 15 | label: Controller Version 16 | description: | 17 | What is the version of the Omada Controller that you're running? This can be found in the hamburger menu (three dots) in the upper right hand corner of the main screen and under 'About' or in the container startup logs. This is *not* the image tag (i.e. - not `latest`) 18 | placeholder: v5.7.4 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: description 23 | attributes: 24 | label: Describe Your Issue or Question 25 | description: | 26 | Please provide a clear and concise description of what you're trying to achieve and what the problem is that you're facing. 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: expected 31 | attributes: 32 | label: Expected Behavior 33 | description: | 34 | A clear and concise description of what you expect to happen. 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: reproduce 39 | attributes: 40 | label: Steps to Reproduce 41 | description: | 42 | Steps to reproduce the unexpected behavior with as much detail as possible. 43 | placeholder: | 44 | 1. 45 | 2. 46 | 3. 47 | 4. 48 | validations: 49 | required: true 50 | - type: textarea 51 | id: docker-run 52 | attributes: 53 | label: How You're Launching the Container 54 | description: | 55 | Include your complete `docker run` or compose file to make analysis easier. 56 | render: plain 57 | validations: 58 | required: true 59 | - type: textarea 60 | id: logs 61 | attributes: 62 | label: Container Logs 63 | description: | 64 | Collect logs by using something similar to `docker logs omada-controller >& output.log` if needed and attach them or copy out the relevant portions of the error. When in doubt, do both. I can't help without logs! 65 | placeholder: | 66 | logs 67 | go 68 | here 69 | render: plain 70 | validations: 71 | required: true 72 | - type: textarea 73 | id: mongo-logs 74 | attributes: 75 | label: MongoDB Logs 76 | description: | 77 | If the container is refusing to start or the controller app fails to start up, collect logs from MongoDB. These can be copied from the container using `docker cp omada-controller:/opt/tplink/EAPController/logs/mongod.log .` or by copying them from the volume/bind mount specified for the logs directory. 78 | placeholder: | 79 | logs 80 | go 81 | here 82 | render: plain 83 | validations: 84 | required: false 85 | - type: textarea 86 | id: additional 87 | attributes: 88 | label: Additional Context 89 | description: | 90 | Add any other context about the issue here. 91 | validations: 92 | required: false 93 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/Ideas.yml: -------------------------------------------------------------------------------- 1 | title: "[Idea]: " 2 | labels: ["Idea"] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | ## Read Me First! 8 | 9 | Thanks for using my image! Hopefully it's helpful to you. If you have an idea for a new feature or enhancement that is related to the packaging or function of this Docker image, you're in the right place. If you have a feature request or enhancement with the software that is not related to this Docker image, file an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582). If you want to report a bug in the packaging or function of this image, go ahead and create a [Bug Report Issue](https://github.com/mbentley/docker-omada-controller/issues/new/choose). In order to have a better discussion about the feature/enhancement/idea, it would be great if you can provide as much information as you can below. 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Describe the Feature/Enhancement/Idea 14 | description: | 15 | Please provide a clear and concise description of what you'd like to see in this image. If you have an idea of how you would propose to solve the problem, include that here! 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: additional 20 | attributes: 21 | label: Additional Context 22 | description: | 23 | Add any other context about the idea here. 24 | validations: 25 | required: false 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a problem with this Docker image or the behavior of the Omada Controller software related to running inside of Docker. 3 | title: '[Bug]: ' 4 | assignees: 5 | - mbentley 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## Read Me First! 11 | 12 | Thanks for using my image! Hopefully it's helpful to you. You are about to report a bug you found related to the packaging or function of this Docker image, not the Controller software itself. If you have a problem with the software that is not related to this Docker image, file an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582). If you're not sure if it is a problem with the Docker image or the software, file an issue here and I can assist in determining where the responsibility lies. 13 | 14 | If you are not sure how to gather some of the requested information, please check out the [support info](https://github.com/mbentley/docker-omada-controller/blob/master/SUPPORT_INFO.md) README. 15 | - type: input 16 | id: controller-version 17 | attributes: 18 | label: Controller Version 19 | description: | 20 | What is the version of the Omada Controller that you're running? This can be found in the hamburger menu (three dots) in the upper right hand corner of the main screen and under 'About' or in the container startup logs. This is *not* the image tag (i.e. - not `latest`) 21 | placeholder: v5.7.4 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: Describe the Bug 28 | description: | 29 | Please provide a clear and concise description of what the bug is. 30 | validations: 31 | required: true 32 | - type: textarea 33 | id: expected 34 | attributes: 35 | label: Expected Behavior 36 | description: | 37 | A clear and concise description of what you expected to happen. 38 | validations: 39 | required: true 40 | - type: textarea 41 | id: reproduce 42 | attributes: 43 | label: Steps to Reproduce 44 | description: | 45 | Steps to reproduce the behavior with as much detail as possible. 46 | placeholder: | 47 | 1. 48 | 2. 49 | 3. 50 | 4. 51 | validations: 52 | required: true 53 | - type: textarea 54 | id: docker-run 55 | attributes: 56 | label: How You're Launching the Container 57 | description: | 58 | Include your complete `docker run` or compose file to make analysis easier. 59 | render: plain 60 | validations: 61 | required: true 62 | - type: textarea 63 | id: logs 64 | attributes: 65 | label: Container Logs 66 | description: | 67 | Collect logs by using something similar to `docker logs omada-controller >& output.log` if needed and attach them or copy out the relevant portions of the error. When in doubt, do both. I can't help without logs! 68 | placeholder: | 69 | logs 70 | go 71 | here 72 | render: plain 73 | validations: 74 | required: true 75 | - type: textarea 76 | id: mongo-logs 77 | attributes: 78 | label: MongoDB Logs 79 | description: | 80 | If the container is refusing to start or the controller app fails to start up, collect logs from MongoDB. These can be copied from the container using `docker cp omada-controller:/opt/tplink/EAPController/logs/mongod.log .` or by copying them from the volume/bind mount specified for the logs directory. 81 | placeholder: | 82 | logs 83 | go 84 | here 85 | render: plain 86 | validations: 87 | required: false 88 | - type: textarea 89 | id: additional 90 | attributes: 91 | label: Additional Context 92 | description: | 93 | Add any other context about the problem here. 94 | validations: 95 | required: false 96 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: mbentley/omada-controller Discussions 4 | url: https://github.com/mbentley/docker-omada-controller/discussions/categories/help 5 | about: For help using this container image, start a discussion. Keep issues related to bugs & features, please. 6 | - name: TP-Link Forums 7 | url: https://community.tp-link.com/en/business/forum/582 8 | about: For issues related to the Omada Controller software itself, use the forums! I do not develop the Omada Controller software. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: For feature requests related to this Docker image only. 3 | title: '[Feature]: ' 4 | assignees: 5 | - mbentley 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## Read Me First! 11 | 12 | Thanks for using my image! Hopefully it's helpful to you. You are about to file a feature request related to the packaging or function of this Docker image, not the Controller software itself. If you have a feature request for the software that is not related to this Docker image, file an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582). If you're not sure if it is a feature request related to the Docker image or the software, file an issue here and I can assist in determining where the responsibility lies. 13 | - type: textarea 14 | id: feature-problem 15 | attributes: 16 | label: What problem are you looking to solve? 17 | description: | 18 | A clear and concise description of what the problem or challenge is that you'd like to be addressed. If this is specific to a version of the Omada Controller, please provide the applicable version number. 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: solution 23 | attributes: 24 | label: Describe the solution that you have in mind 25 | description: | 26 | A clear and concise description of what you want to happen or a proposed method to solving the problem. If you have expectations around how the problem would be solved from a user experience perspective, add that information here. 27 | validations: 28 | required: false 29 | - type: textarea 30 | id: additional 31 | attributes: 32 | label: Additional Context 33 | description: | 34 | Add any other context about the feature here. 35 | validations: 36 | required: false 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | Dockerfile.v5.x -------------------------------------------------------------------------------- /Dockerfile.chromium: -------------------------------------------------------------------------------- 1 | ARG BASE_VER=latest 2 | FROM mbentley/omada-controller:${BASE_VER} 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt-get update &&\ 7 | apt-get install -y --no-install-recommends software-properties-common &&\ 8 | add-apt-repository -y ppa:saiarcot895/chromium-beta &&\ 9 | apt-get update &&\ 10 | apt-get install -y --no-install-recommends chromium-browser &&\ 11 | apt-get purge -y software-properties-common &&\ 12 | apt-get autoremove -y &&\ 13 | rm -rf /var/lib/apt/lists/* 14 | -------------------------------------------------------------------------------- /Dockerfile.v5.x: -------------------------------------------------------------------------------- 1 | # rebased/repackaged base image that only updates existing packages 2 | ARG BASE=mbentley/ubuntu:20.04 3 | FROM ${BASE} 4 | LABEL maintainer="Matt Bentley " 5 | LABEL org.opencontainers.image.source="https://github.com/mbentley/docker-omada-controller" 6 | 7 | COPY healthcheck.sh install.sh / 8 | 9 | # valid values: amd64 (default) | arm64 | armv7l 10 | ARG ARCH=amd64 11 | 12 | # install version (major.minor or full version); OMADA_URL set in install.sh 13 | ARG INSTALL_VER="5.15.20.20" 14 | ARG NO_MONGODB=false 15 | 16 | # install omada controller (instructions taken from install.sh) 17 | RUN /install.sh &&\ 18 | rm /install.sh 19 | 20 | COPY entrypoint-5.x.sh /entrypoint.sh 21 | COPY entrypoint-rootless.sh /entrypoint-rootless.sh 22 | 23 | WORKDIR /opt/tplink/EAPController/lib 24 | EXPOSE 8088 8043 8843 19810/udp 27001/udp 29810/udp 29811 29812 29813 29814 29815 29816 25 | HEALTHCHECK --start-period=5m CMD /healthcheck.sh 26 | VOLUME ["/opt/tplink/EAPController/data","/opt/tplink/EAPController/logs"] 27 | ENTRYPOINT ["/entrypoint.sh"] 28 | CMD ["java","-server","-Xms128m","-Xmx1024m","-XX:MaxHeapFreeRatio=60","-XX:MinHeapFreeRatio=30","-XX:+HeapDumpOnOutOfMemoryError","-XX:HeapDumpPath=/opt/tplink/EAPController/logs/java_heapdump.hprof","-Djava.awt.headless=true","--add-opens","java.base/sun.security.x509=ALL-UNNAMED","--add-opens","java.base/sun.security.util=ALL-UNNAMED","-cp","/opt/tplink/EAPController/lib/*::/opt/tplink/EAPController/properties:","com.tplink.smb.omada.starter.OmadaLinuxMain"] 29 | -------------------------------------------------------------------------------- /KNOWN_ISSUES.md: -------------------------------------------------------------------------------- 1 | # Known Issues 2 | 3 | * [Controller Software Issues](#controller-software-issues) 4 | * [Devices Fail to Adopt](#devices-fail-to-adopt) 5 | * [Containerization Issues](#containerization-issues) 6 | * [MongoDB Corruption](#mongodb-corruption) 7 | * [Notes for `armv7l`](#notes-for-armv7l) 8 | * [:warning: Unsupported Base Image for `armv7l`](#unsupported-base-image-for-armv7l) 9 | * [:warning: Unsupported MongoDB](#unsupported-mongodb) 10 | * [Low Resource Systems](#low-resource-systems) 11 | * [Mismatched Userland and Kernel](#mismatched-userland-and-kernel) 12 | * [Upgrade Issues](#upgrade-issues) 13 | * [5.8 - 404s and Blank Pages](#58---404s-and-blank-pages) 14 | * [Incorrect CMD](#incorrect-cmd) 15 | * [5.12 - Unable to Login After Upgrade](#512---unable-to-login-after-upgrade) 16 | * [Slowness in Safari](#slowness-in-safari) 17 | * [5.14 - Controller Unable to Start](#514---controller-unable-to-start) 18 | * [5.15 - Controller Unable to Start](#515---controller-unable-to-start) 19 | 20 | ## Controller Software Issues 21 | 22 | ### Devices Fail to Adopt 23 | 24 | Users who are using `bridge` mode often report that switches and EAPs fail to adopt. This is due to the controller being technically being on a different network inside the container's bridge network, exporting the ports via NAT. Using port mapping is more complex than using host networking as your devices need to be informed of the controller's IP or hostname. See [this TP-Link FAQ](https://www.tp-link.com/us/support/faq/3087/) for details on how to configure this on your device(s) prior to attempting to adopt them. 25 | 26 | ## Containerization Issues 27 | 28 | ### MongoDB Corruption 29 | 30 | While MongoDB is fairly robust, the persistent data can become corrupt if a clean shutdown isn't performed. By default, Docker only waits 10 seconds before killing the container processes when using `docker stop...`. I would **highly recommend** performing a stop with a large timeout value, such as `docker stop -t 30...` to ensure that the controller is cleanly shut down. This value may need to be even larger for low powered devices, such as a Raspberry Pi. 31 | 32 | ### Notes for `armv7l` 33 | 34 | ** ⚠ Deprecation and Removal Notice ⚠** - armv7l images will no longer be available starting with the v5.15.20 and later versions. See [this issue](https://github.com/mbentley/docker-omada-controller/issues/542) describing the change. The last version that will be available for `armv7l` is `5.15.8.2`. 35 | 36 | **tl;dr** - Do not run the Omada Controller on your `armv7l`/`armhf` (32 bit arm) based operating system! If you're running as Raspberry Pi 3, 4, Pi Zero 2W, you should [run a 64 bit operating system](https://www.raspberrypi.com/news/raspberry-pi-os-64-bit/) so you can use the `arm64` image which is supported. At any time, TP-Link can break compatibility with 32 bit arm and there will be no upgrade path forward! You have been warned! 37 | 38 | #### Unsupported Base Image for `armv7l` 39 | 40 | All `armv7l` images are based on Ubuntu 16.04 due to the lack of packaging for MongoDB in newer Ubuntu releases. Ubuntu 16.04 is end of general support so security patches aren't regularly being released. I would highly recommend not using the `armv7l` images unless you have no other alternative and accept the security risk. If you are running a Raspberry Pi, I might suggest looking into running an `arm64` based operating system if your system supports it (the [Raspberry Pi 3 and above do](https://www.raspberrypi.com/news/raspberry-pi-os-64-bit/)) 41 | 42 | #### Unsupported MongoDB 43 | 44 | The `armv7l` architecture is 32 bit and MongoDB is no longer available as a pre-compiled binary in Ubuntu, this means that the `armv7l` images are running version `2.6.10` of MongoDB. This may lead to unexpected behavior as TP-Link states Omada Controller version 4.1.x and newer require at least MongoDB `3.0.15` or newer, depending on which version of the controller you're running. For the `armv7l` architecture, I will continue to include those in the builds until they stop working as I can't guarantee that an update will not actually require a newer MongoDB feature that isn't available. 45 | 46 | ### Low Resource Systems 47 | 48 | Systems such as Raspberry Pis may not have sufficient memory to run with the default memory settings of this image. If you system only has 1 GB of RAM, I would highly recommend adjusting the Xmx arguments by overriding the `CMD` [as seen in this issue here](https://github.com/mbentley/docker-omada-controller/issues/198#issuecomment-1100485810) to prevent the container from being OOM killed by the OS. 49 | 50 | ### Mismatched Userland and Kernel 51 | 52 | If a Raspberry Pi 4 is running a 32 bit version of Raspberry Pi OS, a [recent firmware update](https://github.com/raspberrypi/firmware/issues/1795) has intentionally made it so the default kernel the Pi will boot from has been switched from 32 bit kernel to a 64 bit kernel. This is a problem for the running container because the version of MongoDB that is present in the `armv7l` image (also known as `armhf`), will fail to start on a 64 bit kernel. Most software tends to run fine when switching kernels but in this case, it will prevent the controller from running due to MongoDB failing to start. Please also review the [Notes for armv7l](#notes-for-armv7l) to also understand the risks for running the `armv7l` based controller! 53 | 54 | To fix this issue in the short term, you will want to instruct your Pi to boot from a 32 bit kernel instead of the 64 bit kernel by: 55 | 56 | 1. Adding `arm_64bit=0` to the `/boot/config.txt` file 57 | 1. Rebooting the device 58 | 59 | A proper long term solution would be to reinstall Raspberry Pi OS on your Pi 4 and use the new `arm64` based operating system which will get you a 64 bit userland and a 64 bit kernel. There are [significant known issues](#notes-for-armv7l) while running the `armv7l` image on a device so longer term, this is the best solution. 60 | 61 | ## Upgrade Issues 62 | 63 | ### 5.8 - 404s and Blank Pages 64 | 65 | It has been reported that a number of users are seeing 404s or blank pages after upgrading to version 5.8. This can be resolved by either force-reloading the page or by clearing your browser's cache. 66 | 67 | ### Incorrect CMD 68 | 69 | It has been reported that users of some NAS devices such as a Synology or users of a Docker management UI like Portainer have had issues with upgrades due to the CMD being retained between versions. This normally does not happen with the Docker command line so it is a bit of an unexpected pattern but it can not be overwritten as it exists outside of the container. 70 | 71 | If updating from 3.x to 4.x or 4.x to 5.x, make sure to **completely** re-create the container (leaving your persistent data intact) otherwise the controller will not start. This is due to the CMD changing between the major releases as some web interfaces like Synology or Portainer retain the entrypoint and command explicitly instead of inheriting it from the image. To resolve the issue, do one of the following: 72 | 73 | * Re-create the container - remove the container, keeping your persistent data and create it again using whatever method you used to originally create it. 74 | * Update the CMD (command is all on one line): 75 | * 4.x to 5.x - `/usr/bin/java -server -Xms128m -Xmx1024m -XX:MaxHeapFreeRatio=60 -XX:MinHeapFreeRatio=30 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tplink/EAPController/logs/java_heapdump.hprof -Djava.awt.headless=true -cp /opt/tplink/EAPController/lib/*::/opt/tplink/EAPController/properties: com.tplink.smb.omada.starter.OmadaLinuxMain` 76 | 77 | It should be noted that users of 3.x who wish to upgrade to 4.x must perform [specific upgrade steps](#upgrading-to-41-from-3210-or-below) to prevent data loss! 78 | 79 | ### 5.12 - Unable to Login After Upgrade 80 | 81 | There is a [known bug](https://github.com/mbentley/docker-omada-controller/discussions/344#discussioncomment-7104908) in the controller software where a user is not able to login with their local user after upgrading to 5.12.x. This has been [reported to TP-Link](https://community.tp-link.com/en/business/forum/topic/623942) but a fix has not yet been provided. 82 | 83 | ### Slowness in Safari 84 | 85 | In versions 5.8 to 5.12, it has been seen where Safari will take a significant amount of time to completely load a page in the controller web interface. This is an [issue that has been reported upstream](https://community.tp-link.com/en/business/forum/topic/619304?replyId=1255404). 86 | 87 | ### 5.14 - Controller Unable to Start 88 | 89 | Upon upgrade to 5.14, the controller may not start. You may see error messages that include phrases like: `Cannot retry start up springboot`, `Unsatisfied dependency expressed through field...`, `org.springframework.beans.factory.UnsatisfiedDependencyException`, among others. This is a problem with the controller software itself that TP-Link is aware of. If you're impacted, see the first post in [this issue](https://github.com/mbentley/docker-omada-controller/issues/418) for possible workaround instructions and more information. This issue should no longer be present on the latest 5.14 versions. 90 | 91 | ### 5.15.6.x - Controller Unable to Start 92 | 93 | **Warning**: do **NOT** use this override environment variable unless you need it. It may cause unexpected issues in the future. Remove the environment variable if you're no longer running on 5.15.6.x. Upon upgrade to 5.15.6.x, the controller may not start. You may see error messages right around the `Valid radius server keystore is missing. Generating one ...` message that include phrases like: `Exception in thread "main" java.lang.NoSuchFieldError: id_alg_zlibCompress` among others. This is a problem with the controller software itself that TP-Link is aware of. If you're impacted, see the first post in [this issue](https://github.com/mbentley/docker-omada-controller/issues/509) for more information. An environment variable can be set as `WORKAROUND_509=true` on the container definition and it will delete two library files that are causing the issue. 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mbentley/omada-controller 2 | 3 | Docker image for [TP-Link Omada Controller](https://www.tp-link.com/us/support/download/omada-software-controller/) to control [TP-Link Omada Hardware](https://www.tp-link.com/en/business-networking/all-omada/) 4 | 5 | For references on running a legacy v3 or v4 controller, see the [README for v3 and v4](README_v3_and_v4.md). See the tag [archive_v3_v4](https://github.com/mbentley/docker-omada-controller/releases/tag/archive_v3_v4) for a snapshot of the code that includes the v3 and v4 artifacts as they have been removed as of July 2, 2024. 6 | 7 | ## Table of Contents 8 | 9 | * [Image Tags](#image-tags) 10 | * [Multi-arch Tags](#multi-arch-tags) 11 | * [Tags for Beta/Testing](#tags-for-betatesting) 12 | * [Explicit Architecture Tags](#explicit-architecture-tags) 13 | * [Explicit Version Tags](#explicit-version-tags) 14 | * [Archived Tags](#archived-tags) 15 | * [Getting Help & Reporting Issues](#getting-help--reporting-issues) 16 | * [Best Practices for Operation](#best-practices-for-operation) 17 | * [Controller Backups](#controller-backups) 18 | * [Controller Upgrades](#controller-upgrades) 19 | * [Preventing Database Corruption](#preventing-database-corruption) 20 | * [Building Images](#building-images) 21 | * [Example Usage](#example-usage) 22 | * [Using `net=host`](#using-nethost) 23 | * [Using port mapping](#using-port-mapping) 24 | * [Using non-default ports](#using-non-default-ports) 25 | * [Running Rootless](#running-rootless) 26 | * [Optional Variables](#optional-variables) 27 | * [Persistent Data](#persistent-data) 28 | * [Custom SSL Certificates](#custom-ssl-certificates) 29 | * [Time Zones](#time-zones) 30 | * [Unprivileged Ports](#unprivileged-ports) 31 | * [Using Docker Compose](#using-docker-compose) 32 | * [Omada Controller API Documentation](#omada-controller-api-documentation) 33 | * [Known Issues](KNOWN_ISSUES.md#known-issues) 34 | * [Controller Software Issues](KNOWN_ISSUES.md#controller-software-issues) 35 | * [Devices Fail to Adopt](KNOWN_ISSUES.md#devices-fail-to-adopt) 36 | * [Containerization Issues](KNOWN_ISSUES.md#containerization-issues) 37 | * [MongoDB Corruption](KNOWN_ISSUES.md#mongodb-corruption) 38 | * [Notes for `armv7l`](KNOWN_ISSUES.md#notes-for-armv7l) 39 | * [:warning: Unsupported Base Image for `armv7l`](KNOWN_ISSUES.md#unsupported-base-image-for-armv7l) 40 | * [:warning: Unsupported MongoDB](KNOWN_ISSUES.md#unsupported-mongodb) 41 | * [Low Resource Systems](KNOWN_ISSUES.md#low-resource-systems) 42 | * [Mismatched Userland and Kernel](KNOWN_ISSUES.md#mismatched-userland-and-kernel) 43 | * [Upgrade Issues](KNOWN_ISSUES.md#upgrade-issues) 44 | * [5.8 - 404s and Blank Pages](KNOWN_ISSUES.md#58---404s-and-blank-pages) 45 | * [Incorrect CMD](KNOWN_ISSUES.md#incorrect-cmd) 46 | * [5.12 - Unable to Login After Upgrade](KNOWN_ISSUES.md#512---unable-to-login-after-upgrade) 47 | * [Slowness in Safari](KNOWN_ISSUES.md#slowness-in-safari) 48 | * [5.14 - Controller Unable to Start](KNOWN_ISSUES.md#514---controller-unable-to-start) 49 | * [5.15 - Controller Unable to Start](KNOWN_ISSUES.md#515---controller-unable-to-start) 50 | 51 | ## Image Tags 52 | 53 | :warning: **Warning** :warning: Do **NOT** run the `armv7l` (32 bit) images. Upgrade your operating system to `arm64` (64 bit) unless you accept that you're running an outdated MongoDB, a base operating system with unpatched vulnerabilities, an old version of Java, and a controller that will never be upgraded beyond `5.15.8.2`! See the [Known Issues readme](KNOWN_ISSUES.md#notes-for-armv7l) for more information. 54 | 55 | ### Multi-arch Tags 56 | 57 | For a full tag list, search the [Docker Hub tags list](https://hub.docker.com/r/mbentley/omada-controller/tags). The following tags have multi-arch support for `amd64` and `arm64` and will automatically pull the correct tag based on your system's architecture: 58 | 59 | | Tag(s) | Major.Minor Release | Current Version | 60 | | :----- | ------------------- | --------------- | 61 | | `latest`, `5.15` | `5.15.x` | `5.15.20.20` | 62 | | `5.14` | `5.14.x` | `5.14.32.4` | 63 | 64 | ### Tags with Chromium 65 | 66 | **Note**: These are currently published for the `amd64` architecture only. These tags extend the tags above to add Chromium which is required to generate reports from the controller. 67 | 68 | | Tag(s) | Major.Minor Release | 69 | | :----- | ------------------- | 70 | | `latest-chromium`, `5.15-chromium` | `5.15.x` | 71 | | `5.14-chromium` | `5.14.x` | 72 | | `beta-chromium`, | `beta` | 73 | 74 | ### Tags for Beta/Testing 75 | 76 | These are multi-arch tags. For the full tag listings, see the Docker Hub tags above but the general format for `beta-*` and `*-openj9` follow for the specific architecture tags. OpenJ9 images are only available for `amd64` and `arm64`. 77 | 78 | | Tag(s) | Major.Minor Release | Current Version | 79 | | :----- | ------------------- | --------------- | 80 | | `beta`, `beta-5.15` | `beta` | `5.15.24.15` | 81 | | `beta-5.15-openj9`, `beta-5.15.24.15-openj9` | `5.15.x` Beta w/OpenJ9 | `5.15.24.15` | 82 | | --- | --- | --- | 83 | | `5.15-openj9`, `5.15.20.20-openj9` | `5.15.x` w/OpenJ9 | `5.15.20.20` | 84 | | `5.14-openj9`, `5.14.32.4-openj9` | `5.14.x` w/OpenJ9 | `5.14.32.4` | 85 | 86 | ### Explicit Architecture Tags 87 | 88 | If for some reason you can't use the multi-arch tags, there are explicitly tagged images with the architecture (`-amd64` and `-arm64`) appended to them. Check [Docker Hub](https://hub.docker.com/r/mbentley/omada-controller/tags) for the full list of tags. 89 | 90 | ### Explicit Version Tags 91 | 92 | If you need a specific version of the controller, starting with 5.13 and 5.14, there are explicitly tagged images with the exact version (i.e. - `5.15.20.20`) in the tag name. Check [Docker Hub](https://hub.docker.com/r/mbentley/omada-controller/tags) for the full list of tags. 93 | 94 | ## Archived Tags 95 | 96 | These images are still published on Docker Hub but are no longer regularly updated due to the controller software no longer being updated. **Use with extreme caution as these images are likely to contain unpatched security vulnerabilities!**. See [Archived Tags for v3 and v4](README_v3_and_v4.md#archived-tags) for details on the old, unmaintained image tags. 97 | 98 | | Tag(s) | Major.Minor Release | Current Version | 99 | | :----- | ------------------- | ----------------| 100 | | `5.13` | `5.13.x` | `5.13.30.8` | 101 | | `5.13-chromium` | `5.13.x` | `5.13.30.8` | 102 | | `5.13-openj9`, `5.13.30.8-openj9` | `5.13.x` w/OpenJ9 | `5.13.30.8` | 103 | | `5.12` | `5.12.x` | `5.12.7` | 104 | | `5.12-chromium` | `5.12.x` | `5.12.7` | 105 | | `5.9` | `5.9.x` | `5.9.31` | 106 | | `5.9-chromium` | `5.9.x` | `5.9.31` | 107 | | `5.8` | `5.8.x` | `5.8.4` | 108 | | `5.8-chromium` | `5.8.x` | `5.8.4` | 109 | | `5.7` | `5.7.x` | `5.7.4` | 110 | | `5.7-chromium` | `5.7.x` | `5.7.4` | 111 | | `5.6` | `5.6.x` | `5.6.3` | 112 | | `5.6-chromium` | `5.6.x` | `5.6.3` | 113 | | `5.5` | `5.5.x` | `5.5.6` | 114 | | `5.5-chromium` | `5.5.x` | `5.5.6` | 115 | | `5.4` | `5.4.x` | `5.4.6` | 116 | | `5.4-chromium` | `5.4.x` | `5.4.6` | 117 | | `5.3` | `5.3.x` | `5.3.1` | 118 | | `5.3-chromium` | `5.3.x` | `5.3.1` | 119 | | `5.1` | `5.1.x` | `5.1.7` | 120 | | `5.1-chromium` | `5.1.x` | `5.1.7` | 121 | | `5.0` | `5.0.x` | `5.0.30` | 122 | 123 | ## Getting Help & Reporting Issues 124 | 125 | If you have issues running the controller, feel free to [create a Help discussion](https://github.com/mbentley/docker-omada-controller/discussions/categories/help) and I will help as I can. If you are specifically having a problem that is related to the actual software, I would suggest filing an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582) as I do not have access to source code to debug those issues. If you're not sure where the problem might be, I can help determine if it is a running in Docker issue or a software issue. If you're certain you have found a bug, create a [Bug Report Issue](https://github.com/mbentley/docker-omada-controller/issues/new/choose). 126 | 127 | ## Best Practices for Operation 128 | 129 | ### Controller Backups 130 | 131 | While you can take backups of your controller by making a copy of the persistent data, the chance of data corruption exists if you do so while the container is running as there is a database used for persistence. The best way to take backups is to use the automatic backup capabilities within the controller itself. Go to `Settings` > `Maintenance` > `Backup` and scroll down to `Auto Backup` to enable and configure the feature. These backups can be restored as a part of the installation process on a clean controller install. 132 | 133 | Backups can also be taken manually on the same screen as the auto backup settings. This would be ideal to do before you perform an upgrade to ensure that you are able to roll back in case of issues upon upgrade as you can not move from a newer version of the controller to an older version! It will break the database and require you to do a full reinstall! 134 | 135 | ### Controller Upgrades 136 | 137 | Before performing any upgrade, I would suggest taking a backup through the controller itself. Controller upgrades are done by stopping the existing container gracefully (see the [note below](#preventing-database-corruption) on this topic), removing the existing container, and running a new container with the new version of the controller. This can be done manually, with compose, or with many other 3rd party tools which auto-update containers. 138 | 139 | ### Preventing Database Corruption 140 | 141 | When stopping your container in order to upgrade the controller, make sure to allow the MongoDB enough time to safely shutdown. This is done using `docker stop -t ` where `` is a number in seconds, such as 60, which should allow the controller to cleanly shutdown. Database corruption has been observed when not cleanly shut down. The `docker run` and compose examples now include `--stop-timeout` and `stop_grace_period` which are set to 60s. 142 | 143 | ## Building images 144 | 145 |
146 | Click to expand docker build instructions 147 | 148 | There are some differences between the build steps for `amd64`, `arm64`, and `armv7l`. These changes will happen automatically if you use the build-args `INSTALL_VER` and `ARCH`. For possible `INSTALL_VER` values, see [mbentley/docker-omada-controller-url](https://github.com/mbentley/docker-omada-controller-url/blob/master/omada_ver_to_url.sh): 149 | 150 | ### `amd64` 151 | 152 | No build args required; set for the default build-args 153 | 154 | ``` 155 | docker build \ 156 | --build-arg INSTALL_VER="5.15.20.20" \ 157 | --build-arg ARCH="amd64" \ 158 | -f Dockerfile.v5.x \ 159 | -t mbentley/omada-controller:5.15-amd64 . 160 | ``` 161 | 162 | ### `arm64` 163 | 164 | Only the `ARCH` build-arg is required 165 | 166 | ``` 167 | docker build \ 168 | --build-arg INSTALL_VER="5.15.20.20" \ 169 | --build-arg ARCH="arm64" \ 170 | -f Dockerfile.v5.x \ 171 | -t mbentley/omada-controller:5.15-arm64 . 172 | ``` 173 | 174 | ### `armv7l` 175 | 176 | **Warning**: the `armv7l` version was deprecated and support has been removed for versions beyond `5.15.8.2`. 177 | 178 | Both the `ARCH` and `BASE` build-args are required 179 | 180 | ``` 181 | docker build \ 182 | --build-arg INSTALL_VER="5.15.8.2" \ 183 | --build-arg ARCH="armv7l" \ 184 | --build-arg BASE="ubuntu:16.04" \ 185 | -f Dockerfile.v5.x \ 186 | -t mbentley/omada-controller:5.15-armv7l . 187 | ``` 188 | 189 |
190 | 191 | ## Example Usage 192 | 193 | See [Optional Variables](#optional-variables) for details on the environment variables that can modify the behavior of the controller inside the container. To run this Docker image and keep persistent data in named volumes: 194 | 195 | ### Using `net=host` 196 | 197 | Using host networking mode is the preferred method of running the controller. In order to use the host's network namespace, you must first ensure that there are not any port conflicts. The `docker run` command is the same except for that all of the published ports should be removed and `--net host` should be added. Technically it will still work if you have the ports included, but Docker will just silently drop them. Here is a snippet of what the above should be modified to look like: 198 | 199 | ```bash 200 | docker run -d \ 201 | --name omada-controller \ 202 | --stop-timeout 60 \ 203 | --restart unless-stopped \ 204 | --ulimit nofile=4096:8192 \ 205 | --net host \ 206 | -e TZ=Etc/UTC \ 207 | -v omada-data:/opt/tplink/EAPController/data \ 208 | -v omada-logs:/opt/tplink/EAPController/logs \ 209 | mbentley/omada-controller:5.15 210 | ``` 211 | 212 | ### Using port mapping 213 | 214 | Using port mapping is more complex than using host networking as your devices need to be informed of the controller's IP or hostname. See [this TP-Link FAQ](https://www.tp-link.com/us/support/faq/3087/) for details on how to configure this on your device(s) prior to attempting to adopt them. 215 | 216 | __Warning__: If you want to change the controller ports from the default mappings, you *absolutely must* update the port binding inside the container via the environment variables. The ports exposed must match what is inside the container. The Omada Controller software expects that the ports are the same inside the container and outside and will load a blank page if that is not done. See [#99](https://github.com/mbentley/docker-omada-controller/issues/99#issuecomment-821243857) for details and and example of the behavior. 217 | 218 | ```bash 219 | docker run -d \ 220 | --name omada-controller \ 221 | --stop-timeout 60 \ 222 | --restart unless-stopped \ 223 | --ulimit nofile=4096:8192 \ 224 | -p 8088:8088 \ 225 | -p 8043:8043 \ 226 | -p 8843:8843 \ 227 | -p 19810:19810/udp \ 228 | -p 27001:27001/udp \ 229 | -p 29810:29810/udp \ 230 | -p 29811-29816:29811-29816 \ 231 | -e TZ=Etc/UTC \ 232 | -v omada-data:/opt/tplink/EAPController/data \ 233 | -v omada-logs:/opt/tplink/EAPController/logs \ 234 | mbentley/omada-controller:5.15 235 | ``` 236 | 237 | ### Using non-default ports 238 | 239 | __tl;dr__: Always make sure the environment variables for the ports match any changes you have made in the web UI and you'll be fine. 240 | 241 | If you want to change the ports of your Omada Controller to something besides the defaults, there is some unexpected behavior that the controller exhibits. There are two sets of ports: one for HTTP/HTTPS for the controller itself and another for HTTP/HTTPS for the captive portal, typically used for authentication to a guest network. The controller's set of ports, which are set by the `MANAGE_*_PORT` environment variables, can only be modified using the environment variables on the first time the controller is started. If persistent data exists, changing the controller's ports via environment variables will have no effect on the controller itself and can only be modified through the web UI. On the other hand, the portal ports will always be set to whatever has been set in the environment variables, which are set by the `PORTAL_*_PORT` environment variables. 242 | 243 | ### Running Rootless 244 | 245 | There is an optional ability to run the container in a rootless mode. This version has fewer pre-flight capabilities to do tasks like set permissions for you but works in environments where running containers as root is blocked (i.e. - many Kubernetes environments). To activate the [rootless entrypoint](entrypoint-rootless.sh) the following conditions must be met: 246 | 247 | * Set the environment variable `ROOTLESS` to `true` 248 | * Set the actual UID/GID of the container to be your desired values (they must be numerical) 249 | * Note: the `PUID` and `PGID` variables do not apply here 250 | * Set the appropriate ownership of your persistent data directories for `data` and `logs` 251 | * Any additional files or data directories, such as the `/certs` path when injecting your own certificates, must be readable by the user in which you're running as 252 | 253 | Example Kubernetes manifests are available in [k8s](./k8s). 254 | 255 | ## Optional Variables 256 | 257 | | Variable | Default | Values | Description | Valid For | 258 | | :------- | :------ | :----: | :---------- | :-------: | 259 | | `MANAGE_HTTP_PORT` | `8088` | `1024`-`65535` | Management portal HTTP port; for ports < 1024, see [Unprivileged Ports](#unprivileged-ports) | >= `3.2` | 260 | | `MANAGE_HTTPS_PORT` | `8043` | `1024`-`65535` | Management portal HTTPS port; for ports < 1024, see [Unprivileged Ports](#unprivileged-ports) | >= `3.2` | 261 | | `PGID` | `508` | _any_ | Set the `omada` process group ID ` | >= `3.2` | 262 | | `PGROUP` | `omada` | _any_ | Set the group name for the process group ID to run as | >= `5.0` | 263 | | `PORTAL_HTTP_PORT` | `8088` | `1024`-`65535` | User portal HTTP port; for ports < 1024, see [Unprivileged Ports](#unprivileged-ports) | >= `4.1` | 264 | | `PORTAL_HTTPS_PORT` | `8843` | `1024`-`65535` | User portal HTTPS port; for ports < 1024, see [Unprivileged Ports](#unprivileged-ports) | >= `4.1` | 265 | | `PORT_ADOPT_V1` | `29812` | `1024`-`65535` | Omada Controller and Omada Discovery Utility manage the Omada devices running firmware fully adapted to Omada Controller v4* | >= `5.x` | 266 | | `PORT_APP_DISCOVERY` | `27001` | `1024`-`65535` | Omada Controller can be discovered by the Omada APP within the same network through this port | >= `5.x` | 267 | | `PORT_DISCOVERY` | `29810` | `1024`-`65535` | Omada Controller and Omada Discovery Utility discover Omada devices | >= `5.x` | 268 | | `PORT_MANAGER_V1` | `29811` | `1024`-`65535` | Omada Controller and Omada Discovery Utility manage the Omada devices running firmware fully adapted to Omada Controller v4* | >= `5.x` | 269 | | `PORT_MANAGER_V2` | `29814` | `1024`-`65535` | Omada Controller and Omada Discovery Utility manage the Omada devices running firmware fully adapted to Omada Controller v5* | >= `5.x` | 270 | | `PORT_TRANSFER_V2` | `29815` | `1024`-`65535` | Omada Controller receives Device Info and Packet Capture files from the Omada devices | >= `5.9` | 271 | | `PORT_RTTY` | `29816` | `1024`-`65535` | Omada Controller establishes the remote control terminal session with the Omada devices | >= `5.9` | 272 | | `PORT_UPGRADE_V1` | `29813` | `1024`-`65535` | When upgrading the firmware for the Omada devices running firmware fully adapted to Omada Controller v4*. | >= `5.x` | 273 | | `PUID` | `508` | _any_ | Set the `omada` process user ID ` | >= `3.2` | 274 | | `PUSERNAME` | `omada` | _any_ | Set the username for the process user ID to run as | >= `5.0` | 275 | | `ROOTLESS` | `false` | `true`, `false` | Sets the entrypoint for [rootless mode](#running-rootless) | >= `5.14` | 276 | | `SHOW_SERVER_LOGS` | `true` | `true`, `false` | Outputs Omada Controller logs to STDOUT at runtime | >= `4.1` | 277 | | `SHOW_MONGODB_LOGS` | `false` | `true`, `false` | Outputs MongoDB logs to STDOUT at runtime | >= `4.1` | 278 | | `SKIP_USERLAND_KERNEL_CHECK` | `false` | `true`, `false` | When set to `true`, skips the userland/kernel match check for `armv7l` & `arm64` | >= `3.2` | 279 | | `SMALL_FILES` | `false` | `true`, `false` | See [Small Files](#small-files) for more detail; no effect in >= `4.1.x` | `3.2` only | 280 | | `SSL_CERT_NAME` | `tls.crt` | _any_ | Name of the public cert chain mounted to `/cert`; see [Custom Certificates](#custom-certificates) | >= `3.2` | 281 | | `SSL_KEY_NAME` | `tls.key` | _any_ | Name of the private cert mounted to `/cert`; see [Custom Certificates](#custom-certificates) | >= `3.2` | 282 | | `TLS_1_11_ENABLED` | `false` | `true`, `false` | Re-enables TLS 1.0 & 1.1 if set to `true` | >= `4.1` | 283 | | `TZ` | `Etc/UTC` | _\_ | See [Time Zones](#time-zones) for more detail | >= `3.2` | 284 | 285 | Documentation on the ports used by the controller can be found in the [TP-Link FAQ](https://www.tp-link.com/us/support/faq/3281/). 286 | 287 | ## Persistent Data 288 | 289 | In the examples, there are two directories where persistent data is stored: `data` and `logs`. The `data` directory is where the persistent database data is stored where all of your settings, app configuration, etc is stored. The `log` directory is where logs are written and stored. I would suggest that you use a bind mounted volume for the `data` directory to ensure that your persistent data is directly under your control and of course take regular backups within the Omada Controller application itself. Previous versions of the controller (before 5.x) also used a `work` persistent directory `omada-work` which was mapped to `/opt/tplink/EAPController/work` inside the container where the application was deployed. This `work` directory is no longer needed as of 5.0.x. 290 | 291 | ## Custom SSL Certificates 292 | 293 | By default, Omada software uses self-signed certificates. If however you want to use custom certificates you can mount them into the container as `/cert/tls.key` and `/cert/tls.crt`. The `tls.crt` file needs to include the full chain of certificates, i.e. cert, intermediate cert(s) and CA cert. This is compatible with kubernetes TLS secrets. Entrypoint script will convert them into Java Keystore used by jetty inside the Omada SW. If you need to use different file names, you can customize them by passing values for `SSL_CERT_NAME` and `SSL_KEY_NAME` as seen above in the [Optional Variables](#optional-variables) section. 294 | 295 | **Warning** - As of the version 4.1, certificates can also be installed through the web UI. You should not attempt to mix certificate management methods as installing certificates via the UI will store the certificates in MongoDB and then the `/cert` volume method will cease to function. If you installed certificates using the UI and want to revert this - see [this discussion](https://github.com/mbentley/docker-omada-controller/discussions/527). 296 | 297 | ## Time Zones 298 | 299 | By default, this image uses the `Etc/UTC` time zone. You may update the time zone used by passing a different value in the `TZ` variable. See [List of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) for a complete list of values in the `TZ identifier` table column. 300 | 301 | ## Unprivileged Ports 302 | 303 | This Docker image runs as a non-root user by default. In order to bind unprivileged ports (ports < 1024 by default), you must include `--sysctl net.ipv4.ip_unprivileged_port_start=0` in your `docker run` command to allow ports below 1024 to be bound by non-root users. 304 | 305 | ## Using Docker Compose 306 | 307 | There is a [Docker Compose file](https://github.com/mbentley/docker-omada-controller/blob/master/docker-compose.yml) available for those who would like to use compose to manage the lifecycle of their container: 308 | 309 | ```bash 310 | wget https://raw.githubusercontent.com/mbentley/docker-omada-controller/master/docker-compose.yml 311 | 312 | docker compose up -d 313 | ``` 314 | 315 | ## Omada Controller API Documentation 316 | 317 | If you are interested in using the Omada Controller APIs to retrieve data from the controller, the latest version of the API documentation that I have found is available from the [community forums in this post](https://community.tp-link.com/en/business/forum/topic/590430). I'm not able to provide support for the APIs but I've found them to be helpful for my own usage and they weren't easy to find. 318 | 319 | ## Known Issues 320 | 321 | See [the Known Issues](KNOWN_ISSUES.md) documentation for details. 322 | -------------------------------------------------------------------------------- /README_DOCKER_HUB.md: -------------------------------------------------------------------------------- 1 | # mbentley/omada-controller 2 | 3 | Docker image for [TP-Link Omada Controller](https://www.tp-link.com/us/support/download/omada-software-controller/) to control [TP-Link Omada Hardware](https://www.tp-link.com/en/business-networking/all-omada/) 4 | 5 | ## Full README 6 | 7 | For the full readme which includes a list of tags, including usage examples, upgrade details, known issues, and more, refer to the [README in the GitHub repository](https://github.com/mbentley/docker-omada-controller/blob/master/README.md). 8 | 9 | ## Getting Help & Reporting Issues 10 | 11 | If you have issues running the controller, feel free to [create a Help discussion](https://github.com/mbentley/docker-omada-controller/discussions/categories/help) and I will help as I can. If you are specifically having a problem that is related to the actual software, I would suggest filing an issue on the [TP-Link community forums](https://community.tp-link.com/en/business/forum/582) as I do not have access to source code to debug those issues. If you're not sure where the problem might be, I can help determine if it is a running in Docker issue or a software issue. If you're certain you have found a bug, create a [Bug Report Issue](https://github.com/mbentley/docker-omada-controller/issues/new/choose). 12 | -------------------------------------------------------------------------------- /README_v3_and_v4.md: -------------------------------------------------------------------------------- 1 | # README for v3 and v4 2 | 3 | This README is the consolidation of information from the v3 and v4 images which has been removed from the main README. 4 | 5 | ## Table of Contents 6 | 7 | * [Image Tags](#image-tags) 8 | * [Archived Tags](#archived-tags) 9 | * [Upgrade Path](#upgrade-path) 10 | * [Upgrading to 5.0.x from 4.1.x or above](#upgrading-to-50x-from-41x-or-above) 11 | * [Changes/Notes for 5.0.x](#changesnotes-for-50x) 12 | * [Upgrading to 4.1 from 3.2.10 or below](#upgrading-to-41-from-3210-or-below) 13 | * [Notes for 4.1](#notes-for-41) 14 | * [Example Usage](#example-usage) 15 | * [4.x - Example Usage](#4x---example-usage) 16 | * [4.x - Using Port Mapping](#4x---using-port-mapping) 17 | * [4.x - Using net=host](#4x---using-nethost) 18 | * [3.x - Example Usage](#3x---example-usage) 19 | * [3.x - Using Port Mapping](#3x---using-port-mapping) 20 | * [3.x - Using net=host](#3x---using-nethost) 21 | * [Persistent Data and Permissions](#persistent-data-and-permissions) 22 | * [MongoDB Small Files](#mongodb-small-files) 23 | 24 | ## Image Tags 25 | 26 | :warning: **Warning** :warning: Do **NOT** run the `armv7l` (32 bit) images. Upgrade your operating system to `arm64` (64 bit) unless you accept that you're running an outdated MongoDB and a base operating system with unpatched vulnerabilities! See the [Known Issues readme](KNOWN_ISSUES.md#notes-for-armv7l) for more information. 27 | 28 | ## Archived Tags 29 | 30 | All of the v3 and v4 images are still published on Docker Hub but are no longer regularly updated due to the controller software no longer being updated. **Use with extreme caution as these images are likely to contain unpatched security vulnerabilities!** 31 | 32 | The following tags have multi-arch support for `amd64`, `armv7l`, and `arm64` and will automatically pull the correct tag based on your system's architecture: 33 | 34 | | Tag(s) | Major.Minor Release | Current Version | 35 | | :----- | ------------------- | ----------------| 36 | | `4.4` | Omada Controller `4.4.x` | `4.4.8` | 37 | | `4.3` | Omada Controller `4.3.x` | `4.3.5` | 38 | | `4.2` | Omada Controller `4.2.x` | `4.2.11` | 39 | | `4.1` | Omada Controller `4.1.x` | `4.1.5` | 40 | | `3.2` | Omada Controller `3.2.x` | `3.2.17` | 41 | | `3.1` | Omada Controller `3.1.x` | `3.1.13` | 42 | | `3.0` | Omada Controller `3.0.x` | `3.0.5` | 43 | 44 | ## Upgrade Path 45 | 46 | As always, take backups and read the documentation but the quick explanation of the upgrade path is: 47 | 48 | * `3.2` -> `4.1` 49 | * This is a manual upgrade. See [Upgrading to 4.1 from 3.2.10 or below](#upgrading-to-41-from-3210-or-below). 50 | * `4.1` or `4.4` -> `5.13` -> `5.x` (latest) 51 | * These are automatic upgrades that take place by updating the image tag. 52 | * **Note**: Upgrading to `5.13.x` as an intermediate step is required due to `5.14.32.2` removing support for upgrading from v4 to v5. 53 | 54 | ## Upgrading to 5.0.x from 4.1.x or above 55 | 56 | There are no manual upgrade steps directly related to the software itself required when upgrading to 5.0.x if you are already running at least 4.1.x. For full details, please refer to the [TP-Link upgrade documentation](https://www.tp-link.com/en/omada-sdn/controller-upgrade/). 57 | 58 | As always, I would recommend taking a backup through the controller software as well as save a copy of the persistent data while the controller is not running when you do upgrade to simplify the rollback process, if required. 59 | 60 | ### Changes/Notes for 5.0.x 61 | 62 | * **Updated Ports** - If you are only exposing ports using port mapping as the list of ports required has been updated. Starting with 5.0.x, the controller is also listening on `TCP port 29814` so you should add `-p 29814:29814` to your run command, compose file, or however you're running the container. Some additional unnecessary ports are no longer required so the list is shorter now. 63 | * **Volume Updates** - Starting with 5.0.x, the controller software is now built using Spring Boot. This version no longer uses the `work` volume as the application is no longer extracted to a temporary directory. If you do nothing, there will be no impact except for an extra directory sitting around. 64 | * **Custom Ports** - If using custom ports from the defaults of 8088, 8043, and 8843, they will _not_ persist across container re-creation starting in 5.0 unless you **always** set the `MANAGE_*_PORT` enviornment variables. This is due to adding `/opt/tplink/EAPController/properties` to the classpath starting in 5.0. If you change the ports through the UI, you should still continue to also set the ports using the environment variables, matching the ports you have set in the UI. For more detail, see [Using non-default ports](#using-non-default-ports). 65 | 66 | ## Upgrading to 4.1 from 3.2.10 or below 67 | 68 | The upgrade to the 4.1.x version is not a seamless upgrade and can't be done in place. You must be running at least 3.1.4 or greater before you can proceed. Instructions are available from [TP-Link](https://www.tp-link.com/en/omada-sdn/controller-upgrade/) but many of the steps will be different due to running in a docker container. Here are the high level steps: 69 | 70 | 1. Review the steps in the TP-Link instructions as some settings will not transfer to the new version. 71 | 1. Take a backup of your controller as described in the [upgrade procedure](https://www.tp-link.com/en/omada-sdn/controller-upgrade/#content-5_1_1) 72 | 1. Stop your controller 73 | 1. Clear your existing persistent data directories for data, work, and logs. I would recommend backing up the files so you can revert to the previous version in case of issues. 74 | 1. Start your controller with the new Docker image and proceed with at least the basic setup options 75 | 1. Import your backup file to the 4.1 version of the controller 76 | 77 | ### Notes for 4.1 78 | 79 | 1. **Ports** - Do not change the ports for the controller or portal in the UI to ports below 1024 unless you have adjusted the unprivileged ports; for ports < 1024, see [Unprivileged Ports](#unprivileged-ports). 80 | 1. **SSL Certificates** - if you are installing your own SSL certificates, you should only manage them using one method - through the UI or by using the `/cert` volume as [described below](#custom-certificates). 81 | 1. **Synology Users** - if you're using a Synology and are using the `latest` tag and update to 4.1, you will need to make sure to re-create the container due to the `CMD` changing from older versions to 4.1 as Synology retains the entrypoint and command from the container as it is defined and not from the image. 82 | 83 | ## Example Usage 84 | 85 | For additional usage information, check out [this revision](https://github.com/mbentley/docker-omada-controller/blob/9885438b013651d18c29b5b2b9e1d18be70e2e5c/README.md) in the git history. 86 | 87 | ### Using non-default ports 88 | 89 | __tl;dr__: Always make sure the environment variables for the ports match any changes you have made in the web UI and you'll be fine. 90 | 91 | **Note**: The `3.2` version of the controller only supports the `MANAGE_HTTP_PORT` and `MANAGE_HTTPS_PORT` variables for modifying the controller's admin web interface ports. This means that setting `PORTAL_HTTP_PORT` and `PORTAL_HTTPS_PORT` will not have any effect in `3.2`. Versions `4.x` or greater support all of the `MANAGE_*_PORT` and `PORTAL_*_PORT` variables as described in the [Optional Variables](#optional-variables) section. 92 | 93 | ### 4.x - Example Usage 94 | 95 | #### 4.x - Using port mapping 96 | 97 | ``` 98 | docker run -d \ 99 | --name omada-controller \ 100 | --restart unless-stopped \ 101 | -p 8088:8088 \ 102 | -p 8043:8043 \ 103 | -p 8843:8843 \ 104 | -p 29810:29810 \ 105 | -p 29810:29810/udp \ 106 | -p 29811:29811 \ 107 | -p 29811:29811/udp \ 108 | -p 29812:29812 \ 109 | -p 29812:29812/udp \ 110 | -p 29813:29813 \ 111 | -p 29813:29813/udp \ 112 | -e MANAGE_HTTP_PORT=8088 \ 113 | -e MANAGE_HTTPS_PORT=8043 \ 114 | -e PORTAL_HTTP_PORT=8088 \ 115 | -e PORTAL_HTTPS_PORT=8843 \ 116 | -e SHOW_SERVER_LOGS=true \ 117 | -e SHOW_MONGODB_LOGS=false \ 118 | -e SSL_CERT_NAME="tls.crt" \ 119 | -e SSL_KEY_NAME="tls.key" \ 120 | -e TZ=Etc/UTC \ 121 | -v omada-data:/opt/tplink/EAPController/data \ 122 | -v omada-work:/opt/tplink/EAPController/work \ 123 | -v omada-logs:/opt/tplink/EAPController/logs \ 124 | mbentley/omada-controller:4.4 125 | ``` 126 | 127 | #### 4.x - Using `net=host` 128 | 129 | ``` 130 | docker run -d \ 131 | --name omada-controller \ 132 | --restart unless-stopped \ 133 | --net host \ 134 | -e MANAGE_HTTP_PORT=8088 \ 135 | -e MANAGE_HTTPS_PORT=8043 \ 136 | -e PORTAL_HTTP_PORT=8088 \ 137 | -e PORTAL_HTTPS_PORT=8843 \ 138 | -e SHOW_SERVER_LOGS=true \ 139 | -e SHOW_MONGODB_LOGS=false \ 140 | -e SSL_CERT_NAME="tls.crt" \ 141 | -e SSL_KEY_NAME="tls.key" \ 142 | -e TZ=Etc/UTC \ 143 | -v omada-data:/opt/tplink/EAPController/data \ 144 | -v omada-work:/opt/tplink/EAPController/work \ 145 | -v omada-logs:/opt/tplink/EAPController/logs \ 146 | mbentley/omada-controller:4.4 147 | ``` 148 | 149 | ### 3.x - Example Usage 150 | 151 | #### 3.x - Using port mapping 152 | 153 | The below example can be used with 3.2. The port and volume mappings have changed in newer versions. 154 | 155 | ``` 156 | docker run -d \ 157 | --name omada-controller \ 158 | --stop-timeout 60 \ 159 | --restart unless-stopped \ 160 | --ulimit nofile=4096:8192 \ 161 | -p 8088:8088 \ 162 | -p 8043:8043 \ 163 | -p 8843:8843 \ 164 | -p 29810:29810/udp \ 165 | -p 29811:29811 \ 166 | -p 29812:29812 \ 167 | -p 29813:29813 \ 168 | -p 29814:29814 \ 169 | -e MANAGE_HTTP_PORT=8088 \ 170 | -e MANAGE_HTTPS_PORT=8043 \ 171 | -e SMALL_FILES=false \ 172 | -e SSL_CERT_NAME="tls.crt" \ 173 | -e SSL_KEY_NAME="tls.key" \ 174 | -e TZ=Etc/UTC \ 175 | -v omada-data:/opt/tplink/EAPController/data \ 176 | -v omada-work:/opt/tplink/EAPController/work \ 177 | -v omada-logs:/opt/tplink/EAPController/logs \ 178 | mbentley/omada-controller:3.2 179 | ``` 180 | 181 | #### 3.x - Using `net=host` 182 | 183 | ``` 184 | docker run -d \ 185 | --name omada-controller \ 186 | --stop-timeout 60 \ 187 | --restart unless-stopped \ 188 | --ulimit nofile=4096:8192 \ 189 | --net host \ 190 | -e MANAGE_HTTP_PORT=8088 \ 191 | -e MANAGE_HTTPS_PORT=8043 \ 192 | -e SMALL_FILES=false \ 193 | -e SSL_CERT_NAME="tls.crt" \ 194 | -e SSL_KEY_NAME="tls.key" \ 195 | -e TZ=Etc/UTC \ 196 | -v omada-data:/opt/tplink/EAPController/data \ 197 | -v omada-work:/opt/tplink/EAPController/work \ 198 | -v omada-logs:/opt/tplink/EAPController/logs \ 199 | mbentley/omada-controller:3.2 200 | ``` 201 | 202 | ## Persistent Data and Permissions 203 | 204 | **Note**: The permissions portion only applies to tags for `3.1.x` and `3.0.x` as the `3.2.x` and newer versions manage the permissions for you. 205 | 206 | If you utilize bind mounts instead of Docker named volumes (e.g. - `-v /path/to/data:/opt/tplink/EAPController/data`) in your run command, you will want to make sure that you have set the permissions appropriately on the filesystem otherwise you will run into permissions errors and the container will not run because it won't have the permissions to write data since this container uses a non-root user. To resolve that, you need to `chown` the directory to `508:508` on the host as that is the UID and GID that we use inside the container. For example: 207 | 208 | ```bash 209 | chown -R 508:508 /data/omada/data /data/omada/logs 210 | ``` 211 | 212 | In the examples, there are two directories where persistent data is stored: `data` and `logs`. The `data` directory is where the persistent database data is stored where all of your settings, app configuration, etc is stored. The `log` directory is where logs are written and stored. I would suggest that you use a bind mounted volume for the `data` directory to ensure that your persistent data is directly under your control and of course take regular backups within the Omada Controller application itself. 213 | 214 | ## MongoDB Small Files 215 | 216 | In Omada 3.2 and older, this image uses the default mongodb settings for journal files. If disk space is an issue, you can set the `SMALL_FILES` variable to `true` which will add [`--smallfiles`](https://docs.mongodb.com/v3.6/core/journaling/#journaling-journal-files) to the startup arguments for MongoDB. 217 | 218 | **Warning** - As of the version 4.1 and newer, MongoDB utilizes the `WiredTiger` storage engine by default which does not have the same journal file size issue as the `MMAPv1` storage engine. If `SMALL_FILES` is set to `true`, a warning will be issued at startup but startup will still proceed. 219 | -------------------------------------------------------------------------------- /SUPPORT_INFO.md: -------------------------------------------------------------------------------- 1 | # Support Information to Gather When Asking for Help 2 | 3 | When filing either an issue or discussion for help, it is always helpful to provide as much information as possible. Here are the things that will be helpful for troubleshooting purposes: 4 | 5 | 1. The version of the controller you're running. 6 | * This can be found in the container's logs so at least if you provide the logs, I can find it in there if you really do not know. 7 | 1. How You're Launching the Container 8 | * This is either going to be a `docker run` command, compose file, or the equivalent of whatever tool you're launching the container from. 9 | * If you do not have any of this information, for whatever reason, you can provide the output of `docker container inspect omada-controller` to provide enough information to help. 10 | 1. Details of the docker image you're running from the output of: 11 | * `docker inspect omada-controller --format '{{json .Image}}'` 12 | * `docker images --filter=reference='mbentley/omada-controller' --digests --format '{{.Repository}}:{{.Tag}}@{{.Digest}}'` 13 | 1. Container & App Logs 14 | * Container logs can be collected using `docker logs omada-controller >& output.log` to put them in a file called `output.log`. 15 | * MongoDB logs do not log to the console by default as they can be very verbose but they can be collected using `docker cp omada-controller:/opt/tplink/EAPController/logs/mongod.log .` to copy out the `mongod.log` to the current directory. The `mongod.log` file may also be in a volume if you have specified a volume path for the container's `/opt/tplink/EAPController/logs` directory. These logs are especially helpful when the container is not starting as expected. 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | omada-controller: 3 | container_name: omada-controller 4 | image: mbentley/omada-controller:5.15 5 | restart: unless-stopped 6 | ulimits: 7 | nofile: 8 | soft: 4096 9 | hard: 8192 10 | stop_grace_period: 60s 11 | network_mode: host 12 | environment: 13 | - PUID=508 14 | - PGID=508 15 | - MANAGE_HTTP_PORT=8088 16 | - MANAGE_HTTPS_PORT=8043 17 | - PORTAL_HTTP_PORT=8088 18 | - PORTAL_HTTPS_PORT=8843 19 | - PORT_APP_DISCOVERY=27001 20 | - PORT_ADOPT_V1=29812 21 | - PORT_UPGRADE_V1=29813 22 | - PORT_MANAGER_V1=29811 23 | - PORT_MANAGER_V2=29814 24 | - PORT_DISCOVERY=29810 25 | - PORT_TRANSFER_V2=29815 26 | - PORT_RTTY=29816 27 | - SHOW_SERVER_LOGS=true 28 | - SHOW_MONGODB_LOGS=false 29 | - SSL_CERT_NAME=tls.crt 30 | - SSL_KEY_NAME=tls.key 31 | - TZ=Etc/UTC 32 | volumes: 33 | - omada-data:/opt/tplink/EAPController/data 34 | - omada-logs:/opt/tplink/EAPController/logs 35 | 36 | volumes: 37 | omada-data: 38 | omada-logs: 39 | -------------------------------------------------------------------------------- /docker-compose_bridge.yml: -------------------------------------------------------------------------------- 1 | services: 2 | omada-controller: 3 | container_name: omada-controller 4 | image: mbentley/omada-controller:5.15 5 | restart: unless-stopped 6 | ulimits: 7 | nofile: 8 | soft: 4096 9 | hard: 8192 10 | stop_grace_period: 60s 11 | network_mode: bridge 12 | ports: 13 | - 8088:8088 14 | - 8043:8043 15 | - 8843:8843 16 | - 19810:19810/udp 17 | - 27001:27001/udp 18 | - 29810:29810/udp 19 | - 29811-29816:29811-29816 20 | environment: 21 | - PUID=508 22 | - PGID=508 23 | - MANAGE_HTTP_PORT=8088 24 | - MANAGE_HTTPS_PORT=8043 25 | - PORTAL_HTTP_PORT=8088 26 | - PORTAL_HTTPS_PORT=8843 27 | - PORT_APP_DISCOVERY=27001 28 | - PORT_ADOPT_V1=29812 29 | - PORT_UPGRADE_V1=29813 30 | - PORT_MANAGER_V1=29811 31 | - PORT_MANAGER_V2=29814 32 | - PORT_DISCOVERY=29810 33 | - PORT_TRANSFER_V2=29815 34 | - PORT_RTTY=29816 35 | - SHOW_SERVER_LOGS=true 36 | - SHOW_MONGODB_LOGS=false 37 | - SSL_CERT_NAME=tls.crt 38 | - SSL_KEY_NAME=tls.key 39 | - TZ=Etc/UTC 40 | volumes: 41 | - omada-data:/opt/tplink/EAPController/data 42 | - omada-logs:/opt/tplink/EAPController/logs 43 | 44 | volumes: 45 | omada-data: 46 | omada-logs: 47 | -------------------------------------------------------------------------------- /entrypoint-5.x.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # check if rootless; run alternate entrypoint 6 | if [ "${ROOTLESS}" = "true" ] 7 | then 8 | echo "INFO: ROOTLESS=true; switching to rootless entrypoint..." 9 | exec /entrypoint-rootless.sh "${@}" 10 | fi 11 | 12 | # set environment variables 13 | export TZ 14 | TZ="${TZ:-Etc/UTC}" 15 | SMALL_FILES="${SMALL_FILES:-false}" 16 | 17 | # PORTS CONFIGURATION 18 | MANAGE_HTTP_PORT="${MANAGE_HTTP_PORT:-8088}" 19 | MANAGE_HTTPS_PORT="${MANAGE_HTTPS_PORT:-8043}" 20 | PORTAL_HTTP_PORT="${PORTAL_HTTP_PORT:-8088}" 21 | PORTAL_HTTPS_PORT="${PORTAL_HTTPS_PORT:-8843}" 22 | PORT_ADOPT_V1="${PORT_ADOPT_V1:-29812}" 23 | PORT_APP_DISCOVERY="${PORT_APP_DISCOVERY:-27001}" 24 | PORT_UPGRADE_V1="${PORT_UPGRADE_V1:-29813}" 25 | PORT_MANAGER_V1="${PORT_MANAGER_V1:-29811}" 26 | PORT_MANAGER_V2="${PORT_MANAGER_V2:-29814}" 27 | PORT_DISCOVERY="${PORT_DISCOVERY:-29810}" 28 | PORT_TRANSFER_V2="${PORT_TRANSFER_V2:-29815}" 29 | PORT_RTTY="${PORT_RTTY:-29816}" 30 | # END PORTS CONFIGURATION 31 | 32 | # EXTERNAL MONGODB 33 | MONGO_EXTERNAL="${MONGO_EXTERNAL:-false}" 34 | EAP_MONGOD_URI="${EAP_MONGOD_URI:-mongodb://127.0.0.1:27217/omada}" 35 | # escape & for eval 36 | EAP_MONGOD_URI="$(eval echo "${EAP_MONGOD_URI//&/\\&}")" 37 | # escape after eval as well for sed 38 | EAP_MONGOD_URI="${EAP_MONGOD_URI//&/\\&}" 39 | # END EXTERNAL MONGODB 40 | 41 | SHOW_SERVER_LOGS="${SHOW_SERVER_LOGS:-true}" 42 | SHOW_MONGODB_LOGS="${SHOW_MONGODB_LOGS:-false}" 43 | SSL_CERT_NAME="${SSL_CERT_NAME:-tls.crt}" 44 | SSL_KEY_NAME="${SSL_KEY_NAME:-tls.key}" 45 | TLS_1_11_ENABLED="${TLS_1_11_ENABLED:-false}" 46 | PUID="${PUID:-508}" 47 | PGID="${PGID:-508}" 48 | PUSERNAME="${PUSERNAME:-omada}" 49 | PGROUP="${PGROUP:-omada}" 50 | SKIP_USERLAND_KERNEL_CHECK="${SKIP_USERLAND_KERNEL_CHECK:-false}" 51 | 52 | # validate user/group exist with correct UID/GID 53 | echo "INFO: Validating user/group (${PUSERNAME}:${PGROUP}) exists with correct UID/GID (${PUID}:${PGID})" 54 | 55 | # check to see if group exists; if not, create it 56 | if grep -q -E "^${PGROUP}:" /etc/group > /dev/null 2>&1 57 | then 58 | # existing group found; also make sure the omada group matches the GID 59 | echo "INFO: Group (${PGROUP}) exists; skipping creation" 60 | EXISTING_GID="$(getent group "${PGROUP}" | cut -d: -f3)" 61 | if [ "${EXISTING_GID}" != "${PGID}" ] 62 | then 63 | echo "ERROR: Group (${PGROUP}) has an unexpected GID; was expecting '${PGID}' but found '${EXISTING_GID}'!" 64 | exit 1 65 | fi 66 | else 67 | # make sure the group doesn't already exist with a different name 68 | if awk -F ':' '{print $3}' /etc/group | grep -q "^${PGID}$" 69 | then 70 | # group ID exists but has a different group name 71 | EXISTING_GROUP="$(grep ":${PGID}:" /etc/group | awk -F ':' '{print $1}')" 72 | echo "INFO: Group (${PGROUP}) already exists with a different name; renaming '${EXISTING_GROUP}' to '${PGROUP}'" 73 | groupmod -n "${PGROUP}" "${EXISTING_GROUP}" 74 | else 75 | # create the group 76 | echo "INFO: Group (${PGROUP}) doesn't exist; creating" 77 | groupadd -g "${PGID}" "${PGROUP}" 78 | fi 79 | fi 80 | 81 | # check to see if user exists; if not, create it 82 | if id -u "${PUSERNAME}" > /dev/null 2>&1 83 | then 84 | # exiting user found; also make sure the omada user matches the UID 85 | echo "INFO: User (${PUSERNAME}) exists; skipping creation" 86 | EXISTING_UID="$(id -u "${PUSERNAME}")" 87 | if [ "${EXISTING_UID}" != "${PUID}" ] 88 | then 89 | echo "ERROR: User (${PUSERNAME}) has an unexpected UID; was expecting '${PUID}' but found '${EXISTING_UID}'!" 90 | exit 1 91 | fi 92 | else 93 | # make sure the user doesn't already exist with a different name 94 | if awk -F ':' '{print $3}' /etc/passwd | grep -q "^${PUID}$" 95 | then 96 | # user ID exists but has a different user name 97 | EXISTING_USER="$(grep ":${PUID}:" /etc/passwd | awk -F ':' '{print $1}')" 98 | echo "INFO: User (${PUSERNAME}) already exists with a different name; renaming '${EXISTING_USER}' to '${PUSERNAME}'" 99 | usermod -g "${PGID}" -d /opt/tplink/EAPController/data -l "${PUSERNAME}" -s /bin/sh -c "" "${EXISTING_USER}" 100 | else 101 | # create the user 102 | echo "INFO: User (${PUSERNAME}) doesn't exist; creating" 103 | useradd -u "${PUID}" -g "${PGID}" -d /opt/tplink/EAPController/data -s /bin/sh -c "" "${PUSERNAME}" 104 | fi 105 | fi 106 | 107 | # check if properties file exists; create it if it is missing 108 | DEFAULT_FILES="/opt/tplink/EAPController/properties.defaults/*" 109 | for FILE in ${DEFAULT_FILES} 110 | do 111 | BASENAME=$(basename "${FILE}") 112 | if [ ! -f "/opt/tplink/EAPController/properties/${BASENAME}" ] 113 | then 114 | echo "INFO: Properties file '${BASENAME}' missing, restoring default file..." 115 | cp "${FILE}" "/opt/tplink/EAPController/properties/${BASENAME}" 116 | chown "${PUSERNAME}:${PGROUP}" "/opt/tplink/EAPController/properties/${BASENAME}" 117 | fi 118 | done 119 | 120 | # make sure that the html directory exists 121 | if [ ! -d "/opt/tplink/EAPController/data/html" ] && [ -f "/opt/tplink/EAPController/data-html.tar.gz" ] 122 | then 123 | # missing directory; extract from original 124 | echo "INFO: Report HTML directory missing; extracting backup to '/opt/tplink/EAPController/data/html'" 125 | tar zxvf /opt/tplink/EAPController/data-html.tar.gz -C /opt/tplink/EAPController/data 126 | chown -R "${PUSERNAME}:${PGROUP}" /opt/tplink/EAPController/data/html 127 | fi 128 | 129 | # make sure that the pdf directory exists 130 | if [ ! -d "/opt/tplink/EAPController/data/pdf" ] 131 | then 132 | # missing directory; extract from original 133 | echo "INFO: Report PDF directory missing; creating '/opt/tplink/EAPController/data/pdf'" 134 | mkdir /opt/tplink/EAPController/data/pdf 135 | chown -R "${PUSERNAME}:${PGROUP}" /opt/tplink/EAPController/data/pdf 136 | fi 137 | 138 | # check to see if there is a db directory; create it if it is missing 139 | if [ ! -d "/opt/tplink/EAPController/data/db" ] 140 | then 141 | echo "INFO: Database directory missing; creating '/opt/tplink/EAPController/data/db'" 142 | mkdir /opt/tplink/EAPController/data/db 143 | chown "${PUSERNAME}:${PGROUP}" /opt/tplink/EAPController/data/db 144 | echo "done" 145 | fi 146 | 147 | # set default time zone and notify user of time zone 148 | echo "INFO: Time zone set to '${TZ}'" 149 | 150 | # append smallfiles if set to true 151 | if [ "${SMALL_FILES}" = "true" ] 152 | then 153 | echo "WARN: smallfiles was passed but is not supported in >= 4.1 with the WiredTiger engine in use by MongoDB" 154 | echo "INFO: Skipping setting smallfiles option" 155 | fi 156 | 157 | # update stored ports when different of enviroment defined ports (works for numbers only) 158 | for ELEM in MANAGE_HTTP_PORT MANAGE_HTTPS_PORT PORTAL_HTTP_PORT PORTAL_HTTPS_PORT PORT_ADOPT_V1 PORT_APP_DISCOVERY PORT_UPGRADE_V1 PORT_MANAGER_V1 PORT_MANAGER_V2 PORT_DISCOVERY PORT_TRANSFER_V2 PORT_RTTY 159 | do 160 | # convert element to key name 161 | KEY="$(echo "${ELEM}" | tr '[:upper:]' '[:lower:]' | tr '_' '.')" 162 | 163 | # get value we want to set from the element 164 | END_VAL=${!ELEM} 165 | 166 | # get the current value from the omada.properties file 167 | STORED_PROP_VAL=$(grep -Po "(?<=${KEY}=)([0-9]+)" /opt/tplink/EAPController/properties/omada.properties || true) 168 | 169 | # check to see if we need to set the value 170 | if [ "${STORED_PROP_VAL}" = "" ] 171 | then 172 | echo "INFO: Skipping '${KEY}' - not present in omada.properties" 173 | elif [ "${STORED_PROP_VAL}" != "${END_VAL}" ] 174 | then 175 | # check to see if we are trying to bind to privileged port 176 | if [ "${END_VAL}" -lt "1024" ] && [ "$(cat /proc/sys/net/ipv4/ip_unprivileged_port_start)" = "1024" ] 177 | then 178 | echo "ERROR: Unable to set '${KEY}' to ${END_VAL}; 'ip_unprivileged_port_start' has not been set. See https://github.com/mbentley/docker-omada-controller#unprivileged-ports" 179 | exit 1 180 | fi 181 | 182 | # update the key-value pair 183 | echo "INFO: Setting '${KEY}' to ${END_VAL} in omada.properties" 184 | sed -i "s~^${KEY}=${STORED_PROP_VAL}$~${KEY}=${END_VAL}~g" /opt/tplink/EAPController/properties/omada.properties 185 | else 186 | # values already match; nothing to change 187 | echo "INFO: Value of '${KEY}' already set to ${END_VAL} in omada.properties" 188 | fi 189 | done 190 | 191 | # update stored property values when different of environment defined values (works for any value) 192 | for ELEM in MONGO_EXTERNAL EAP_MONGOD_URI 193 | do 194 | # convert element to key name 195 | KEY="$(echo "${ELEM}" | tr '[:upper:]' '[:lower:]' | tr '_' '.')" 196 | 197 | # get the full key & value to store for checking later 198 | KEY_VALUE="$(grep "^${KEY}=" /opt/tplink/EAPController/properties/omada.properties || true)" 199 | 200 | # get value we want to set from the element 201 | END_VAL=${!ELEM} 202 | 203 | # get the current value from the omada.properties file 204 | STORED_PROP_VAL=$(grep -Po "(?<=${KEY}=)(.*)+" /opt/tplink/EAPController/properties/omada.properties || true) 205 | 206 | # check to see if we need to set the value; see if there is something in the key/value first 207 | if [ -z "${KEY_VALUE}" ] 208 | then 209 | echo "INFO: Skipping '${KEY}' - not present in omada.properties" 210 | elif [ "${STORED_PROP_VAL}" != "${END_VAL}" ] 211 | then 212 | # update the key-value pair 213 | echo "INFO: Setting '${KEY}' to ${END_VAL} in omada.properties" 214 | sed -i "s~^${KEY}=${STORED_PROP_VAL}$~${KEY}=${END_VAL}~g" /opt/tplink/EAPController/properties/omada.properties 215 | else 216 | # values already match; nothing to change 217 | echo "INFO: Value of '${KEY}' already set to ${END_VAL} in omada.properties" 218 | fi 219 | done 220 | 221 | # make sure permissions are set appropriately on each directory 222 | for DIR in data logs properties 223 | do 224 | OWNER="$(stat -c '%u' /opt/tplink/EAPController/${DIR})" 225 | GROUP="$(stat -c '%g' /opt/tplink/EAPController/${DIR})" 226 | 227 | if [ "${OWNER}" != "${PUID}" ] || [ "${GROUP}" != "${PGID}" ] 228 | then 229 | # notify user that uid:gid are not correct and fix them 230 | echo "WARN: Ownership not set correctly on '/opt/tplink/EAPController/${DIR}'; setting correct ownership (${PUSERNAME}:${PGROUP})" 231 | chown -R "${PUSERNAME}:${PGROUP}" "/opt/tplink/EAPController/${DIR}" 232 | fi 233 | done 234 | 235 | # validate permissions on /tmp 236 | TMP_PERMISSIONS="$(stat -c '%a' /tmp)" 237 | if [ "${TMP_PERMISSIONS}" != "1777" ] 238 | then 239 | echo "WARN: Permissions are not set correctly on '/tmp' (${TMP_PERMISSIONS}); setting correct permissions (1777)" 240 | chmod -v 1777 /tmp 241 | fi 242 | 243 | # Import a cert from a possibly mounted secret or file at /cert 244 | if [ -f "/cert/${SSL_KEY_NAME}" ] && [ -f "/cert/${SSL_CERT_NAME}" ] 245 | then 246 | # see where the keystore directory is; check for old location first 247 | if [ -d /opt/tplink/EAPController/keystore ] 248 | then 249 | # keystore in the parent folder before 5.3.1 250 | KEYSTORE_DIR="/opt/tplink/EAPController/keystore" 251 | else 252 | # keystore directory moved to the data directory in 5.3.1 253 | KEYSTORE_DIR="/opt/tplink/EAPController/data/keystore" 254 | 255 | # check to see if the KEYSTORE_DIR exists (it won't on upgrade) 256 | if [ ! -d "${KEYSTORE_DIR}" ] 257 | then 258 | echo "INFO: Creating keystore directory (${KEYSTORE_DIR})" 259 | mkdir "${KEYSTORE_DIR}" 260 | echo "INFO: Setting permissions on ${KEYSTORE_DIR}" 261 | chown "${PUSERNAME}:${PGROUP}" "${KEYSTORE_DIR}" 262 | fi 263 | fi 264 | 265 | echo "INFO: Importing cert from /cert/tls.[key|crt]" 266 | # delete the existing keystore 267 | rm -f "${KEYSTORE_DIR}/eap.keystore" 268 | 269 | # example certbot usage: ./certbot-auto certonly --standalone --preferred-challenges http -d mydomain.net 270 | openssl pkcs12 -export \ 271 | -inkey "/cert/${SSL_KEY_NAME}" \ 272 | -in "/cert/${SSL_CERT_NAME}" \ 273 | -certfile "/cert/${SSL_CERT_NAME}" \ 274 | -name eap \ 275 | -out "${KEYSTORE_DIR}/eap.keystore" \ 276 | -passout pass:tplink 277 | 278 | # set ownership/permission on keystore 279 | chown "${PUSERNAME}:${PGROUP}" "${KEYSTORE_DIR}/eap.keystore" 280 | chmod 400 "${KEYSTORE_DIR}/eap.keystore" 281 | fi 282 | 283 | # re-enable disabled TLS versions 1.0 & 1.1 284 | if [ "${TLS_1_11_ENABLED}" = "true" ] 285 | then 286 | echo "INFO: Re-enabling TLS 1.0 & 1.1" 287 | if [ -f "/etc/java-8-openjdk/security/java.security" ] 288 | then 289 | # openjdk8 290 | sed -i 's#^jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1,#jdk.tls.disabledAlgorithms=SSLv3,#' /etc/java-8-openjdk/security/java.security 291 | elif [ -f "/etc/java-17-openjdk/security/java.security" ] 292 | then 293 | # openjdk17 294 | sed -i 's#^jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1,#jdk.tls.disabledAlgorithms=SSLv3,#' /etc/java-17-openjdk/security/java.security 295 | else 296 | # not running openjdk8 or openjdk17 297 | echo "WARN: Unable to re-enable TLS 1.0 & 1.1; unable to detect openjdk version" 298 | fi 299 | fi 300 | 301 | # see if any of these files exist; if so, do not start as they are from older versions 302 | if [ -f /opt/tplink/EAPController/data/db/tpeap.0 ] || [ -f /opt/tplink/EAPController/data/db/tpeap.1 ] || [ -f /opt/tplink/EAPController/data/db/tpeap.ns ] 303 | then 304 | echo "ERROR: The data volume mounted to /opt/tplink/EAPController/data appears to have data from a previous version!" 305 | echo " Follow the upgrade instructions at https://github.com/mbentley/docker-omada-controller#upgrading-to-41" 306 | exit 1 307 | fi 308 | 309 | # check to see if the CMD passed contains the text "com.tplink.omada.start.OmadaLinuxMain" which is the old classpath from 4.x 310 | if [ "$(echo "${@}" | grep -q "com.tplink.omada.start.OmadaLinuxMain"; echo $?)" = "0" ] 311 | then 312 | echo -e "\n############################" 313 | echo "WARN: CMD from 4.x detected! It is likely that this container will fail to start properly with a \"Could not find or load main class com.tplink.omada.start.OmadaLinuxMain\" error!" 314 | echo " See the note on old CMDs at https://github.com/mbentley/docker-omada-controller/blob/master/KNOWN_ISSUES.md#upgrade-issues for details on why and how to resolve the issue." 315 | echo -e "############################\n" 316 | fi 317 | 318 | # compare version from the image to the version stored in the persistent data (last ran version) 319 | if [ -f "/opt/tplink/EAPController/IMAGE_OMADA_VER.txt" ] 320 | then 321 | # file found; read the version that is in the image 322 | IMAGE_OMADA_VER="$(cat /opt/tplink/EAPController/IMAGE_OMADA_VER.txt)" 323 | else 324 | echo "ERROR: Missing image version file (/opt/tplink/EAPController/IMAGE_OMADA_VER.txt); this should never happen!" 325 | exit 1 326 | fi 327 | 328 | # load LAST_RAN_OMADA_VER, if file present 329 | if [ -f "/opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt" ] 330 | then 331 | # file found; read the version that was last recorded 332 | LAST_RAN_OMADA_VER="$(cat /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt)" 333 | else 334 | # no file found; set version to 0.0.0 as we don't know the last version 335 | LAST_RAN_OMADA_VER="0.0.0" 336 | fi 337 | 338 | # make sure we are not trying to upgrade from 4.x to 5.14.32.x 339 | LAST_RAN_MAJOR_VER="$(echo "${LAST_RAN_OMADA_VER}" | awk -F '.' '{print $1}')" 340 | IMAGE_MAJOR_VER="$(echo "${IMAGE_OMADA_VER}" | awk -F '.' '{print $1}')" 341 | IMAGE_MINOR_VER="$(echo "${IMAGE_OMADA_VER}" | awk -F '.' '{print $2}')" 342 | 343 | # make sure we are not trying to upgrade from 4.x to 5.14.32.x or greater 344 | if [ "${LAST_RAN_MAJOR_VER}" = "4" ] && [ "${IMAGE_MAJOR_VER}" -ge "5" ] 345 | then 346 | # check to see if we are runnning 5.14 or greater 347 | if [ "${IMAGE_MAJOR_VER}" = "5" ] && [ "${IMAGE_MINOR_VER}" -ge "14" ] || [ "${IMAGE_MAJOR_VER}" -gt "5" ] 348 | then 349 | echo "ERROR: You are attempting to upgrade from 4.x to 5.14.x or greater; the upgrade code was removed in 5.14.x!" 350 | echo " See https://github.com/mbentley/docker-omada-controller/blob/master/README_v3_and_v4.md#upgrade-path for the upgrade path from 4.x to 5.x" 351 | exit 1 352 | fi 353 | fi 354 | 355 | # use sort to check which version is newer; should sort the newest version to the top 356 | if [ "$(printf '%s\n' "${IMAGE_OMADA_VER}" "${LAST_RAN_OMADA_VER}" | sort -rV | head -n1)" != "${IMAGE_OMADA_VER}" ] 357 | then 358 | # version in the image is didn't match newest image version; this means we are trying to start and older version 359 | echo "ERROR: The version from the image (${IMAGE_OMADA_VER}) is older than the last version executed (${LAST_RAN_OMADA_VER})! Refusing to start to prevent data loss!" 360 | echo " To bypass this check, remove /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt only if you REALLY know what you're doing!" 361 | exit 1 362 | else 363 | echo "INFO: Version check passed; image version (${IMAGE_OMADA_VER}) >= the last version ran (${LAST_RAN_OMADA_VER}); writing image version to last ran file..." 364 | echo "${IMAGE_OMADA_VER}" > /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt 365 | fi 366 | 367 | # check to see if we are in a bad situation with a 32 bit userland and 64 bit kernel (fails to start MongoDB on a Raspberry Pi) 368 | if [ "$(dpkg --print-architecture)" = "armhf" ] && [ "$(uname -m)" = "aarch64" ] && [ "${SKIP_USERLAND_KERNEL_CHECK}" = "false" ] 369 | then 370 | echo "##############################################################################" 371 | echo "##############################################################################" 372 | echo "ERROR: 32 bit userspace with 64 bit kernel detected! MongoDB will NOT start!" 373 | echo " See https://github.com/mbentley/docker-omada-controller/blob/master/KNOWN_ISSUES.md#mismatched-userland-and-kernel for how to fix the issue" 374 | echo "##############################################################################" 375 | echo "##############################################################################" 376 | 377 | exit 1 378 | else 379 | echo "INFO: userland/kernel check passed" 380 | fi 381 | 382 | # see if we should try to delete bcpkix-jdk15on-1.70.jar and bcprov-jdk15on-1.70.jar to workaround https://github.com/mbentley/docker-omada-controller/issues/509 383 | if [ "${WORKAROUND_509}" = "true" ] && [ "${IMAGE_OMADA_VER}" = "5.15.6.7" ] 384 | then 385 | echo "INFO: WORKAROUND_509=true; deleting files that block controller startup, if present" 386 | 387 | # delete files, if present 388 | for FILE in bcpkix-jdk15on-1.70.jar bcprov-jdk15on-1.70.jar 389 | do 390 | # see if the file is there 391 | if [ -f "${FILE}" ] 392 | then 393 | # found; delete it 394 | echo -ne "INFO: deleting '/opt/tplink/EAPController/lib/${FILE}'\nINFO: " 395 | rm -v "/opt/tplink/EAPController/lib/${FILE}" 396 | else 397 | # not found 398 | echo "INFO: '/opt/tplink/EAPController/lib/${FILE}' isn't present, skipping" 399 | fi 400 | done 401 | 402 | echo "INFO: WORKAROUND_509 complete!" 403 | elif [ "${WORKAROUND_509}" = "true" ] && [ "${IMAGE_OMADA_VER}" != "5.15.6.7" ] 404 | then 405 | echo "WARN: WORKAROUND_509=true; but you're not running an impacted version; skipping workaround. (You should remove this env var as it does nothing!)" 406 | fi 407 | 408 | # show java version 409 | echo -e "INFO: output of 'java -version':\n$(java -version 2>&1)\n" 410 | 411 | # get the java version in different formats 412 | JAVA_VERSION="$(java -version 2>&1 | head -n 1 | awk -F '"' '{print $2}')" 413 | JAVA_VERSION_1="$(echo "${JAVA_VERSION}" | awk -F '.' '{print $1}')" 414 | JAVA_VERSION_2="$(echo "${JAVA_VERSION}" | awk -F '.' '{print $2}')" 415 | 416 | # for java 8, remove the opens argument from the CMD 417 | case ${JAVA_VERSION_1}.${JAVA_VERSION_2} in 418 | 1.8) 419 | echo "INFO: running Java 8; removing '--add-opens' option(s) from CMD (if present)..." 420 | # remove opens option 421 | NEW_CMD="${*}" 422 | NEW_CMD="${NEW_CMD/'--add-opens java.base/sun.security.x509=ALL-UNNAMED '/}" 423 | NEW_CMD="${NEW_CMD/'--add-opens java.base/sun.security.util=ALL-UNNAMED '/}" 424 | # shellcheck disable=SC2086 425 | set -- ${NEW_CMD} 426 | ;; 427 | esac 428 | 429 | # check for autobackup 430 | if [ ! -d "/opt/tplink/EAPController/data/autobackup" ] 431 | then 432 | echo 433 | echo "##############################################################################" 434 | echo "##############################################################################" 435 | echo "WARN: autobackup directory not found! Please configure automatic backups!" 436 | echo " For instructions, see https://github.com/mbentley/docker-omada-controller#controller-backups" 437 | echo "##############################################################################" 438 | echo "##############################################################################" 439 | echo 440 | sleep 2 441 | fi 442 | 443 | echo "INFO: Starting Omada Controller as user ${PUSERNAME}" 444 | 445 | # tail the omada logs if set to true 446 | if [ "${SHOW_SERVER_LOGS}" = "true" ] 447 | then 448 | gosu "${PUSERNAME}" tail -F -n 0 /opt/tplink/EAPController/logs/server.log & 449 | fi 450 | 451 | # tail the mongodb logs if set to true 452 | if [ "${SHOW_MONGODB_LOGS}" = "true" ] 453 | then 454 | gosu "${PUSERNAME}" tail -F -n 0 /opt/tplink/EAPController/logs/mongod.log & 455 | fi 456 | 457 | # run the actual command as the omada user 458 | exec gosu "${PUSERNAME}" "${@}" 459 | -------------------------------------------------------------------------------- /entrypoint-rootless.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # set environment variables 6 | export TZ 7 | TZ="${TZ:-Etc/UTC}" 8 | 9 | # PORTS CONFIGURATION 10 | MANAGE_HTTP_PORT="${MANAGE_HTTP_PORT:-8088}" 11 | MANAGE_HTTPS_PORT="${MANAGE_HTTPS_PORT:-8043}" 12 | PORTAL_HTTP_PORT="${PORTAL_HTTP_PORT:-8088}" 13 | PORTAL_HTTPS_PORT="${PORTAL_HTTPS_PORT:-8843}" 14 | PORT_ADOPT_V1="${PORT_ADOPT_V1:-29812}" 15 | PORT_APP_DISCOVERY="${PORT_APP_DISCOVERY:-27001}" 16 | PORT_UPGRADE_V1="${PORT_UPGRADE_V1:-29813}" 17 | PORT_MANAGER_V1="${PORT_MANAGER_V1:-29811}" 18 | PORT_MANAGER_V2="${PORT_MANAGER_V2:-29814}" 19 | PORT_DISCOVERY="${PORT_DISCOVERY:-29810}" 20 | PORT_TRANSFER_V2="${PORT_TRANSFER_V2:-29815}" 21 | PORT_RTTY="${PORT_RTTY:-29816}" 22 | # END PORTS CONFIGURATION 23 | 24 | # EXTERNAL MONGODB 25 | MONGO_EXTERNAL="${MONGO_EXTERNAL:-false}" 26 | EAP_MONGOD_URI="${EAP_MONGOD_URI:-mongodb://127.0.0.1:27217/omada}" 27 | # escape & for eval 28 | EAP_MONGOD_URI="$(eval echo "${EAP_MONGOD_URI//&/\\&}")" 29 | # escape after eval as well for sed 30 | EAP_MONGOD_URI="${EAP_MONGOD_URI//&/\\&}" 31 | # END EXTERNAL MONGODB 32 | 33 | SHOW_SERVER_LOGS="${SHOW_SERVER_LOGS:-true}" 34 | SHOW_MONGODB_LOGS="${SHOW_MONGODB_LOGS:-false}" 35 | SSL_CERT_NAME="${SSL_CERT_NAME:-tls.crt}" 36 | SSL_KEY_NAME="${SSL_KEY_NAME:-tls.key}" 37 | SKIP_USERLAND_KERNEL_CHECK="${SKIP_USERLAND_KERNEL_CHECK:-false}" 38 | 39 | # set USER_ID and GROUP_ID variables 40 | USER_ID="$(id -u)" 41 | GROUP_ID="$(id -g)" 42 | 43 | # make sure we aren't actually running as root 44 | if [ "${USER_ID}" = "0" ] || [ "${GROUP_ID}" = "0" ] 45 | then 46 | echo "ERROR: you're running as root (${USER_ID}:${GROUP_ID}); this defeats the purpose of running rootless!" 47 | exit 1 48 | else 49 | echo "INFO: running as ${USER_ID}:${GROUP_ID}" 50 | fi 51 | 52 | # make sure the directories are writable 53 | for DIR in /opt/tplink/EAPController/data /opt/tplink/EAPController/logs /opt/tplink/EAPController/properties /tmp 54 | do 55 | if [ ! -w "${DIR}" ] 56 | then 57 | # notify user that the directory is not writable 58 | echo "ERROR: ${DIR} is not writable!" 59 | exit 1 60 | fi 61 | done 62 | 63 | # check if properties file exists; create it if it is missing 64 | DEFAULT_FILES="/opt/tplink/EAPController/properties.defaults/*" 65 | for FILE in ${DEFAULT_FILES} 66 | do 67 | BASENAME=$(basename "${FILE}") 68 | if [ ! -f "/opt/tplink/EAPController/properties/${BASENAME}" ] 69 | then 70 | echo "INFO: Properties file '${BASENAME}' missing, restoring default file..." 71 | cp "${FILE}" "/opt/tplink/EAPController/properties/${BASENAME}" 72 | chown "${USER_ID}:${GROUP_ID}" "/opt/tplink/EAPController/properties/${BASENAME}" 73 | fi 74 | done 75 | 76 | # make sure that the html directory exists 77 | if [ ! -d "/opt/tplink/EAPController/data/html" ] && [ -f "/opt/tplink/EAPController/data-html.tar.gz" ] 78 | then 79 | # missing directory; extract from original 80 | echo "INFO: Report HTML directory missing; extracting backup to '/opt/tplink/EAPController/data/html'" 81 | tar zxvf /opt/tplink/EAPController/data-html.tar.gz -C /opt/tplink/EAPController/data 82 | chown -R "${USER_ID}:${GROUP_ID}" /opt/tplink/EAPController/data/html 83 | fi 84 | 85 | # make sure that the pdf directory exists 86 | if [ ! -d "/opt/tplink/EAPController/data/pdf" ] 87 | then 88 | # missing directory; extract from original 89 | echo "INFO: Report PDF directory missing; creating '/opt/tplink/EAPController/data/pdf'" 90 | mkdir /opt/tplink/EAPController/data/pdf 91 | chown -R "${USER_ID}:${GROUP_ID}" /opt/tplink/EAPController/data/pdf 92 | fi 93 | 94 | # check to see if there is a db directory; create it if it is missing 95 | if [ ! -d "/opt/tplink/EAPController/data/db" ] 96 | then 97 | echo "INFO: Database directory missing; creating '/opt/tplink/EAPController/data/db'" 98 | mkdir /opt/tplink/EAPController/data/db 99 | chown "${USER_ID}:${GROUP_ID}" /opt/tplink/EAPController/data/db 100 | echo "done" 101 | fi 102 | 103 | # set default time zone and notify user of time zone 104 | echo "INFO: Time zone set to '${TZ}'" 105 | 106 | # set values in omada.properties 107 | # update stored ports when different of enviroment defined ports (works for numbers only) 108 | for ELEM in MANAGE_HTTP_PORT MANAGE_HTTPS_PORT PORTAL_HTTP_PORT PORTAL_HTTPS_PORT PORT_ADOPT_V1 PORT_APP_DISCOVERY PORT_UPGRADE_V1 PORT_MANAGER_V1 PORT_MANAGER_V2 PORT_DISCOVERY PORT_TRANSFER_V2 PORT_RTTY 109 | do 110 | # convert element to key name 111 | KEY="$(echo "${ELEM}" | tr '[:upper:]' '[:lower:]' | tr '_' '.')" 112 | 113 | # get value we want to set from the element 114 | END_VAL=${!ELEM} 115 | 116 | # get the current value from the omada.properties file 117 | STORED_PROP_VAL=$(grep -Po "(?<=${KEY}=)([0-9]+)" /opt/tplink/EAPController/properties/omada.properties || true) 118 | 119 | # check to see if we need to set the value 120 | if [ "${STORED_PROP_VAL}" = "" ] 121 | then 122 | echo "INFO: Skipping '${KEY}' - not present in omada.properties" 123 | elif [ "${STORED_PROP_VAL}" != "${END_VAL}" ] 124 | then 125 | # check to see if we are trying to bind to privileged port 126 | if [ "${END_VAL}" -lt "1024" ] && [ "$(cat /proc/sys/net/ipv4/ip_unprivileged_port_start)" = "1024" ] 127 | then 128 | echo "ERROR: Unable to set '${KEY}' to ${END_VAL}; 'ip_unprivileged_port_start' has not been set. See https://github.com/mbentley/docker-omada-controller#unprivileged-ports" 129 | exit 1 130 | fi 131 | 132 | # update the key-value pair 133 | echo "INFO: Setting '${KEY}' to ${END_VAL} in omada.properties" 134 | sed -i "s~^${KEY}=${STORED_PROP_VAL}$~${KEY}=${END_VAL}~g" /opt/tplink/EAPController/properties/omada.properties 135 | else 136 | # values already match; nothing to change 137 | echo "INFO: Value of '${KEY}' already set to ${END_VAL} in omada.properties" 138 | fi 139 | done 140 | 141 | # update stored property values when different of environment defined values (works for any value) 142 | for ELEM in MONGO_EXTERNAL EAP_MONGOD_URI 143 | do 144 | # convert element to key name 145 | KEY="$(echo "${ELEM}" | tr '[:upper:]' '[:lower:]' | tr '_' '.')" 146 | 147 | # get the full key & value to store for checking later 148 | KEY_VALUE="$(grep "^${KEY}=" /opt/tplink/EAPController/properties/omada.properties || true)" 149 | 150 | # get value we want to set from the element 151 | END_VAL=${!ELEM} 152 | 153 | # get the current value from the omada.properties file 154 | STORED_PROP_VAL=$(grep -Po "(?<=${KEY}=)(.*)+" /opt/tplink/EAPController/properties/omada.properties || true) 155 | 156 | # check to see if we need to set the value; see if there is something in the key/value first 157 | if [ -z "${KEY_VALUE}" ] 158 | then 159 | echo "INFO: Skipping '${KEY}' - not present in omada.properties" 160 | elif [ "${STORED_PROP_VAL}" != "${END_VAL}" ] 161 | then 162 | # update the key-value pair 163 | echo "INFO: Setting '${KEY}' to ${END_VAL} in omada.properties" 164 | sed -i "s~^${KEY}=${STORED_PROP_VAL}$~${KEY}=${END_VAL}~g" /opt/tplink/EAPController/properties/omada.properties 165 | else 166 | # values already match; nothing to change 167 | echo "INFO: Value of '${KEY}' already set to ${END_VAL} in omada.properties" 168 | fi 169 | done 170 | 171 | # Import a cert from a possibly mounted secret or file at /cert 172 | if [ -f "/cert/${SSL_KEY_NAME}" ] && [ -f "/cert/${SSL_CERT_NAME}" ] 173 | then 174 | # see where the keystore directory is; check for old location first 175 | if [ -d /opt/tplink/EAPController/keystore ] 176 | then 177 | echo "ERROR: rootless isn't supported on versions < 5.3.1" 178 | exit 1 179 | else 180 | # keystore directory moved to the data directory in 5.3.1 181 | KEYSTORE_DIR="/opt/tplink/EAPController/data/keystore" 182 | 183 | # check to see if the KEYSTORE_DIR exists (it won't on upgrade) 184 | if [ ! -d "${KEYSTORE_DIR}" ] 185 | then 186 | echo "INFO: Creating keystore directory (${KEYSTORE_DIR})" 187 | mkdir "${KEYSTORE_DIR}" 188 | echo "INFO: Setting permissions on ${KEYSTORE_DIR}" 189 | chown "${USER_ID}:${GROUP_ID}" "${KEYSTORE_DIR}" 190 | fi 191 | fi 192 | 193 | echo "INFO: Importing cert from /cert/tls.[key|crt]" 194 | # delete the existing keystore 195 | rm -f "${KEYSTORE_DIR}/eap.keystore" 196 | 197 | # example certbot usage: ./certbot-auto certonly --standalone --preferred-challenges http -d mydomain.net 198 | openssl pkcs12 -export \ 199 | -inkey "/cert/${SSL_KEY_NAME}" \ 200 | -in "/cert/${SSL_CERT_NAME}" \ 201 | -certfile "/cert/${SSL_CERT_NAME}" \ 202 | -name eap \ 203 | -out "${KEYSTORE_DIR}/eap.keystore" \ 204 | -passout pass:tplink 205 | 206 | # set ownership/permission on keystore 207 | chown "${USER_ID}:${GROUP_ID}" "${KEYSTORE_DIR}/eap.keystore" 208 | chmod 400 "${KEYSTORE_DIR}/eap.keystore" 209 | fi 210 | 211 | # see if any of these files exist; if so, do not start as they are from older versions 212 | if [ -f /opt/tplink/EAPController/data/db/tpeap.0 ] || [ -f /opt/tplink/EAPController/data/db/tpeap.1 ] || [ -f /opt/tplink/EAPController/data/db/tpeap.ns ] 213 | then 214 | echo "ERROR: The data volume mounted to /opt/tplink/EAPController/data appears to have data from a previous version!" 215 | echo " Follow the upgrade instructions at https://github.com/mbentley/docker-omada-controller#upgrading-to-41" 216 | exit 1 217 | fi 218 | 219 | # check to see if the CMD passed contains the text "com.tplink.omada.start.OmadaLinuxMain" which is the old classpath from 4.x 220 | if [ "$(echo "${@}" | grep -q "com.tplink.omada.start.OmadaLinuxMain"; echo $?)" = "0" ] 221 | then 222 | echo -e "\n############################" 223 | echo "WARN: CMD from 4.x detected! It is likely that this container will fail to start properly with a \"Could not find or load main class com.tplink.omada.start.OmadaLinuxMain\" error!" 224 | echo " See the note on old CMDs at https://github.com/mbentley/docker-omada-controller/blob/master/KNOWN_ISSUES.md#upgrade-issues for details on why and how to resolve the issue." 225 | echo -e "############################\n" 226 | fi 227 | 228 | # compare version from the image to the version stored in the persistent data (last ran version) 229 | if [ -f "/opt/tplink/EAPController/IMAGE_OMADA_VER.txt" ] 230 | then 231 | # file found; read the version that is in the image 232 | IMAGE_OMADA_VER="$(cat /opt/tplink/EAPController/IMAGE_OMADA_VER.txt)" 233 | else 234 | echo "ERROR: Missing image version file (/opt/tplink/EAPController/IMAGE_OMADA_VER.txt); this should never happen!" 235 | exit 1 236 | fi 237 | 238 | # load LAST_RAN_OMADA_VER, if file present 239 | if [ -f "/opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt" ] 240 | then 241 | # file found; read the version that was last recorded 242 | LAST_RAN_OMADA_VER="$(cat /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt)" 243 | else 244 | # no file found; set version to 0.0.0 as we don't know the last version 245 | LAST_RAN_OMADA_VER="0.0.0" 246 | fi 247 | 248 | # make sure we are not trying to upgrade from 4.x to 5.14.32.x 249 | LAST_RAN_MAJOR_VER="$(echo "${LAST_RAN_OMADA_VER}" | awk -F '.' '{print $1}')" 250 | IMAGE_MAJOR_VER="$(echo "${IMAGE_OMADA_VER}" | awk -F '.' '{print $1}')" 251 | IMAGE_MINOR_VER="$(echo "${IMAGE_OMADA_VER}" | awk -F '.' '{print $2}')" 252 | 253 | # make sure we are not trying to upgrade from 4.x to 5.14.32.x or greater 254 | if [ "${LAST_RAN_MAJOR_VER}" = "4" ] && [ "${IMAGE_MAJOR_VER}" -ge "5" ] 255 | then 256 | # check to see if we are runnning 5.14 or greater 257 | if [ "${IMAGE_MAJOR_VER}" = "5" ] && [ "${IMAGE_MINOR_VER}" -ge "14" ] || [ "${IMAGE_MAJOR_VER}" -gt "5" ] 258 | then 259 | echo "ERROR: You are attempting to upgrade from 4.x to 5.14.x or greater; the upgrade code was removed in 5.14.x!" 260 | echo " See https://github.com/mbentley/docker-omada-controller/blob/master/README_v3_and_v4.md#upgrade-path for the upgrade path from 4.x to 5.x" 261 | exit 1 262 | fi 263 | fi 264 | 265 | # use sort to check which version is newer; should sort the newest version to the top 266 | if [ "$(printf '%s\n' "${IMAGE_OMADA_VER}" "${LAST_RAN_OMADA_VER}" | sort -rV | head -n1)" != "${IMAGE_OMADA_VER}" ] 267 | then 268 | # version in the image is didn't match newest image version; this means we are trying to start and older version 269 | echo "ERROR: The version from the image (${IMAGE_OMADA_VER}) is older than the last version executed (${LAST_RAN_OMADA_VER})! Refusing to start to prevent data loss!" 270 | echo " To bypass this check, remove /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt only if you REALLY know what you're doing!" 271 | exit 1 272 | else 273 | echo "INFO: Version check passed; image version (${IMAGE_OMADA_VER}) >= the last version ran (${LAST_RAN_OMADA_VER}); writing image version to last ran file..." 274 | echo "${IMAGE_OMADA_VER}" > /opt/tplink/EAPController/data/LAST_RAN_OMADA_VER.txt 275 | fi 276 | 277 | # check to see if we are in a bad situation with a 32 bit userland and 64 bit kernel (fails to start MongoDB on a Raspberry Pi) 278 | if [ "$(dpkg --print-architecture)" = "armhf" ] && [ "$(uname -m)" = "aarch64" ] && [ "${SKIP_USERLAND_KERNEL_CHECK}" = "false" ] 279 | then 280 | echo "##############################################################################" 281 | echo "##############################################################################" 282 | echo "ERROR: 32 bit userspace with 64 bit kernel detected! MongoDB will NOT start!" 283 | echo " See https://github.com/mbentley/docker-omada-controller/blob/master/KNOWN_ISSUES.md#mismatched-userland-and-kernel for how to fix the issue" 284 | echo "##############################################################################" 285 | echo "##############################################################################" 286 | 287 | exit 1 288 | else 289 | echo "INFO: userland/kernel check passed" 290 | fi 291 | 292 | # show java version 293 | echo -e "INFO: output of 'java -version':\n$(java -version 2>&1)\n" 294 | 295 | # get the java version in different formats 296 | JAVA_VERSION="$(java -version 2>&1 | head -n 1 | awk -F '"' '{print $2}')" 297 | JAVA_VERSION_1="$(echo "${JAVA_VERSION}" | awk -F '.' '{print $1}')" 298 | JAVA_VERSION_2="$(echo "${JAVA_VERSION}" | awk -F '.' '{print $2}')" 299 | 300 | # for java 8, remove the opens argument from the CMD 301 | case ${JAVA_VERSION_1}.${JAVA_VERSION_2} in 302 | 1.8) 303 | echo "INFO: running Java 8; removing '--add-opens' option(s) from CMD (if present)..." 304 | # remove opens option 305 | NEW_CMD="${*}" 306 | NEW_CMD="${NEW_CMD/'--add-opens java.base/sun.security.x509=ALL-UNNAMED '/}" 307 | NEW_CMD="${NEW_CMD/'--add-opens java.base/sun.security.util=ALL-UNNAMED '/}" 308 | # shellcheck disable=SC2086 309 | set -- ${NEW_CMD} 310 | ;; 311 | esac 312 | 313 | # check for autobackup 314 | if [ ! -d "/opt/tplink/EAPController/data/autobackup" ] 315 | then 316 | echo 317 | echo "##############################################################################" 318 | echo "##############################################################################" 319 | echo "WARN: autobackup directory not found! Please configure automatic backups!" 320 | echo " For instructions, see https://github.com/mbentley/docker-omada-controller#controller-backups" 321 | echo "##############################################################################" 322 | echo "##############################################################################" 323 | echo 324 | sleep 2 325 | fi 326 | 327 | echo "INFO: Starting Omada Controller..." 328 | 329 | # tail the omada logs if set to true 330 | if [ "${SHOW_SERVER_LOGS}" = "true" ] 331 | then 332 | tail -F -n 0 /opt/tplink/EAPController/logs/server.log & 333 | fi 334 | 335 | # tail the mongodb logs if set to true 336 | if [ "${SHOW_MONGODB_LOGS}" = "true" ] 337 | then 338 | tail -F -n 0 /opt/tplink/EAPController/logs/mongod.log & 339 | fi 340 | 341 | # run the actual command 342 | exec "${@}" 343 | -------------------------------------------------------------------------------- /external_mongodb/README.md: -------------------------------------------------------------------------------- 1 | # Notes for External MongoDB (Experimental) 2 | 3 | Note: This is still experiemental. If you move to an external MongoDB, you're on your own in terms of getting help. These notes below are just my notes from when I was proving this out, not a production ready setup. They include standing up a new MongoDB + Controller and test steps for a migration from the all in one to separate containers. Again, you're on your own. 4 | 5 | * [Common Steps](#common-steps) 6 | * [MongoDB + Omada Controller (fresh install)](#mongodb--omada-controller-fresh-install) 7 | * [Migration from All in One](#migration-from-all-in-one) 8 | 9 | ## Common Steps 10 | 11 | These steps are needed for either scenario you want to test. 12 | 13 | 1. (Optional) Build the Docker Image 14 | 15 | As of 3/19/2024, a multi-arch test image is available on Docker Hub as `mbentley/omada-controller:5.13-external-mongo-test` for `amd64`, `arm64`, and `armv7l` but you can build them yourself: 16 | 17 | ```bash 18 | # amd64 19 | docker build \ 20 | --pull \ 21 | --build-arg NO_MONGODB=true \ 22 | --build-arg ARCH="amd64" \ 23 | --platform linux/amd64 \ 24 | --progress plain \ 25 | -f Dockerfile.v5.x \ 26 | -t mbentley/omada-controller:5.13-external-mongo-test-amd64 \ 27 | -t mbentley/omada-controller:5.13-external-mongo-test . 28 | 29 | # arm64 30 | docker build \ 31 | --pull \ 32 | --build-arg NO_MONGODB=true \ 33 | --build-arg ARCH="arm64" \ 34 | --platform linux/arm64 \ 35 | --progress plain \ 36 | -f Dockerfile.v5.x \ 37 | -t mbentley/omada-controller:5.13-external-mongo-test-arm64 \ 38 | -t mbentley/omada-controller:5.13-external-mongo-test . 39 | 40 | # armv7l 41 | docker build \ 42 | --pull \ 43 | --build-arg NO_MONGODB=true \ 44 | --build-arg ARCH="armv7l" \ 45 | --platform linux/arm/v7 \ 46 | --progress plain \ 47 | -f Dockerfile.v5.x \ 48 | -t mbentley/omada-controller:5.13-external-mongo-test-armv7l \ 49 | -t mbentley/omada-controller:5.13-external-mongo-test . 50 | ``` 51 | 52 | 1. Create a Docker `bridge` Network 53 | 54 | Creating and using a custom bridge network allows for container to container comunication: 55 | 56 | ```bash 57 | docker network create -d bridge omada 58 | ``` 59 | 60 | ## MongoDB + Omada Controller (fresh install) 61 | 62 | This expects that you are in this project's root where the `Dockerfile` is. Update the path for the MongoDB `/docker-entrypoint-initdb.d` bind mount if you want/need to but these commands should all work from there. 63 | 64 | 1. Start MongoDB 65 | 66 | As far as I can tell, using MongoDB 7 works fine for the controller. I have yet to test it extensively though, just gone through basic setup. The [installation documentation](https://www.tp-link.com/us/support/faq/3272/) says that you should run MongoDB 3 or 4 though. 67 | 68 | The `omada` user in MongoDB will have the following credentials: user: `omada` & pwd: `0m4d4`. This is defined in the `omada.js` file that it used to initialize the databases and you can modify if as you wish. 69 | 70 | ```bash 71 | docker run -d \ 72 | --name mongodb \ 73 | --network omada \ 74 | -p 27017:27017 \ 75 | -e MONGO_INITDB_ROOT_USERNAME="admin" \ 76 | -e MONGO_INITDB_ROOT_PASSWORD="password" \ 77 | -e MONGO_INITDB_DATABASE="omada" \ 78 | --mount type=volume,source=omada-mongo-config,destination=/data/configdb \ 79 | --mount type=volume,source=omada-mongo-data,destination=/data/db \ 80 | --mount type=bind,source="${PWD}/external_mongodb",destination=/docker-entrypoint-initdb.d \ 81 | mongo:4 82 | ``` 83 | 84 | 1. Start the Omada Controller 85 | 86 | This is a basic run command, taking most of the default env vars. Assuming you use the bridge network, the containers will use the custom `omada` Docker bridge network for container to container communication. 87 | 88 | ```bash 89 | docker run -d \ 90 | --name omada-controller \ 91 | --ulimit nofile=4096:8192 \ 92 | --network omada \ 93 | -p 8088:8088 \ 94 | -p 8043:8043 \ 95 | -p 8843:8843 \ 96 | -p 27001:27001/udp \ 97 | -p 29810:29810/udp \ 98 | -p 29811-29816:29811-29816 \ 99 | --mount type=volume,source=omada-data,destination=/opt/tplink/EAPController/data \ 100 | --mount type=volume,source=omada-logs,destination=/opt/tplink/EAPController/logs \ 101 | -e MONGO_EXTERNAL="true" \ 102 | -e EAP_MONGOD_URI="mongodb://omada:0m4d4@mongodb.omada:27017/omada" \ 103 | mbentley/omada-controller:5.13-external-mongo-test &&\ 104 | docker logs -f omada-controller 105 | ``` 106 | 107 | 1. Cleanup After Testing 108 | 109 | If you want to clean everything up, this command will kill the containers, remove the volumes, and remove the bridge network: 110 | 111 | ```bash 112 | docker rm -f mongodb omada-controller ;\ 113 | docker volume rm omada-mongo-config omada-mongo-data omada-data omada-logs ;\ 114 | docker network rm omada 115 | ``` 116 | 117 | ## Migration from All in One 118 | 119 | While I have this WIP for migrating from all in one, it would be much simplier to take a backup from the Omada Controller and then do a restore of the config to a new controller install with a modern MongoDB version as the migration from version to version is very tedious. 120 | 121 | 1. Run standard all in one container (mongodb + controller) 122 | 123 | ```bash 124 | docker run -d \ 125 | --name omada-controller \ 126 | --ulimit nofile=4096:8192 \ 127 | --network omada \ 128 | -p 8088:8088 \ 129 | -p 8043:8043 \ 130 | -p 8843:8843 \ 131 | -p 27001:27001/udp \ 132 | -p 29810:29810/udp \ 133 | -p 29811-29816:29811-29816 \ 134 | --mount type=volume,source=omada-data,destination=/opt/tplink/EAPController/data \ 135 | --mount type=volume,source=omada-logs,destination=/opt/tplink/EAPController/logs \ 136 | mbentley/omada-controller:5.13-external-mongo-test &&\ 137 | docker logs -f omada-controller 138 | ``` 139 | 140 | 1. Stop & remove it 141 | 142 | ```bash 143 | docker stop -t 60 omada-controller &&\ 144 | docker rm omada-controller 145 | ``` 146 | 147 | 1. chown db files to prepare for the mongodb image 148 | 149 | ```bash 150 | docker run -it --rm \ 151 | --mount type=volume,source=omada-data,destination=/opt/tplink/EAPController/data \ 152 | alpine chown -R 999:999 /opt/tplink/EAPController/data/db 153 | ``` 154 | 155 | 1. Start mongodb, attached to the same data from the all in one image (updating the dbpath) 156 | 157 | Note: this uses `mongo:3` because you otherwise have to perform an upgrade which is currently outside of the scope of this test. 158 | 159 | ```bash 160 | docker run -d \ 161 | --name mongodb \ 162 | --network omada \ 163 | -p 27017:27017 \ 164 | --mount type=volume,source=omada-data,destination=/opt/tplink/EAPController/data \ 165 | mongo:3 --dbpath /opt/tplink/EAPController/data/db 166 | ``` 167 | 168 | 1. Start the controller 169 | 170 | ```bash 171 | docker run -d \ 172 | --name omada-controller \ 173 | --ulimit nofile=4096:8192 \ 174 | --network omada \ 175 | -p 8088:8088 \ 176 | -p 8043:8043 \ 177 | -p 8843:8843 \ 178 | -p 27001:27001/udp \ 179 | -p 29810:29810/udp \ 180 | -p 29811-29816:29811-29816 \ 181 | --mount type=volume,source=omada-data,destination=/opt/tplink/EAPController/data \ 182 | --mount type=volume,source=omada-logs,destination=/opt/tplink/EAPController/logs \ 183 | -e MONGO_EXTERNAL="true" \ 184 | -e EAP_MONGOD_URI="mongodb://mongodb.omada:27017/omada" \ 185 | mbentley/omada-controller:5.13-external-mongo-test &&\ 186 | docker logs -f omada-controller 187 | ``` 188 | 189 | 1. Cleanup After Testing 190 | 191 | If you want to clean everything up, this command will kill the containers, remove the volumes, and remove the bridge network: 192 | 193 | ```bash 194 | docker rm -f mongodb omada-controller ;\ 195 | docker volume prune -f ;\ 196 | docker volume rm omada-data omada-logs ;\ 197 | docker network rm omada 198 | ``` 199 | 200 | ## Kubernetes Deployment Guide 201 | 202 | In advanced setups, deploying applications in container orchestrators like Kubernetes is common, 203 | even in homelabs to enhance reliability. 204 | 205 | Below, we’ll use both Helm and Kustomize to deploy **MongoDB** and **Omada Controller**. 206 | 207 | ### Deploy MongoDB 208 | 209 | 210 | We use a custom Helm chart that wraps Bitnami's MongoDB chart. 211 | 212 | The customization includes templates for managing secrets securely, avoiding the bad practice of 213 | hardcoding credentials in `values.yaml`. 214 | 215 | Instead, it supports tools like **External Secrets** to fetch credentials from secure vaults and 216 | generate Kubernetes secrets automatically. 217 | 218 | The custom Helm chart has credentials hardcoded as an example, but provides commented examples 219 | about how to get secrets safely from mentioned vaults. 220 | 221 | Let's deploy our chart: 222 | 223 | 1. Update dependencies 224 | 225 | ```console 226 | helm dependency update kubernetes/mongodb 227 | ``` 228 | 229 | 2. Deploy MongoDB in the cluster currently pointed by your Kubeconfig 230 | 231 | > [!IMPORTANT] 232 | > Customize chart's parameters to meet your needs 233 | 234 | ```console 235 | helm upgrade --install mongodb kubernetes/mongodb \ 236 | -f kubernetes/mongodb/values-customized.yaml \ 237 | -n omada-controller --create-namespace 238 | ``` 239 | 240 | ### Deploy Omada Controller 241 | 242 | We'll use Kustomize since there's no official Helm chart provided by Omada Controller's maintainers 243 | or a trusted external provider like Bitnami. 244 | 245 | Ensure your cluster has Ingress-Nginx as the ingress controller and Cert-Manager for certificate management. 246 | 247 | If you're in an on-premises environment, you might need tools like MetalLB or Kube-VIP to provision 248 | load balancers for services of type LoadBalancer. 249 | 250 | To deploy Omada Controller, just execute the following command 251 | 252 | ```console 253 | kubectl apply -k kubernetes/production 254 | ``` 255 | 256 | > [!IMPORTANT] 257 | > Always adjust parameters to align with your infrastructure and requirements. -------------------------------------------------------------------------------- /external_mongodb/kubernetes/mongodb/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: mongodb 3 | version: 0.1.0 4 | dependencies: 5 | - name: mongodb 6 | version: 14.13.0 7 | repository: https://charts.bitnami.com/bitnami 8 | -------------------------------------------------------------------------------- /external_mongodb/kubernetes/mongodb/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "meta-mongodb.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "meta-mongodb.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "meta-mongodb.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "meta-mongodb.labels" -}} 37 | helm.sh/chart: {{ include "meta-mongodb.chart" . }} 38 | {{ include "meta-mongodb.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "meta-mongodb.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "meta-mongodb.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | -------------------------------------------------------------------------------- /external_mongodb/kubernetes/mongodb/templates/external-secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- range $key, $value := .Values.customComponents.externalSecrets }} 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: {{ include "meta-mongodb.fullname" $ }}-{{ $key }} 6 | labels: 7 | {{- include "meta-mongodb.labels" $ | nindent 4 }} 8 | {{- with $value.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | {{ toYaml $value.spec | nindent 2 }} 14 | --- 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /external_mongodb/kubernetes/mongodb/values-customized.yaml: -------------------------------------------------------------------------------- 1 | customComponents: {} 2 | 3 | # externalSecrets: 4 | # mongodb-users-credentials: 5 | # annotations: {} 6 | # spec: 7 | # secretStoreRef: 8 | # kind: ClusterSecretStore 9 | # name: gitlab-secret-store 10 | # target: 11 | # name: mongodb-users-credentials 12 | # data: 13 | # - secretKey: mongodb-root-password 14 | # remoteRef: 15 | # key: MONGODB_USERS_CREDENTIALS_PASSWORD_ROOT 16 | # - secretKey: mongodb-passwords 17 | # remoteRef: 18 | # key: MONGODB_USERS_CREDENTIALS_PASSWORD_OMADA 19 | 20 | # Ref: https://github.com/bitnami/charts/blob/main/bitnami/mongodb/values.yaml 21 | mongodb: 22 | # MongoDB Authentication parameters 23 | auth: 24 | enabled: true 25 | 26 | # MongoDB root user 27 | #rootUser: root 28 | 29 | # MongoDB root password 30 | # Ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#setting-the-root-user-and-password-on-first-run 31 | rootPassword: "provision-me-externally" 32 | 33 | # MongoDB custom users and databases 34 | # Ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#creating-a-user-and-database-on-first-run 35 | # List of custom users to be created during the initialization 36 | # List of passwords for the custom users set at `auth.usernames` 37 | # List of custom databases to be created during the initialization 38 | # Ref: https://github.com/bitnami/charts/issues/16975#issuecomment-1803017023 39 | # Relationship between following lists is [0]->[0]->[0]; [1]->[1]->[1]; ... 40 | databases: ["omada"] 41 | usernames: ["omada"] 42 | passwords: ["provision-me-externally"] 43 | 44 | # Existing secret with MongoDB credentials (keys: `mongodb-passwords`, `mongodb-root-password`, `mongodb-metrics-password`, `mongodb-replica-set-key`) 45 | # When it's set the passwords defined in previous parameters are ignored. 46 | #existingSecret: "mongodb-users-credentials" 47 | 48 | # Dictionary of initdb scripts 49 | # Specify dictionary of scripts to be run at first boot 50 | initdbScripts: 51 | 52 | # Ref: https://github.com/mbentley/docker-omada-controller/blob/master/external_mongodb/omada.js 53 | init-mongo.sh: | 54 | #!/bin/bash 55 | 56 | mongosh --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD <&1; exit 1; } 62 | 63 | echo "**** Selecting packages based on the architecture and version ****" 64 | # common package dependencies 65 | PKGS=( 66 | gosu 67 | net-tools 68 | tzdata 69 | wget 70 | ) 71 | 72 | # add specific package for mongodb 73 | case "${NO_MONGODB}" in 74 | true) 75 | # do not include mongodb 76 | ;; 77 | *) 78 | # include mongodb 79 | case "${ARCH}" in 80 | amd64|arm64|"") 81 | PKGS+=( mongodb-server-core ) 82 | ;; 83 | armv7l) 84 | PKGS+=( mongodb ) 85 | ;; 86 | *) 87 | die "${ARCH}: unsupported ARCH" 88 | ;; 89 | esac 90 | ;; 91 | esac 92 | 93 | # add specific package for openjdk 94 | case "${ARCH}:${NO_MONGODB}" in 95 | amd64:*|arm64:*|armv7l:true|"":*) 96 | # use openjdk-17 for v5.4 and above; all others use openjdk-8 97 | case "${OMADA_MAJOR_VER}" in 98 | 5) 99 | # pick specific package based on the major.minor version 100 | case "${OMADA_MAJOR_MINOR_VER}" in 101 | 5.0|5.1|5.3) 102 | # 5.0 to 5.3 all use openjdk-8 103 | PKGS+=( openjdk-8-jre-headless ) 104 | ;; 105 | *) 106 | # starting with 5.4, OpenJDK 17 is supported; we will use OpenJ9 if present or OpenJDK 17 if not 107 | if [ "$(. /opt/java/openjdk/release >/dev/null 2>&1; echo "${JVM_VARIANT}")" = "Openj9" ] 108 | then 109 | # we found OpenJ9; assume we want to use that 110 | echo "INFO: OpenJ9 was found; using that instead of OpenJDK 17!" 111 | else 112 | # OpenJ9 not found; assume we need to use OpenJDK 17 113 | echo "INFO: OpenJ9 was NOT found; using adding OpenJDK 17 to the list of packages to install" 114 | PKGS+=( openjdk-17-jre-headless ) 115 | fi 116 | ;; 117 | esac 118 | ;; 119 | *) 120 | # all other versions, use openjdk-8 121 | PKGS+=( openjdk-8-jre-headless ) 122 | ;; 123 | esac 124 | ;; 125 | armv7l:false) 126 | # always use openjdk-8 for armv7l 127 | PKGS+=( openjdk-8-jre-headless ) 128 | ;; 129 | *) 130 | die "${ARCH}: unsupported ARCH" 131 | ;; 132 | esac 133 | 134 | # output variables/selections 135 | echo "ARCH=\"${ARCH}\"" 136 | echo "OMADA_URL=\"${OMADA_URL}\"" 137 | echo "OMADA_TAR=\"${OMADA_TAR}\"" 138 | echo "OMADA_VER=\"${OMADA_VER}\"" 139 | echo "OMADA_MAJOR_VER=\"${OMADA_MAJOR_VER}\"" 140 | echo "OMADA_MAJOR_MINOR_VER=\"${OMADA_MAJOR_MINOR_VER}\"" 141 | echo "PKGS=( ${PKGS[*]} )" 142 | 143 | echo "**** Install Dependencies ****" 144 | apt-get install --no-install-recommends -y "${PKGS[@]}" 145 | 146 | echo "**** Download Omada Controller ****" 147 | cd /tmp 148 | wget -nv "${OMADA_URL}" 149 | 150 | echo "**** Extract and Install Omada Controller ****" 151 | 152 | # the beta versions are absolutely horrific in the file naming scheme - this mess tries to address and fix that bullshit 153 | if [[ "${INSTALL_VER}" =~ ^beta.* ]] 154 | then 155 | # get the extension to determine what to do with it 156 | case "${OMADA_URL##*.}" in 157 | zip) 158 | # this beta version is a tar.gz inside of a zip so let's pre-unzip it 159 | echo "INFO: this beta version is a zip file; unzipping..." 160 | # unzip the file 161 | unzip "${OMADA_TAR}" 162 | rm -f "${OMADA_TAR}" 163 | 164 | # whoever packages the beta up sucks at understanding file extensions 165 | FILENAME_CHECK="$(find . -name "*tar.gz*" | grep -v "zip" | sed 's|^./||')" 166 | 167 | # expect .tar.gz as the extension 168 | case "${FILENAME_CHECK}" in 169 | *.tar.gz) 170 | echo "INFO: filename extension for (${FILENAME_CHECK}) is '.tar.gz'; it's fine as is" 171 | ;; 172 | *_tar.gz.gz) 173 | echo "INFO: filename extension for (${FILENAME_CHECK}) is '_tar.gz.gz'; let's rename it to something sane" 174 | mv -v "${FILENAME_CHECK}" "${FILENAME_CHECK/_tar.gz.gz/.tar.gz}" 175 | ;; 176 | *tar.gz.gz) 177 | echo "INFO: filename extension for (${FILENAME_CHECK}) is 'tar.gz.gz'; let's rename it to something sane" 178 | mv -v "${FILENAME_CHECK}" "${FILENAME_CHECK/tar.gz.gz/.tar.gz}" 179 | ;; 180 | *) 181 | echo "WARN: the filename extension for (${FILENAME_CHECK}) is nothing that is expected; don't be surprised if one of the next steps fail!" 182 | esac 183 | 184 | # let's figure out where the tar.gz file is 185 | if [ -n "$(find . -name "*.tar.gz" -maxdepth 1 | sed 's|^./||')" ] 186 | then 187 | # it's in the current directory; just output message 188 | echo "INFO: .tar.gz is in the current directory, nothing to move" 189 | elif [ -n "$(find . -name "*.tar.gz" | sed 's|^./||')" ] 190 | then 191 | # it's in a subdirectory, move it to the current directory 192 | mv -v "$(find . -name "*.tar.gz" | sed 's|^./||')" . 193 | 194 | # cleanup directories 195 | # shellcheck disable=SC2044 196 | for DIR in $(find ./* -type d) 197 | do 198 | # cd to dir, find and delete any files; return 199 | cd "${DIR}" 200 | find . -type f -delete 201 | cd - 202 | done 203 | 204 | find ./* -type d -delete 205 | else 206 | echo "ERROR: unable to find a .tar.gz file!" 207 | exit 1 208 | fi 209 | 210 | # it's in the current directory; let's get the tar name 211 | OMADA_TAR="$(ls -- *.tar.gz)" 212 | ;; 213 | gz) 214 | # check to see if this is a tar.gz or just a gz 215 | if ls -- *.tar.gz >/dev/null 2>&1 216 | then 217 | # this is a .tar.gz 218 | echo "INFO: OMADA_TAR is a .tar.gz; we can handle it normally!" 219 | else 220 | # this beta version might be a tar.gz inside of a gzipped file so let's pre-gunzip it 221 | echo "INFO: this beta version is a .gz file; gunzipping..." 222 | # gunzip the file 223 | gunzip "${OMADA_TAR}" 224 | 225 | # now that we have unzipped, let's get the tar name 226 | OMADA_TAR="$(ls -- *.tar.gz*)" 227 | fi 228 | ;; 229 | *) 230 | echo "ERROR: unknown file extension, exiting!" 231 | exit 1 232 | ;; 233 | esac 234 | fi 235 | 236 | echo "${OMADA_TAR}" 237 | ls -l "${OMADA_TAR}" 238 | tar xvf "${OMADA_TAR}" 239 | rm -f "${OMADA_TAR}" 240 | cd Omada_SDN_Controller_* 241 | 242 | # make sure tha the install directory exists 243 | mkdir "${OMADA_DIR}" -vp 244 | 245 | # starting with 5.0.x, the installation has no webapps directory; these values are pulled from the install.sh 246 | case "${OMADA_MAJOR_VER}" in 247 | 5) 248 | # see if we are running 5.3.x or greater by checking the minor version 249 | if [ "${OMADA_MAJOR_MINOR_VER#*.}" -ge 3 ] 250 | then 251 | # 5.3.1 and above moved the keystore directory to be a subdir of data 252 | NAMES=( bin data lib properties install.sh uninstall.sh ) 253 | else 254 | # is less than 5.3 255 | NAMES=( bin data properties keystore lib install.sh uninstall.sh ) 256 | fi 257 | ;; 258 | *) 259 | # isn't v5.x 260 | NAMES=( bin data properties keystore lib webapps install.sh uninstall.sh ) 261 | ;; 262 | esac 263 | 264 | # copy over the files to the destination 265 | for NAME in "${NAMES[@]}" 266 | do 267 | cp "${NAME}" "${OMADA_DIR}" -r 268 | done 269 | 270 | # only add standlone options for controller version 5.x and above 271 | case "${OMADA_MAJOR_VER}" in 272 | 5) 273 | # add additional properties to the properties file 274 | { \ 275 | echo "" ;\ 276 | echo "" ;\ 277 | echo "# external mongodb" ;\ 278 | echo "mongo.external=false" ;\ 279 | echo "eap.mongod.uri=mongodb://127.0.0.1:27217/omada" ;\ 280 | } >> /opt/tplink/EAPController/properties/omada.properties 281 | ;; 282 | esac 283 | 284 | # copy omada default properties for can be used when properties is mounted as volume 285 | cp -r /opt/tplink/EAPController/properties/ "${OMADA_DIR}/properties.defaults" 286 | 287 | # symlink for mongod, if applicable 288 | case "${NO_MONGODB}" in 289 | true) 290 | # do not include mongodb 291 | ;; 292 | *) 293 | # include mongodb 294 | ln -sf "$(command -v mongod)" "${OMADA_DIR}/bin/mongod" 295 | chmod 755 "${OMADA_DIR}"/bin/* 296 | ;; 297 | esac 298 | 299 | # starting with 5.0.x, the work directory is no longer needed 300 | case "${OMADA_MAJOR_VER}" in 301 | 5) 302 | # create logs directory 303 | mkdir "${OMADA_DIR}/logs" 304 | ;; 305 | *) 306 | # create logs and work directories 307 | mkdir "${OMADA_DIR}/logs" "${OMADA_DIR}/work" 308 | ;; 309 | esac 310 | 311 | # for v5.1 & above, create backup of data/html directory in case it is missing (to be extracted at runtime) 312 | if [ -d /opt/tplink/EAPController/data/html ] 313 | then 314 | # create backup 315 | cd /opt/tplink/EAPController/data 316 | tar zcvf ../data-html.tar.gz html 317 | fi 318 | 319 | echo "Setting permissions to 777 for the properties directory (required for rootless to function)" 320 | chmod -R 777 /opt/tplink/EAPController/properties 321 | 322 | echo "**** Cleanup ****" 323 | rm -rf /tmp/* /var/lib/apt/lists/* 324 | 325 | # write installed version to a file 326 | echo "${OMADA_VER}" > "${OMADA_DIR}/IMAGE_OMADA_VER.txt" 327 | -------------------------------------------------------------------------------- /k8s/deployment.yaml: -------------------------------------------------------------------------------- 1 | # this example runs in a rootless configuration 2 | 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: omada-controller 7 | spec: 8 | replicas: 1 9 | strategy: 10 | type: Recreate 11 | selector: 12 | matchLabels: 13 | app: omada-controller 14 | template: 15 | metadata: 16 | labels: 17 | app: omada-controller 18 | spec: 19 | securityContext: 20 | runAsUser: 508 21 | runAsGroup: 508 22 | runAsNonRoot: true 23 | fsGroup: 508 24 | fsGroupChangePolicy: "OnRootMismatch" 25 | seccompProfile: 26 | type: RuntimeDefault 27 | containers: 28 | - name: omada-controller 29 | image: mbentley/omada-controller:5.15 30 | imagePullPolicy: Always 31 | securityContext: 32 | allowPrivilegeEscalation: false 33 | capabilities: 34 | drop: 35 | - ALL 36 | env: 37 | - name: ROOTLESS 38 | value: "true" 39 | - name: MANAGE_HTTP_PORT 40 | value: "8088" 41 | - name: MANAGE_HTTPS_PORT 42 | value: "8043" 43 | - name: PORTAL_HTTP_PORT 44 | value: "8088" 45 | - name: PORTAL_HTTPS_PORT 46 | value: "8843" 47 | - name: PORT_APP_DISCOVERY 48 | value: "27001" 49 | - name: PORT_ADOPT_V1 50 | value: "29812" 51 | - name: PORT_UPGRADE_V1 52 | value: "29813" 53 | - name: PORT_MANAGER_V1 54 | value: "29811" 55 | - name: PORT_MANAGER_V2 56 | value: "29814" 57 | - name: PORT_DISCOVERY 58 | value: "29810" 59 | - name: PORT_TRANSFER_V2 60 | value: "29815" 61 | - name: PORT_RTTY 62 | value: "29816" 63 | - name: SHOW_SERVER_LOGS 64 | value: "true" 65 | - name: SHOW_MONGODB_LOGS 66 | value: "false" 67 | - name: SSL_CERT_NAME 68 | value: tls.crt 69 | - name: SSL_KEY_NAME 70 | value: tls.key 71 | - name: TZ 72 | value: Etc/UTC 73 | - name: SKIP_USERMOD 74 | value: "true" 75 | volumeMounts: 76 | - name: omada-data 77 | mountPath: /opt/tplink/EAPController/data 78 | - name: omada-logs 79 | mountPath: /opt/tplink/EAPController/logs 80 | volumes: 81 | - name: omada-data 82 | persistentVolumeClaim: 83 | claimName: omada-data-pvc 84 | - name: omada-logs 85 | persistentVolumeClaim: 86 | claimName: omada-logs-pvc 87 | restartPolicy: Always 88 | -------------------------------------------------------------------------------- /k8s/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: omada-data-pvc 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 1Gi 11 | --- 12 | apiVersion: v1 13 | kind: PersistentVolumeClaim 14 | metadata: 15 | name: omada-logs-pvc 16 | spec: 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | -------------------------------------------------------------------------------- /k8s/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: omada-svc 5 | spec: 6 | type: LoadBalancer 7 | selector: 8 | app: omada-controller 9 | ports: 10 | - name: manage-http 11 | port: 8088 12 | targetPort: 8088 13 | protocol: TCP 14 | - name: manage-https 15 | port: 8043 16 | targetPort: 8043 17 | protocol: TCP 18 | - name: portal-https 19 | port: 8843 20 | targetPort: 8843 21 | protocol: TCP 22 | - name: app-discovery 23 | port: 27001 24 | targetPort: 27001 25 | protocol: UDP 26 | - name: adopt-v1 27 | port: 29812 28 | targetPort: 29812 29 | protocol: TCP 30 | - name: upgrade-v1 31 | port: 29813 32 | targetPort: 29813 33 | protocol: TCP 34 | - name: manager-v1 35 | port: 29811 36 | targetPort: 29811 37 | protocol: TCP 38 | - name: manager-v2 39 | port: 29814 40 | targetPort: 29814 41 | protocol: TCP 42 | - name: udp-discovery 43 | port: 29810 44 | targetPort: 29810 45 | protocol: UDP 46 | - name: udp-management 47 | protocol: UDP 48 | port: 19810 49 | targetPort: 19810 50 | - name: transfer-v2 51 | port: 29815 52 | targetPort: 29815 53 | protocol: TCP 54 | - name: rtty 55 | port: 29816 56 | targetPort: 29816 57 | protocol: TCP 58 | --------------------------------------------------------------------------------