NetrunHome

Sites and apps

How to deploy a Ruby on Rails app

· 5 min read

In short

To deploy a Ruby on Rails app you need a server that installs the gems from Gemfile and Gemfile.lock, builds the assets and starts the app on the port from the PORT environment variable, bound to 0.0.0.0. The app key (the contents of master.key, or SECRET_KEY_BASE) and the DATABASE_URL connection string belong in environment variables, not in the code folder. The simplest route is to upload the code to Netrun: it detects Rails on its own, installs the dependencies, builds the project and gives you a public HTTPS link. The database either runs next to the app as a separate service or comes from outside.

The usual way to deploy a Rails app is a long checklist: rent a VPS, install the right Ruby version, bundle the gems, configure Puma, put nginx in front of it, issue a certificate, bring up a database, remember to precompile the assets and find somewhere safe to keep the key Rails uses to decrypt its own credentials. Every item is simple on its own, but together they cost an evening, plus another evening spent working out why the site shows the standard Rails error page instead of your app.

Netrun removes that part: you upload the code, the platform sees the Gemfile, installs the dependencies, builds the project and issues a public HTTPS link. Below is what to prepare in the project itself so it works the first time, and what usually keeps the site from opening.

  1. Put Gemfile and Gemfile.lock in the root#

    Both files belong in the project root: they tell the platform this is a Ruby on Rails app and pin the exact gem versions the project runs on. Do not delete Gemfile.lock or add it to your ignore list. Without it versions can drift and the build breaks even though everything worked locally. Leave the installed gems out: there is no need to ship vendor/bundle in the archive.

  2. Let the platform set the port and the host#

    The app has to listen on the port from the PORT environment variable and bind to 0.0.0.0, not to the familiar 3000 on localhost. A hard-coded port is the number one reason a link does not open after deploy: the app is running, just not where traffic arrives. The stock config/puma.rb already reads the port from the environment, so in most cases the right move is to change nothing and not override it.

  3. Move the app key into secrets#

    The config/master.key file, and everything it decrypts, is a secret: it must not end up in the archive or the repository. Copy the contents of master.key into the RAILS_MASTER_KEY value during project setup, or set SECRET_KEY_BASE instead if you do not use encrypted credentials. Netrun stores these values encrypted and passes them in as environment variables, so Rails reads them the usual way. Set RAILS_ENV to production at the same time so the app runs in production mode.

  4. Drop everything that gets built during deploy#

    Assets are compiled on our side while the project is published, so there is no reason to precompile locally and upload the result. Leave vendor/bundle, node_modules, the contents of tmp and log, and any previously compiled files in public/assets out of the archive: they bloat the upload and can shadow the fresh build with a stale one. In a GitHub repository these folders are usually listed in .gitignore already, so nothing extra is needed.

  5. Decide where the database lives#

    There is no managed database as a separate service here, so you have two options. One: run the database next to the app as its own service in a docker-compose file (up to five connected services in one project), and give it a named volume, otherwise the data is wiped on the first code update. Two: use an external database and enter its connection string during setup as DATABASE_URL, which Rails picks up without any changes to config/database.yml. SQLite only works for a small project, and only if the database file lives in the persistent /data folder.

  6. Upload the code, run migrations and grab the link#

    Upload the project as a ZIP archive or import a repository from GitHub, including a private one. Migrations run from your start command: put a Procfile in the root, a single line that says how to boot the app, and call rails db:migrate in it before the server starts. Build and boot logs stream in your dashboard in real time, so an error shows up immediately instead of as a blank page, and once the deploy finishes your Rails site opens at its own HTTPS address.

The result: your Rails site opens at its own address over a secure connection, with no VPS to rent, no web server to configure and no certificate to renew by hand. On the free plan the site sleeps while nobody uses it and wakes up on the first request, so that first response after a pause is a little slower. On the Pro plan there is no idle downtime and you can attach your own domain. Try Netrun.

Common questions

Where do I put master.key if it cannot go into the repository?

Open config/master.key, copy the single line inside it and enter it during project setup as the value of RAILS_MASTER_KEY. The value is stored encrypted and passed in as an environment variable, while the file itself stays out of the archive and the repository. If you do not use encrypted credentials, set SECRET_KEY_BASE instead, because Rails refuses to boot in production without one of them.

Do I need to precompile assets and upload public/assets?

No. Assets are compiled on our side while the project is built, so there is nothing to prepare locally. It is better to remove an old compiled folder from the archive: it makes the upload heavier and can shadow the fresh build with a previous version. If your asset build is unusual, call it from your own start command in the Procfile before the server boots.

How do I run database migrations after deploying?

There is no terminal inside the project, so migrations have to run automatically when the app starts. The simplest way is a Procfile in the root that calls rails db:migrate before booting the server, so tables are created and updated on every deploy. The other option is to trigger migrations from your own startup code.

Can I stay on SQLite instead of PostgreSQL?

You can, if the project is small and the database file lives in the persistent /data folder. A file sitting next to the code is recreated on every deploy and every record in it is lost. Note that projects with their own docker-compose have no /data folder — there persistence comes from a named volume in your own file. For anything that will grow, start with PostgreSQL as a separate service or an external database.

How do I run Sidekiq and background jobs?

Sidekiq needs Redis, so a project like that is described with a docker-compose file: the app, Redis and a separate worker service, up to five connected services in one project. Pass the Redis connection string as an environment variable, like any other secret. If background work is rare, it is often simpler to skip Sidekiq and do the work inside the app.

Why does the site return a 500 error right after deploy?

Usually the app key is missing (RAILS_MASTER_KEY or SECRET_KEY_BASE), or the migrations never ran, so the app boots and then fails on the first query. The real cause is in the logs in your dashboard: they show the actual Rails error rather than the generic error page. The third most common cause is an app listening on its own port instead of the one from PORT.

Which languages and technologies are supported?

Python, Node.js, Go, Rust, Ruby, PHP, Java, .NET, Deno, Bun, Elixir, static sites and bash scripts. You can bring your own Dockerfile or docker-compose, but more often the stack is detected from your code automatically.

Can I run several services at once?

Yes. With docker-compose you can bring up to five connected services in one project — for example, an app together with a database.

Can I connect my own domain?

Yes, on the Pro plan, and not just one: you can connect as many of your own domains to a website as you need. Open the “Domains” tab on the project page, enter the domain you bought from a registrar, and add the DNS record shown in the hint — every next domain is added the same way. Once the domains are ready, press “Check”: Netrun checks them all at once and issues a separate HTTPS certificate for each, so a hiccup with one domain does not hold up the others. The site opens at any of your addresses, and the Netrun link stays as a backup. If you connect a whole domain (for example myshop.com), you can add one more record so the site also opens with www. This is for websites — a bot or a background script does not need a domain.

Why does my website sometimes sleep?

On the free plan, websites sleep after being idle and wake up in a couple of seconds on the first request. On the Pro plan your project runs without sleeping.

Get your own project online

Upload your code, answer a couple of questions and get a working link. There is a free plan

Try Netrun
All blog articles