rebar3 is included at
the end.
Prerequisites
To follow this tutorial, you will need the following:- Elixir (v1.17 or later at the time of writing this doc) and the matching Erlang/OTP (OTP 27 or
later) installed via
asdfor your platform package manager. - Mix as the build tool for Elixir. This comes bundled with Elixir.
- Phoenix installer (
mix archive.install hex phx_new). - A basic knowledge of Elixir and Phoenix.
- Docker to build standalone containers to serve your production app.
This guide assumes that you have basic knowledge of the above-mentioned technologies and tools. If you are not
familiar with any of them, it is highly recommended to review their official documentation and tutorials to get up to
speed before proceeding with this guide.
Scaffolding the Phoenix app
Create a new Phoenix project. In the following examples, we’ll use the project namehello_app. The --no-ecto flag
skips database setup so we can focus on the Dockerfile — drop it if your real app uses a database.
Hello World! example
Openlib/hello_app_web/router.ex and add a simple route at / returning JSON:
lib/hello_app_web/router.ex
lib/hello_app_web/controllers/page_controller.ex:
lib/hello_app_web/controllers/page_controller.ex
http://localhost:4000 in your browser. You should see {"message":"Hello, World!"}.
Create the Docker image
Dockerizing makes the app run anywhere, agnostic of the platform. As long as Docker is installed, whether it’s Windows, Mac, or Linux, it can run with the same behavior. The recommended way to ship a Phoenix app in production is as an Elixir release — a self-contained tarball that bundles the Erlang VM, your compiled code, and all dependencies. It’s smaller and faster to boot than runningmix phx.server in production.
Generate the release config
If you haven’t already, generate the release config that Phoenix uses to start your app inside a release:rel/overlays/bin/server, rel/overlays/bin/migrate, and a starter Dockerfile and .dockerignore tuned
for Phoenix releases. You can use the generated files as-is or customize them with the snippets below.
Create .dockerignore
Before building the image, create a.dockerignore file with paths that shouldn’t be copied into the build context:
.dockerignore
Excluding
_build, deps, and node_modules is important — these contain build artifacts from your local machine
that may not match the target platform. The build will happen inside the Docker container with the correct platform
settings.Create Dockerfile
Now, create a Dockerfile. The Dockerfile uses Multi-Stage Builds — a builder stage with the full Elixir toolchain compiles the release, and a tiny Debian slim runtime stage runs it. The final image is typically under 100 MB.Dockerfile
Pin the Elixir, Erlang, and Debian versions in the
hexpm/elixir tag to match what your team develops against — a
mismatch between local and container OTP versions is the most common source of “works on my machine” surprises with
the BEAM.Build Docker image
Now you can build the Docker image:hello-app image for platform linux/amd64 and tags it as latest.
If you are locally testing your application, you can skip the platform key:
Run the Docker image
Let’s run the Docker container using the image created of the Phoenix application. The app needs aSECRET_KEY_BASE to
start in production — generate one with mix phx.gen.secret and pass it via -e:
-it: enables interactivity with TTY.--rm: tells the Docker Daemon to clean up the container and remove the file system after the container exits.--name hello-app: Name of the containerhello-app.-e PORT=4000: Sets the HTTP port Phoenix listens on.-e PHX_SERVER=true: Tells the release to start the Phoenix endpoint (releases skip it by default).-e SECRET_KEY_BASE=...: Required signing/encryption secret for sessions and tokens.-d: Runs the container in detached (background) mode.-p 4000:4000: Maps port 4000 on your host to port 4000 in the container.
http://localhost:4000 to see the Phoenix application running inside the Docker
container.
To view logs from the container:
Erlang variant (Cowboy + rebar3)
For Erlang services using Cowboy directly, the structure is similar — replace Mix withrebar3 and the Elixir
release with an Erlang relx-based release.
A minimal rebar.config:
rebar.config
Dockerfile
docker build / docker run commands as above, swapping the image name.