Self-hosted service
Shmayro/dockerify-android avatar
Shmayro/dockerify-android

dockerify-android puts a rooted Android emulator inside a Docker container

A Dockerized Android emulator supporting multiple CPU architectures (x86 and arm64) with native performance and seamless ADB & Scrcpy Web access.

647 stars73 forksShellMIT

At a glance

What is it?
Dockerify Android is an MIT licensed Docker image that runs an Android emulator with root and Magisk, PICO GAPPS and an ARM translation layer, reachable over ADB, over desktop scrcpy or through a browser interface. It needs KVM and a privileged container, and it ships as a single v1.0.0 release with most of its complexity baked into the image.
Who is it for?
dockerify-android suits a CI pipeline or a test lab that needs a reproducible, rooted Android device it can start, script over ADB and throw away, and it is the wrong tool for a developer who wants a fast local emulator on a laptop without KVM, since the container is privileged and bound to the virtualisation device.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 147 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

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

Editorial analysis

A container that behaves like a device lab

Dockerify Android is a Dockerized Android emulator supporting multiple CPU architectures, x86 and ARM and ARM64 apps via an ndk_translation layer, with native performance and seamless ADB and web access. The stated purpose is to let developers run Android virtual devices, AVDs, efficiently within Docker containers, which is the shape you need when the emulator is infrastructure rather than an application on your desk.

The feature list explains what that means in practice. There is a web interface that puts the emulator in a browser through the scrcpy-web project, with no extra software to install, access from any computer with a browser, full touchscreen and keyboard support, and a use case of remote work or sharing the emulator with team members. There is ARM translation, so modern apps that ship only ARM native libraries in arm64-v8a or armeabi-v7a can be installed on an x86_64 emulator. There is root access with Magisk preinstalled, and PICO GAPPS for the Google services many apps expect.

Underneath, the container is managed by Supervisor, which the documentation lists as supervisor management for reliability, and all emulator and boot logs are redirected to Docker's standard log system, so a container that misbehaves can be diagnosed with the tools you already use.

The project is a shell and Docker project, MIT licensed, and the last push was on 2026-05-29, the same day as the single tagged release, v1.0.0, whose note reads ARM apps, Magisk modules, and full Docker bake-in.

Prerequisites: KVM decides whether this runs at all

The prerequisites are short, and one of them is the one that decides everything.

You need Docker and Docker Compose, and you need KVM support for hardware acceleration. The check is a single command:

bash
    egrep -c '(vmx|svm)' /proc/cpuinfo

A non-zero output indicates KVM support. The flags being counted are the CPU virtualisation extensions, vmx on Intel and svm on AMD, and the point of the check is that you find out before you build an image rather than after.

The compose file confirms how the requirement is enforced. The emulator service declares privileged: true and passes the device through directly:

yaml
services:
  dockerify-android:
    container_name: dockerify-android
    image: shmayro/dockerify-android:latest
    build:
      context: .
    ports:
      - "5555:5555"

A privileged container with the KVM device mapped in is the price of hardware acceleration. It also means the container has far more authority over the host than a normal container, and any organisation that forbids privileged containers in CI will rule this project out before the emulator starts.

There is also a /dev/kvm requirement in the devices list, and the compose file publishes port 5555, which is the ADB port the emulator listens on.

Cloning, starting and waiting for the first boot

The documented install is the standard two step for a compose project.

Clone the repository:

bash
    git clone https://github.com/shmayro/dockerify-android.git
    cd dockerify-android

Then start it:

bash
    docker compose up -d

That command launches the Android emulator and the web interface, and the documentation is clear that the first boot takes some time to initialise. Once the device is ready it appears in the web interface at http://localhost:8000.

That delay is the first thing to expect and the reason the compose file has a health check arrangement. The scrcpy-web service declares a dependency on the emulator with a condition of service_healthy, so the web container waits for the emulator to report itself ready rather than starting against a device that is still booting. Its command connects the two explicitly:

yaml
    command: >
      sh -c "
        adb connect dockerify-android:5555 &&
        npm start
      "

The two containers in the compose file are therefore a pair rather than two independent services. The emulator holds the AVD and exposes ADB on 5555, and the web frontend attaches to it over the compose network by container name.

Three ways in: browser, ADB and desktop scrcpy

Access comes in three forms, and the browser route is the one the project leads with.

In the browser you open http://localhost:8000, where the device should already be listed as dockerify-android:5555 and connected. You then choose a streaming option. The H264 Converter is the recommended one for the best overall experience, Tiny H264 is for low bandwidth connections, and Broadway.js is the fallback. The choice exists because the web client needs to decode the video stream in the browser, and each of these approaches gets there differently, at different quality and bandwidth costs.

For direct ADB access, the commands are the standard ones:

bash
adb connect localhost:5555
adb devices

and the documented expected output is a connected line followed by a device list containing localhost:5555. This is the route a CI script would use, since it does not involve a browser at all.

For a native desktop mirror, scrcpy connects to the same endpoint:

bash
scrcpy -s localhost:5555

with the note that scrcpy has to be installed on the host machine.

The three options map onto three kinds of user. A person sharing a device with a colleague uses the browser, an engineer scripting a test uses ADB, and a developer at a desk who wants a real window uses scrcpy. The underlying device is the same in all three cases.

The environment variables, and the one you cannot take back

The configuration table is short, and one entry behaves differently from the rest.

