appium-docker-android: running Appium against real phones from a container
Appium Server setup to automate android testing on real devices
At a glance
- What is it?
- The Appium Docker for Android project packages the Appium server and its Android tooling into an image so that UI tests can drive physical devices over USB instead of an emulator, removing the manual environment setup that is slow and error prone. The device plumbing is the interesting part, since the container needs privileged USB access, a shared Android authorisation key, or a network device list, and each of those has a different security profile.
- Who is it for?
- appium-docker-android suits mobile teams running Appium against physical hardware in continuous integration, where every build agent would otherwise repeat the same driver installation and authorisation dance. It is the wrong tool if you want an emulator rather than real hardware, since the README points at docker-android for that case, and it is unsuitable for a shared untrusted runner because the container needs privileged access to the USB bus.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why the setup was packaged into an image
The README states the motivation in two bullets, and they are worth quoting in spirit because they define the scope. It helps with a quick and easier setup of the automation environment for Appium with Android, and without this approach you have to do each of the automation setup steps manually, which can be slow and error prone. That is the whole problem. A CI agent that has to install the Android SDK, the adb tools, the Appium server and the right driver versions for every project and every image refresh is a source of flaky failures that have nothing to do with the tests. The image ships the server and the tooling together, and the intended use is running Appium tests on real Android devices. For emulators the README points you elsewhere, to the docker-android project, which is a useful distinction because emulators do not need USB passthrough at all, while real devices do.
The USB passthrough and the privileged container
The quick start is short because the container does the setup for you. You connect an Android device to the machine over USB, then run the container. The basic invocation publishes the Appium port 4723, mounts the host USB bus into the container and runs the container privileged:
$ docker run --privileged -d -p 4723:4723 -v /dev/bus/usb:/dev/bus/usb --name appium-container appium/appiumThe README also offers a tighter variant. If you look up the device id with the ls command on the serial by-id directory, you can pass that id to the container with the device option, which the documentation describes as having more security:
docker run --privileged -d -p 4723:4723 --device=/dev/<your-device-id> --name appium-container appium/appiumThe difference is the scope of the device access. Mounting the whole USB bus gives the container every USB device on the host, while naming one device path limits it to that device. Both variants still request privileged mode, which is the part to think about before putting this on a shared build agent, since a privileged container has more authority over the host than most CI workloads want to grant.
Checking that adb can see the phone
Step three of the quick start is a verification command, and it is the step that tells you whether the plumbing works before any test runs:
$ docker exec -it appium-container adb devicesIf the device does not appear in that list, nothing else will work, so this is the cheapest place to fail. On Windows there is an extra step, because the container cannot reach the host the way a Linux container can, so the adb host has to be given explicitly as host.docker.internal:
$ docker exec -it appium-container adb -H host.docker.internal devicesThe same host value is needed later from the test side, as the appium:remoteAdbHost capability, and the README notes that this capability is supported by several drivers, naming UiAutomator2, Espresso and Flutter. The test itself then points at the published port:
private void androidSetup() throws MalformedURLException {
caps.setCapability("deviceName", "Android");
caps.setCapability("app", "/home/androidusr/sample.apk");
//Get the IP Address of boot2docker
//docker inspect $(docker ps -q) | grep IPA
driver = new AndroidDriver<MobileElement>(new URL("http://xx.xx.xx.xx:4723/wd/hub"), caps);
}The application under test is copied into the container with docker cp, pointing at a path inside the container, which is why the capability refers to that container path rather than a host path.
Sharing the Android authorisation key between containers
A recurring annoyance with real devices is the authorisation prompt. Every time you recreate the container, the connected devices ask for authorisation again after the first connection, which means an interactive step in the middle of an automated pipeline. The README's solution is to share one identity across all created containers. You connect the devices to the Docker host machine, run adb devices, and authorise all of them, and the instruction to not forget to check the always allow this computer checkbox is the part that actually stops the prompt, since the adb key lives in the home directory of the user who authorised. Then the containers are run with the Android directory mounted into the container:
$ docker run --privileged -d -p 4723:4723 -v ~/.android:/home/androidusr/.android -v /dev/bus/usb:/dev/bus/usb --name appium-container appium/appiumThe same mount, with the container home path differing in the separate container example, is how the identity is carried over. It also means the host's adb key material is inside the container, which is a deliberate trade of isolation for unattended runs.
One container per device, and devices over the network
Two variations cover the setups a team is most likely to hit. For a separate container per device, the README explains that you must run adb kill-server and then give the device option to docker run, so each container claims one device node rather than competing for the whole bus:
$ docker run -d -p 4723:4723 --device /dev/bus/usb/XXX/YYY:/dev/bus/usb/XXX/YYY -v ~/.android:/root/.android --name device1 appium/appium
$ docker run -d -p 4724:4723 --device /dev/bus/usb/XXX/ZZZ:/dev/bus/usb/XXX/ZZZ -v ~/.android:/root/.android --name device2 appium/appiumNote the second container publishes a different host port, 4724, so two Appium servers do not collide. For devices that are not physically attached, the container can talk to them over the network, using the adb wireless configuration from the official manual. Three parameters do the work. REMOTE_ADB=true switches the mode, ANDROID_DEVICES takes a comma separated list of device host and port pairs, and REMOTE_ADB_POLLING_SEC controls how often the container re-checks the device list so that a lost remote device is picked up again, with a default interval of 5 seconds:
$ docker run -d -p 4723:4723 -e REMOTE_ADB=true -e ANDROID_DEVICES=192.168.0.5:5555,192.168.0.6:5555 -e REMOTE_ADB_POLLING_SEC=60That third parameter matters more than it looks. A wireless device on a home network or a lab bench will drop off, and without polling the container keeps believing the device is there.
Plugging the container into a Selenium Grid
The image can register itself as a node in a Selenium Grid, and the parameters follow the usual address and port convention. CONNECT_TO_GRID=true enables the behaviour, APPIUM_HOST and APPIUM_PORT describe the Appium server, and SELENIUM_HOST and SELENIUM_PORT describe the hub:
$ docker run --privileged -d -p 4723:4723 -e CONNECT_TO_GRID=true -e APPIUM_HOST="127.0.0.1" -e APPIUM_PORT=4723 -e SELENIUM_HOST="172.17.0.1" -e SELENIUM_PORT=4444 -v /dev/bus/usb:/dev/bus/usb --name appium-container appium/appiumThe image generates the node configuration file itself, and if you want your own you set CUSTOM_NODE_CONFIG=true and mount your configuration to the nodeconfig.json path in the container. There is also an extra parameter for passing additional Appium arguments, given as APPIUM_ADDITIONAL_PARAMS, with the example flags including relaxed security and the insecure options for chromedriver autodownload and adb shell. That last one is worth flagging: those switches lower the security posture of the Appium server, so they belong in a controlled lab network rather than a shared runner. For the compose setup there is an example file in the examples directory that simulates a hub and an Appium server with connected devices, started with docker-compose up -d.
Building the image and the release trail
You do not have to use the published image. The build is a single docker build command that points at the Appium directory and its Dockerfile, and the result is tagged as a local image:
$ docker build -t "appium/appium:local" -f Appium/Dockerfile AppiumThe repository layout is small, with an Appium/ directory holding the Dockerfile, an images/ directory, an examples/ directory, an app.sh entry script, and a renovate.json for dependency updates, all in a project whose primary language is shell. The published image lives on Docker Hub as appium/appium, and the release history on GitHub moves in patch releases, with v3.8.0-p1 from 2026-10-07, v3.7.0-p1 from 2026-09-18 and v3.7.0-p0 from 2026-09-01, so the p suffix marks the image variant rather than a semantic version of the code. The last push to the master branch was on 2026-10-21. One loose end is licensing: the repository licence field is classified as a custom licence that GitHub cannot categorise and points to the LICENSE file, so if your organisation needs a known licence, read that file rather than assuming one.
Editorial conclusion
appium-docker-android suits mobile teams running Appium against physical hardware in continuous integration, where every build agent would otherwise repeat the same driver installation and authorisation dance. It is the wrong tool if you want an emulator rather than real hardware, since the README points at docker-android for that case, and it is unsuitable for a shared untrusted runner because the container needs privileged access to the USB bus. Before adopting it, decide whether your devices are attached by USB or reachable over the network, because the two modes need different configuration, and check the licence file in the repository since GitHub could not classify it.
Frequently asked questions
How do I run Appium against a real Android device with Docker?
Connect the device to the machine over USB and run the container with privileged mode, the Appium port 4723 published and the USB bus mounted. The README suggests the docker run command with the --privileged, -p 4723:4723 and -v /dev/bus/usb:/dev/bus/usb options, then checking the device is visible with adb devices inside the container.
Do I have to run the container in privileged mode?
The quick start uses --privileged, and both documented variants keep it while narrowing the device access, either the whole USB bus or a single device path passed with the device option, which the README describes as having more security.
How do I connect Android devices over the network instead of USB?
Configure the device for wireless adb following the official manual, then run the container with REMOTE_ADB=true, ANDROID_DEVICES set to a comma separated list of host and port pairs, and REMOTE_ADB_POLLING_SEC to control how often the device list is re-checked, with a default interval of 5 seconds.
How does the container join a Selenium Grid?
Pass CONNECT_TO_GRID=true together with APPIUM_HOST, APPIUM_PORT, SELENIUM_HOST and SELENIUM_PORT, or set CUSTOM_NODE_CONFIG=true and mount your own configuration to the nodeconfig.json path in the container. An example compose file is provided in the examples directory.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/appium-appium-docker-android)Was this useful?