Deploying Elixir on Hop3¶
Deploying Elixir on Hop3 means building an OTP release with Mix and running it as a long-lived BEAM process. Hop3 compiles your project on the server, packages it into a self-contained release with mix release, and runs that release binary as a managed worker. The BEAM listens on the dynamic $PORT Hop3 assigns, and nginx proxies your hostname to it — the same model as every other language on Hop3, with the BEAM's supervision trees and clustering available on top.
This page covers what every Elixir deployment has in common. Read it first, then follow the framework guide below for a complete, runnable walkthrough.
How Hop3 builds and runs Elixir¶
Hop3 installs the toolchain your build needs — declare it in [build].packages (typically erlang, elixir, and nodejs for asset bundling). On each deploy, the before-build steps run on the server: install Hex/Rebar, fetch production deps, build assets, and cut the release with mix release. The result lands in _build/prod/rel/<app>/, and [run].start launches the release binary as the web worker.
The release process must bind to the port Hop3 gives it. Hop3 exports $PORT into the run environment; your app reads it (Phoenix does this in config/runtime.exs) and listens on 0.0.0.0:$PORT. Hop3 then configures nginx to forward your HOST_NAME to that process — you never bind a fixed public port yourself.
A representative hop3.toml:
[metadata]
id = "my-elixir-app"
version = "1.0.0"
[build]
before-build = [
"mix local.hex --force --if-missing",
"mix local.rebar --force --if-missing",
"mix deps.get --only prod",
"MIX_ENV=prod mix assets.deploy",
"MIX_ENV=prod mix release --overwrite",
]
packages = ["erlang", "elixir", "nodejs"]
[run]
start = "_build/prod/rel/my-elixir-app/bin/my-elixir-app start"
[env]
MIX_ENV = "prod"
MIX_HOME = "/home/hop3/apps/my-elixir-app/.mix"
HEX_HOME = "/home/hop3/apps/my-elixir-app/.hex"
[port]
web = 4000
[healthcheck]
path = "/up"
timeout = 30
interval = 60
Notes that apply to every Elixir app¶
- Releases, not
mix phx.server. Production deploys run a compiled OTP release, which bundles the Erlang runtime and your compiled code into one artifact — no Mix or source needed at runtime. Build it inbefore-build, run it in[run].start. - Set
SECRET_KEY_BASE. Releases refuse to start without it. DeclareSECRET_KEY_BASE = { generate = "urlsafe", length = 64 }inhop3.toml[env]and Hop3 generates one on the first deploy, persists it, and reuses it on every later deploy — nomix phx.gen.secret, no manual step, nothing committed. - Hostname and host config. Set
HOST_NAMEso nginx routes to your app, andPHX_HOSTso the framework builds correct URLs. After setting them, deploy once more so the changes take effect. - Databases via addons. Add a PostgreSQL addon and Hop3 injects
DATABASE_URL; read it inconfig/runtime.exsand run migrations from abefore-runrelease-eval step so they apply before the new release serves traffic. - Health checks. Expose a cheap endpoint (Phoenix ships
/up) and point[healthcheck].pathat it so Hop3 knows when the BEAM is actually ready. - Build cost. The first deploy fetches and compiles all dependencies, which is slow; subsequent deploys reuse
_buildanddepsand are much faster.
Choose a framework¶
| Framework | Description |
|---|---|
| Phoenix | The standard Elixir web framework — real-time apps with LiveView, channels, and an OTP release, proxied by nginx on the dynamic $PORT. |