DNS sets the private DNS server used inside the emulator and defaults to one.one.one.one. RAM_SIZE is the RAM in megabytes allocated to the emulator and defaults to 4096. SCREEN_RESOLUTION takes a WIDTHxHEIGHT value such as 1080x1920 and defaults to the device default, and SCREEN_DENSITY is the screen pixel density in DPI, also defaulting to the device default. ARM_TRANSLATION set to 1 enables the ARM translation layer that allows ARM64 apps.

Then there are the two that install things. ROOT_SETUP set to 1 enables rooting and Magisk, and the documentation is explicit that it can be turned on after the first start but cannot be undone without recreating the data volume. GAPPS_SETUP set to 1 installs PICO GAPPS, with the same one-way property described for it.

That irreversibility is the practical trap. Turning on rooting later is fine, but turning it off again means throwing away the data volume, which means re-running the first boot, which means the device state, the installed apps and the accounts all start again from nothing. Anyone planning to test both a rooted and an unrooted configuration should use separate data directories rather than flipping the variable.

In the compose file the two flags default to 0 with inline comments, and ARM_TRANSLATION defaults to 1, so the shipped default is a plain, unrooted, ARM-capable emulator.

What the image bakes in before it runs anything

The Dockerfile is where the project does its unusual work, and the comment in the compose file that says full Docker bake-in is about the third stage of the build.

The base is ubuntu:20.04, and the package list is the emulator's dependency set: libegl1, openjdk-17-jdk-headless, wget, curl, git, lzip, unzip, supervisor, qemu-kvm, iproute2, socat and tzdata. Supervisor is the process manager, qemu-kvm is the emulator's virtual machine, socat handles the port plumbing and libegl1 provides the graphics support the emulator needs.

Three artefacts are fetched and baked into the image rather than downloaded at run time. The Google ndk_translation prebuilts come from a fork, with the repository and branch set as build arguments, and the comment explains why: the fork matches the emulator's API 30. The rootAVD tool, a Magisk-based AVD rooting tool with a bundled Magisk.zip, is fetched from GitLab. And the Android SDK command line tools are downloaded and unzipped, with ANDROID_HOME and ANDROID_AVD_HOME set so the AVDs live under the mounted data volume rather than inside the image.

That last point is the reason the compose file mounts ./data at /data. AVDs, user data and installed apps live there, so the image stays immutable and the device state survives a container rebuild.

The repository mirrors this in its layout, with a first-boot.sh and a start-emulator.sh script, a supervisord.conf, an emulator/ directory and an emulator.zip, and an extras/ directory that is mounted into the container as well, which is the place to put files you want on the device.

One release, a privileged container and an emulation layer

There are three limitations worth naming, and none of them are hidden.

The first is the release history. There is a single tag, v1.0.0, published on 2026-05-29, and the last push to the repository is the same day. A project that has been public for a short time with one release is a project whose configuration will still change, and a team pinning it in CI should expect to read the roadmap section and the changelog in the repository before relying on it.

The second is the privileged requirement. The container runs privileged with the KVM device mapped in, which is what makes hardware acceleration possible and therefore what makes the emulator usable rather than a slideshow. On a shared build host, on a managed CI service, or anywhere with a policy against privileged containers, that is a hard stop.

The third is the nature of the ARM support. It is a translation layer, ndk_translation, not native ARM execution, and it is applied to an x86_64 emulator. The project describes the performance as native, and the Docker image is built to run natively on both x86 and arm64 hosts, which is a different claim: the host runs at native speed while the guest ARM code is translated. For an app that ships only ARM libraries, that is the difference between installable and not installable, and it is worth testing the particular apps you care about rather than assuming the flag covers them.

The licence is MIT, and the project also ships a CODE_OF_CONDUCT.md and a CONTRIBUTING.md. The image is published on Docker Hub as shmayro/dockerify-android.

Editorial conclusion

dockerify-android suits a CI pipeline or a test lab that needs a reproducible, rooted Android device it can start, script over ADB and throw away, and it is the wrong tool for a developer who wants a fast local emulator on a laptop without KVM, since the container is privileged and bound to the virtualisation device. Before adopting it, decide about ROOT_SETUP and GAPPS_SETUP up front, because the documentation states that rooting can be enabled after the first start but cannot be undone without recreating the data volume.

Frequently asked questions

What is dockerify-android?

It is a Dockerized Android emulator that runs AVDs inside a container with root and Magisk, PICO GAPPS and an ARM translation layer, and it can be reached over ADB, over desktop scrcpy or through a browser-based scrcpy-web interface. It is MIT licensed.

What does dockerify-android need to run?

Docker, Docker Compose and KVM support for hardware acceleration, which you check with egrep -c '(vmx|svm)' /proc/cpuinfo where a non-zero output means KVM is available. The container is privileged and maps /dev/kvm through to the host.

How do I start dockerify-android?

Clone the repository, change into the directory and run docker compose up -d. The first boot takes time to initialise, and once the device is ready it appears in the web interface at http://localhost:8000 as dockerify-android:5555.

Can I turn off rooting in dockerify-android later?

No. The documentation states that ROOT_SETUP can be turned on after the first start but cannot be undone without recreating the data volume, which means re-running the first boot and losing the device state.

How do ARM-only Android apps run in dockerify-android?

Through the ndk_translation layer, which is enabled with ARM_TRANSLATION=1 and is baked into the image from a fork whose branch matches the emulator's API 30. It allows installation of modern apps shipping only arm64-v8a or armeabi-v7a native libraries on an x86_64 emulator.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. Shmayro/dockerify-android on GitHub
Add this badge to your README

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

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/shmayro-dockerify-android.svg)](https://hysenlabs.com/projects/shmayro-dockerify-android)

Was this useful?