Ruby on Rails, Phoenix, and static site generators
Ruby on Rails, Phoenix and Elixir, and Jekyll, Hugo and other static site generators.
Part of Deploying by framework.
Ruby on Rails
noust create -d app.example.com -s https://github.com/you/app.gitA Gemfile next to a config.ru or a Rails config/application.rb, and no Dockerfile (a Dockerfile
is how a repository says it runs: it becomes a container application, and --type ruby builds it
natively anyway). The Ruby is the server's own, a distribution package: Noust does not install a
Ruby version for the application, and it says which package to install when the server has none
(apt install ruby ruby-dev bundler build-essential; the RPM names for Fedora and openSUSE). Bundler
reports a mismatch with the project's .ruby-version, and the deploy's log warns first.
-
Gems are installed into the release, by the unprivileged build account in the sandbox:
vendor/bundle, in deployment mode (Gemfile.lockis respected; without one the log says gems are being resolved on the server and asks you to commit it), without thedevelopmentandtestgroups. A rollback is the release's own gems. -
Assets are precompiled as production (
rails assets:precompile) when the application hasapp/assetsorapp/javascript; an API-only one has nothing to compile. The build runs withRAILS_ENV=productionand a throwawaySECRET_KEY_BASE, whatever.envsays. -
It runs under Puma when the bundle has it (
bundle exec puma -b tcp://127.0.0.1:PORT), elserackup, behind the web server.RAILS_LOG_TO_STDOUTputs the application's log in the journal andRAILS_SERVE_STATIC_FILESlets Puma serve the compiled assets. -
.envgetsRAILS_ENV=production,RACK_ENV=productionand a generatedSECRET_KEY_BASE, once; a value you set is never replaced. -
Migrations are a decision. Noust does not run
db:migratefor you; when the application has migrations the log says so. Declare it as a hook, which runs before the new release serves and aborts the deploy when it fails:YAML# noust.yaml hooks: pre_deploy: - run: bundle exec rails db:migrate migrates: true -
A database:
noust db provision app.example.com -e postgresqlcreates it and writes its connection string toDATABASE_URL, which Rails reads. Active Storage on the local disk needs--persist storage. -
Background jobs (Sidekiq, Solid Queue) are a process type: a
Procfilewith aworker:line runs beside the web process (build.md). -
A bare Rack application (a
config.ruand no Rails) is the same type;rackupruns it on the port.
What Noust does not do for Rails: it installs no Ruby for the application.
Phoenix and Elixir
noust create -d app.example.com -s https://github.com/you/app.gitA mix.exs with mod: {...}, a releases: block or Phoenix, and no Dockerfile. Noust builds a
Mix release as production and runs its script as the unit, so a rollback is a link to a release
that carries the Erlang runtime it was built with. The Elixir and Erlang are the server's own
(apt install elixir erlang-dev build-essential).
-
The build is
MIX_ENV=prodwhatever.envsays: Hex and Rebar are installed for the application (mix local.hex --force, in its build cache),mix deps.get --only prodis the install phase, thenmix compile, Phoenix'smix assets.deploywhen the project has the alias, andmix release --overwrite. -
.envgetsPHX_SERVER=true(a release does not start the endpoint without it),RELEASE_DISTRIBUTION=none(a release started otherwise runsepmdand listens on a node name),PHX_HOST(the domain, which Phoenix checks WebSocket origins against) and a generatedSECRET_KEY_BASE, once. PutPORTandDATABASE_URLwhereconfig/runtime.exsreads them: the unit setsPORT. -
Migrations are a decision.
mix phx.gen.releasewrites aRelease.migratefunction; declare it as a hook:YAML# noust.yaml hooks: pre_deploy: - run: ./_build/prod/rel/my_app/bin/my_app eval MyApp.Release.migrate migrates: true -
A database:
noust db provision app.example.com -e postgresql. -
A server older than the dependencies. The distributions ship an Elixir older than current Hex packages want (Ubuntu 24.04 has Elixir 1.14 on Erlang/OTP 25, and recent
plugandcowlibneed 1.15 and OTP 26). Mix reports that from inside the dependency; Noust names the dependency and the two versions and says to install a newer Elixir system-wide or to pin an older dependency (build.md). This is not a corner case for Phoenix: whatmix phx.newwrites today (Phoenix 1.7.21) stops on Ubuntu 24.04 atmix assets.setup, withphoenix_templateasking for Elixir 1.16; with Elixir 1.17 installed system-wide (the precompiled build for OTP 25 frombuilds.hex.pm, unpacked into/usr/localahead of the distribution's) the same project deploys, serves, updates and goes back.
A plain Plug application without Phoenix is the same type. A cluster of nodes is not what this sets up: a release runs alone, off the Erlang network.
Jekyll and other static site generators
Jekyll is not a type Noust detects: a repository with a Gemfile and a _config.yml and no
config.ru has nothing to run, so the Ruby type declines it (it is not an application server), and
index.html is not at its root until it is built. There are three honest ways, in the order that
costs least:
-
Build it where its tools are, in CI, and deploy the output. A pipeline runs
bundle exec jekyll buildand deploys_siteas a static site (noust upload, or a repository of the output). Nothing about Ruby is needed on the server. -
Build it on the server, as a static application with a
build:block. The server needs Ruby and Bundler (apt install ruby ruby-dev bundler build-essential), and gems must be installed where the unprivileged build account can write: commit a.bundle/configwithBUNDLE_PATH: "vendor/bundle"(the.gitignorethatjekyll newwrites lists.bundle/: take that line out, or the file is not committed).YAML# noust.yaml build: install: bundle install build: bundle exec jekyll build publish_directory: _siteShellnoust create -d blog.example.com -s https://github.com/you/blog.git --type static--type staticis needed because detection looks for anindex.html. The site is served as files behind nginx or Apache, with a certificate, and every update is a release like any other. -
A container. A
Dockerfilewith a build stage (Ruby, thenjekyll build) that leaves the files in an image served by a web server runs as a container application (containers.md).
Eleventy, Docusaurus, Hugo (its binary on the server) and every generator whose tools are on the server follow the second way; the ones whose tools are Node's need only Node (build.md).