Deployment into Digital Ocean or Linode or Vultr or OVH

Dear all,
Please help me, how to deploy phoenix application into VPS like Digital Ocean or Vultr or Linode or OVH cloud, I have searching through Google but nothing found fit to me

Hi @ariandanim, can you share some of the posts you have seen and help us understand what doesn’t fit?

1 Like

@benwilson512 Fit to me mean no one explain with detail to deploy it

Have you tried Introduction to Deployment — Phoenix v1.6.12? it has step by step instructions for three different hosting solutions.


The end of the “Releases” documentation has an example dockerfile Deploying with Releases — Phoenix v1.6.12.

Also see mix help phx.gen.release and mix phx.gen.release --docker.

You can get quite far with a docker-compose file. The only issue is getting your container image upstream which has a few options:

  1. docker/podman save, scp and docker/podman load.
  2. Push your container to a hosted registry (docker, quay, github, google all provide free hosting, at least for public images).
  3. Run a registry yourself, which is quite easy (there is a container for it!). You can run this bound to localhost only and push images over an ssh tunnel to simplify auth for small-scale deployments or run it on a protected network interface with a auth wrapper for multi-host systems, or expose it to the world if you’re into that kind of thing.

The save-load method is simple, it just has to copy the whole thing every time, vs a registry that lets you just push the changed layers. This can have an impact if your project is large or your internet is slow.

You can also just rsync the release output and run it directly.

I host all my services on Linode and they have always been great.


Tks @soup , but I need pure VPS for production not using Docker,
Btw does docker can deploy to production? May I miss something?

Yes. I suggest you investigate containerised deployment. Docker is probably the simplest and most popular runtime for doing this. Podman is another option. I think you can avoid getting side tracked by other systems such as Kubernetes for now.

Docker will have the widest amount of documentation & tutorials.

I would suggest you get docker compose running locally, then get it running on your VPS (ignore your Phoenix app for now) then look into how you can deploy your app into that infrastructure. Then you are probably in a better place to make a decision on your production strategy.


Tks Bro @soup ,

Perhaps @chrismccord have a solution to deploy phoenix app into VPs production

I think that is the one you have already in the official docs.

That is the one I followed to deploy on Digital Ocean VPS.

If you don’t want to use docker like me, just build the release with the same OS version as the one you have on your production machine.

You can also install elixir on your production machine and build the release from it.

Just follow the guide and if you feel lost somewhere, just ask it here. As I can see there are already very good advices here in this thread.

Good luck. ^^


I use Linode+Dokku for a Phoenix app and it works well. Gigalixir also worked for me, and looks very promising. Gigalixir, Fly, and Dokku, though, as PaaS’s, not VMs. So they take care of a lot of the work. I didn’t need to consult the Phoenix docs.


I’ll second (or third) the advice to follow the official documentation. That documentation is great, but there’s some context that’s not immediately obvious. First, the preferred method of deploying to a VPS would be to use Releases, as documented (and previously mentioned) here: Deploying with Releases — Phoenix v1.6.12

A release must be built on the same platform that it will be run on. That means, if your VPS is running Ubuntu, you need to build the release on Ubuntu. If you develop on a mac, you’re in a position where you have to use docker, CI or some other custom environment to build the release. That’s one reason why there’s the --dockerfile option on mix phx.gen.release. See more info here: mix release — Mix v1.14.0

If you don’t want to run Docker in production, you should be able to just copy the release up to your server, and start it with _build/prod/rel/my_app/bin/server (changing the path based on what your release path actually looks like).

Other considerations:

  • If you need a database, that’s a whole separate thing. You’ll need to either set one up on that instance, or connect to one running on some other instance
  • Make sure your DNS is pointed to the IP address of your VPS to test things out, and that your phoenix app is listening at least on port 80
  • Make sure you have an SSL cert if you are making this publicly accessible (GitHub - sasa1977/site_encrypt: Integrated certification via Let's encrypt for Elixir-powered sites is a good way to do that)
  • Consider using something like systemd to ensure that your app keeps running through restarts and gets restarted automatically if there are problems on the server
  • For your own sanity, don’t neglect to set up some basic security configuration on the server (close ports you don’t need with a firewall, set up automatic updates, don’t allow ssh connections with passwords)

Tks @dmcbrayer , I am using Ubuntu 20 LTS Server in Contabo VPS service, where the spesific folder my Ubuntu server to put my phoenix app release?

I would also recommend that you look in to docker and docker-compose think of your docker enviroment as a virtualized VPS what you do in your docker file it would be needed on your vps as well. Dockerfile read like a docuement for your release steps IMO. Here is a write up I did sometime ago which might be of some help

1 Like

It doesn’t particularly matter where you put the release package to my knowledge. I typically have a single user that let’s call bob. I’d make an app directory in bob’s home directory and drop the release package there. So to start the app I’d do something like (logged in as bob): ~/app/_build/prod/rel/my_app/bin/server to start the app.

1 Like

I recently wrote an article on how I deploy, might help you. How I deploy my Phoenix apps

I use OVH to deploy my app, not the VPS, but I guess it should be the same… My instances all have Ubuntu 22.04 installed, what I did to generate my releases was create a special docker container that has the same environment as my VMs, here is the Dockerfile:

FROM ubuntu:22.04 AS build

ARG USER=builder
ARG UID=1000
ARG GID=1000
ARG PWD=builder

RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates gnupg software-properties-common wget

RUN wget -O - 2> /dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg > /dev/null

RUN apt-add-repository 'deb focal main'

RUN wget -O - | apt-key add -

RUN apt-add-repository 'deb llvm-toolchain-jammy-14 main'

RUN apt-get update

RUN DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y apt-utils

RUN apt-get update

RUN wget
RUN dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb
RUN rm libssl1.1_1.1.1f-1ubuntu2_amd64.deb

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y clang-14 capnproto

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y git

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y curl

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libssl-dev automake autoconf libncurses5-dev

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y xsltproc fop libxml2-utils

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libsystemd-dev

RUN update-alternatives --install /usr/bin/cc cc /usr/bin/clang-14 10
RUN update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-14 10

RUN useradd -m $USER --uid $UID
RUN echo "${USER}:${PWD}" | chpasswd



ENV TERM=xterm-256color

RUN git clone ~/.asdf --branch v0.10.2

RUN echo 'source $HOME/.asdf/' >> ~/.bashrc

ENV PATH="/home/${USER}/.asdf/bin:${PATH}"
ENV PATH="/home/${USER}/.asdf/shims:${PATH}"


RUN /bin/bash -c "asdf plugin add cmake"
RUN /bin/bash -c "asdf install cmake 3.23.3"
RUN /bin/bash -c "asdf global cmake 3.23.3"

RUN /bin/bash -c "asdf plugin add rust"
RUN /bin/bash -c "asdf install rust 1.63.0"
RUN /bin/bash -c "asdf global rust 1.63.0"

RUN /bin/bash -c "asdf plugin add erlang"
RUN /bin/bash -c "asdf install erlang 25.0.4"
RUN /bin/bash -c "asdf global erlang 25.0.4"

RUN /bin/bash -c "asdf plugin add elixir"
RUN /bin/bash -c "asdf install elixir 1.14.0-otp-25"
RUN /bin/bash -c "asdf global elixir 1.14.0-otp-25"

RUN echo 'PS1="(builder) $PS1"' >> ~/.bashrc

RUN /bin/bash -c "HEX_MIRROR= mix local.hex --force"
RUN /bin/bash -c "HEX_MIRROR= mix local.rebar --force"

WORKDIR /home/${USER}/project

CMD ["/bin/bash"]

This will install a lot of dependencies that I need (like rust, libssl1, etc) so you can probably remove some that you don’t need and make the script simpler.

To build it I use the following command:

docker build --build-arg USER=$USER   \
             --build-arg UID=$(id -u) \
             --build-arg GID=$(id -g) \
             --no-cache               \
             -t my-project/builder:v1 .

And now, to use it, I first go to my elixir project directory and run:

docker run --detach-keys='ctrl-e,e' --cpus 8 --net=host -it -v$(pwd):/home/$USER/project --rm my-project/builder:v1

This will start the container, leave you in a bash inside it where you can build your release with MIX_ENV=prod mix release and then copy the resulting release in _build/prod/rel/my-project to your VPS and then run it there.