Deployment guide

Elixir Phoenix

Overview

Elixir is a dynamic, functional language that runs on the Erlang virtual machine (the BEAM). Phoenix is its productive, real-time web framework. Together they form the stack behind fault-tolerant, massively concurrent web applications and WebSocket channels at scale.

This SecureAnyCloud image installs Elixir 1.20.2 and Phoenix 1.8.9 on Erlang/OTP 28.5 on Ubuntu 24.04 on Azure. Every component is pinned by exact version and verified against sha256 checksums: Erlang/OTP is compiled from the official source release, and Elixir is the official precompiled build.

The image also ships a browsable web UI. A demo Phoenix application is pre-deployed as a production Mix release, the self-contained BEAM artifact that bundles its own Erlang runtime, and is served behind nginx on port 80. Point a browser at the VM to see the standard Phoenix welcome page, a live JSON status route, and Phoenix LiveDashboard, the real-time BEAM observability console.

What you get:

  • Elixir 1.20.2 (Apache-2.0) and Phoenix 1.8.9 (MIT), pinned and sha256-verified
  • Erlang/OTP 28.5.0.3 compiled from the official source release and installed to /usr/local
  • elixir, iex and mix on the default system PATH for every user
  • A demo Phoenix app built as a production Mix release and deployed to /var/lib/phoenix-demo/rel/demo
  • The phoenix-demo.service systemd unit, which starts on boot and runs as the unprivileged phoenix:phoenix system user
  • The elixir-phoenix-firstboot.service systemd oneshot, which generates a per-VM secret, starts the release and nginx, and confirms the app answers before completing
  • The Phoenix endpoint bound to loopback only (127.0.0.1:4000), with nginx fronting it on :80 and passing WebSocket upgrades for LiveView
  • An unauthenticated, nginx-native /healthz endpoint (HTTP 200) for load balancer and probe checks
  • The standard Phoenix welcome landing page at /
  • A live JSON status route at /api/status that returns a server timestamp, the Elixir, OTP and Phoenix versions, and a concurrency-safe request counter, which shows that the BEAM executes code on every request
  • Phoenix LiveDashboard at /dashboard, showing live BEAM memory, processes, ETS and run-queues over a LiveView WebSocket
  • The Mix release and runtime data on a dedicated 20 GiB Azure data disk at /var/lib/phoenix-demo, independent of the OS disk and independently resizable
  • Ubuntu 24.04 LTS base with the latest security patches applied at build time
  • Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA

Prerequisites

  • An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
  • A subscription to the Elixir with Phoenix listing on Azure Marketplace
  • Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development. Production Phoenix workloads should use Standard_D4s_v5 (4 vCPU, 16 GB RAM) or larger.
1

Deploy from the Azure Portal

Search the Azure Marketplace for Elixir with Phoenix, select the SecureAnyCloud publisher, and click Create.

Add Network Security Group rules that allow TCP 22 (admin), TCP 80 (HTTP) and TCP 443 (reserved for TLS) from your client networks.

2

Deploy from the Azure CLI

RG="phoenix-prod"; LOCATION="eastus"; VM_NAME="phoenix-01" IMAGE_URN="sac1647283583153:elixir-phoenix-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name phoenix-vnet --address-prefix 10.100.0.0/16 --subnet-name phoenix-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name phoenix-nsg az network nsg rule create -g "$RG" --nsg-name phoenix-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name phoenix-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name phoenix-nsg --name allow-https --priority 120 \
  --destination-port-ranges 443 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:elixir-phoenix-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name phoenix-vnet --subnet phoenix-subnet --nsg phoenix-nsg --public-ip-sku Standard
3

Connect via SSH

ssh azureuser@<vm-ip>
4

Verify the Phoenix and nginx services

Run the checks below. They confirm that the demo release and nginx are running, Phoenix is bound to loopback only, the health endpoint answers, and the data disk is mounted.

for s in phoenix-demo.service nginx.service elixir-phoenix-firstboot.service; do printf ' %-34s %s\n' "$s" "$(systemctl is-active $s)" done ss -tlnH | awk '{print $4}' | grep -E ':4000$|:80$' | sort -u curl -s -o /dev/null -w 'GET /healthz -> HTTP %{http_code}\n' http://127.0.0.1/healthz findmnt -no SOURCE,TARGET,FSTYPE,SIZE /var/lib/phoenix-demo
5

Check the health endpoint

Request the /healthz endpoint. nginx serves it directly, with no round trip to the BEAM, so it suits Azure Load Balancer health probes.

curl -i http://127.0.0.1/healthz
6

Open the Phoenix landing page in a browser

Browse to http://<vm-public-ip>/. The demo Phoenix application serves the standard Phoenix welcome page, rendered by the running release on the BEAM VM.

7

Call the live status API

Browse to http://<vm-public-ip>/api/status, or request it with curl. The route returns live JSON: a server timestamp, the Elixir, Erlang/OTP and Phoenix version numbers, and a request counter held in a supervised process.

Reload the page. The counter increments and the timestamp advances, which shows that the BEAM VM executes code on every request instead of serving a static file.

curl -s http://127.0.0.1/api/status echo
curl -s http://127.0.0.1/api/status
8

Explore Phoenix LiveDashboard

Browse to http://<vm-public-ip>/dashboard. Phoenix LiveDashboard is the real-time observability console for the BEAM VM, and it updates live over a LiveView WebSocket. The Home page shows the Erlang/OTP, Elixir and Phoenix versions, atom and process counts, memory breakdown and run-queue depth.

The Processes page lists the live Erlang processes inside the BEAM VM with their memory, reduction count, message-queue length and current function, refreshing in real time.

LiveDashboard is exposed without authentication as a demo and showcase surface. Restrict it in production, either by putting it behind authentication or by removing the route (see Step 13).

9

Confirm the toolchain and deployed release

The Elixir toolchain is on the system PATH. The demo app is a self-contained production Mix release that bundles its own Erlang runtime. Confirm both:

elixir --version ls -1 /var/lib/phoenix-demo/rel/demo/ test -x /var/lib/phoenix-demo/rel/demo/bin/demo && echo "release binary present"
10

Read the endpoint notes

First boot writes a non-secret notes file that documents the demo URLs and how to deploy your own release. Read it:

cat /var/lib/sac/data/elixir-phoenix-endpoints.notes
11

Build and deploy your own Phoenix release

The image is a full Elixir and Phoenix build environment. To ship your own application, generate it, build a production release, and point the systemd unit at it. A Mix release bundles its own runtime, so nothing else is needed at runtime.

# On a build host (or this VM), generate and build a release, then browse http://<vm-ip>/ : mix phx.new myapp cd myapp MIX_ENV=prod mix assets.deploy MIX_ENV=prod mix release
# Deploy it onto the data disk and repoint the service:
sudo systemctl stop phoenix-demo.service
sudo cp -a _build/prod/rel/myapp /var/lib/phoenix-demo/rel/myapp
sudo chown -R phoenix:phoenix /var/lib/phoenix-demo/rel/myapp
sudo sed -i 's#/rel/demo#/rel/myapp#g; s#/bin/demo#/bin/myapp#g' /etc/systemd/system/phoenix-demo.service
sudo systemctl daemon-reload
sudo systemctl start phoenix-demo.service

The per-VM SECRET_KEY_BASE, PHX_HOST and PORT live in /var/lib/phoenix-demo/demo.env. The systemd unit reads this file as an EnvironmentFile.

12

Manage the Phoenix service

sudo systemctl status phoenix-demo.service --no-pager sudo systemctl restart phoenix-demo.service
sudo journalctl -u phoenix-demo.service -n 50 --no-pager

Run sudo journalctl -u phoenix-demo.service -f to follow the logs live. Run sudo -u phoenix /var/lib/phoenix-demo/rel/demo/bin/demo remote to attach a remote IEx shell to the running node.

13

Security recommendations

  • Restrict or remove LiveDashboard. The /dashboard route is unauthenticated in this demo image. For production, put it behind authentication, for example a Plug that checks a basic-auth header or an admin session. Alternatively, remove the live_dashboard route from your router.
  • Add TLS. Terminate HTTPS at nginx (port 443) with your certificate, or front the VM with Azure Application Gateway. Port 443 is reserved in the NSG for this.
  • Lock down the NSG. Restrict TCP 22 to your management CIDR. Expose TCP 80 and 443 only to the clients or load balancer that need them.
  • Keep the OS patched. Unattended security upgrades are enabled by default.
  • Rotate the Phoenix secret if you clone the VM. Delete /var/lib/phoenix-demo/demo.env and restart elixir-phoenix-firstboot.service to regenerate SECRET_KEY_BASE.

Support

SecureAnyCloud provides 24/7 commercial support with a guaranteed 24-hour response SLA, separate from the upstream open source projects. Contact sales@secureanycloud.com.

Elixir is licensed under Apache-2.0 and Phoenix under the MIT license. Both are free and open source, with no per-CPU or per-deployment fee. The SecureAnyCloud charge covers packaging, security patching, image maintenance and support.

Deploy on Azure

Launch Elixir with Phoenix on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure