DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
VGSources
Blog

How to Deploy a Rails App with Puma and Nginx on a VPS

Set up a Rails app behind Nginx with Puma and systemd on an Ubuntu VPS, then release, verify, tune, and roll back safely.
Length11 min Posted Quest giverVGSources Team

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable hand-managed layout is client → Nginx on ports 80/443 → Puma on a private localhost port or Unix socket → Rails → database and other services. Nginx owns the public hostname, TLS, static files, and proxying; Puma runs the Rails process under a non-privileged account and is supervised in the foreground by systemd. This guide shows how to build that arrangement on an Ubuntu LTS VPS, release code safely, test each layer, and recover when a deployment fails.

Understand the deployment before changing the server

Puma is Rails’ default application server and is included in a generated Rails Gemfile. Nginx is placed in front of it because a reverse proxy can terminate TLS, serve files from Rails’ public directory, preserve request headers, and keep the application listener off the public network interface.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A browser should never need to know the Puma endpoint. Nginx receives the request for your domain, serves a matching static file when possible, and sends dynamic requests to the upstream endpoint. Puma then loads the production Rails environment and talks to the database, cache, mail service, and job system.

Choose the boundaries

  • Public: Nginx listens on TCP ports 80 and 443 and matches the real hostname in server_name.
  • Private: Puma binds to 127.0.0.1 or a Unix socket owned by the application account.
  • Persistent: the database, uploaded files, credentials, and any external services must survive a code release.
  • Supervised: systemd starts Puma at boot, keeps it in the foreground, restarts it after an unexpected exit, and exposes logs through the journal.

The exact Ruby version, database, paths, TLS tooling, firewall rules, and VPS networking depend on the application and distribution. Treat the examples below as a pattern to adapt, not as values to copy blindly.

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Provision and harden an Ubuntu LTS VPS

Create an application account and establish access

Use an Ubuntu LTS image, create a deploy user, and keep day-to-day application processes away from root. Install your SSH key for that account, verify that a second administrative session works, and only then tighten the SSH policy. Apply the host firewall so that SSH is reachable from your administration network and HTTP/HTTPS are reachable from the Internet. Do not close the original root session until the new login and recovery path have been tested.

Set the server’s time zone and time synchronization according to your operations policy. Consistent timestamps make Rails, Nginx, and systemd logs useful when a release goes wrong. Create a stable application layout such as /var/www/arcade/releases, /var/www/arcade/shared, and a /var/www/arcade/current symlink. Keep shared credentials, uploaded files, and other persistent data outside individual release directories.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install the versions the application actually requires

Read the repository’s .ruby-version and deployment documentation before installing Ruby. A system Ruby that happens to be available on the VPS is not a safe substitute. Install the matching Ruby and Bundler, then verify both as the deploy user. Install build packages and database client libraries required by the Gemfile, and make sure the production database is reachable before the first web start.

Store secrets in the host environment, a systemd environment file with suitable permissions, or a dedicated secret manager. Do not commit SECRET_KEY_BASE, database passwords, cloud credentials, or Rails encrypted-key files to the repository.

Prepare a production release

Build a release in a new directory, validate it, and switch the current symlink only after the files are ready. This makes rollback a pointer change instead of a reconstruction on a half-updated tree.

Rank #2
Sale
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
  1. Fetch the exact Git revision intended for production and record its commit ID.
  2. Run bundle install with production settings and without development or test groups.
  3. Export RAILS_ENV=production and every credential required by the application. Confirm that Rails can decrypt credentials before starting Puma.
  4. Run the application’s database preparation or migration command. Review destructive migrations separately and decide whether they are backward-compatible with the currently running release.
  5. Compile assets when the application uses an asset pipeline or JavaScript build. Confirm that the generated files are present under the release’s public tree or in the configured asset store.
  6. Link shared uploads, logs, sockets, and other persistent paths into the release.
  7. Run a boot check, such as loading the production environment or invoking a non-destructive health task, before moving the current symlink.

Keep the previous release available until the new one has passed external checks. A rollback is only useful if the old code, compatible dependencies, and required assets still exist.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure Puma for the VPS

Put the application’s production settings in config/puma.rb. The following example uses a Unix socket, five threads per worker, and automatic worker selection as a starting point:

environment 'production'
threads 5, 5
workers :auto
preload_app!
bind 'unix:///var/www/arcade/shared/tmp/sockets/puma.sock'
plugin :tmp_restart

Create the socket directory before starting the service and ensure that the Nginx worker can access the resulting socket. If a Unix socket complicates permissions or orchestration, bind Puma to an unused loopback TCP port instead, for example 127.0.0.1:3000, and use that exact endpoint in Nginx.

Choose single or cluster mode deliberately

Puma’s deployment guidance considers single mode suitable for a VPS with one CPU core. When more than one core is available, cluster mode can use the available CPU resources; workers :auto is a starting point when concurrent-ruby is available. Puma documents five threads per worker as its default and a reasonable starting point, but workload and memory determine the correct values.

Decision Starting guidance What to measure
One CPU core Single mode Request latency, CPU saturation, and restart time
More than one CPU core Cluster mode; try workers :auto when supported Queue time, total resident memory, and per-worker CPU
Thread count Five threads per worker is Puma’s documented starting point Latency, database wait time, and memory under concurrent traffic

Each worker adds memory. Increasing workers or threads without checking the database connection pool can trade a faster queue for connection exhaustion. Start conservatively on a small VPS, watch memory and swap, and change one setting at a time. Background jobs can compete with web workers for CPU and memory, so include their burst behavior in the measurement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Run Puma under systemd

Puma’s current deployment model is a foreground process supervised by a process monitor. Daemonization was removed in Puma 5; do not copy older tutorials that pass a --daemon option. Systemd supplies boot ordering, restart handling, status, and journal logs.

Create a unit such as /etc/systemd/system/arcade-puma.service and replace every path with the values from your server:

[Unit]
Description=Arcade Rails Puma
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/arcade/current
Environment=RAILS_ENV=production
EnvironmentFile=-/var/www/arcade/shared/config/production.env
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -C /var/www/arcade/current/config/puma.rb
Restart=always
RestartSec=5
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target

ExecStart must be an absolute executable path because systemd does not search the interactive shell’s PATH. Find the actual Bundler path as the deploy user and use that path, or call the absolute Ruby-manager shim used by your installation. The WorkingDirectory, environment file, and Puma configuration must all point to the active application layout.

Load and start the unit with:

sudo systemctl daemon-reload
sudo systemctl enable arcade-puma.service
sudo systemctl start arcade-puma.service
sudo systemctl status arcade-puma.service
sudo journalctl -u arcade-puma.service -e

After changing the unit or a referenced path, run daemon-reload again and use restart. A failed start usually appears immediately in systemctl status and the journal: an invalid Ruby path, missing credentials, a non-writable socket directory, or a migration/boot exception is more useful than the generic systemd failure state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure Nginx as the public reverse proxy

Create an Nginx site whose upstream exactly matches the Puma bind endpoint. This example serves Rails’ public files and proxies everything else to a Unix socket:

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
upstream arcade_puma {
    server unix:/var/www/arcade/shared/tmp/sockets/puma.sock;
}

server {
    listen 80;
    server_name play.example.net;
    root /var/www/arcade/current/public;

    location / {
        try_files $uri $uri/ @arcade;
    }

    location @arcade {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_pass http://arcade_puma;
    }
}

server_name must be the hostname users actually request, and root must be the active release’s public directory. The Rails reverse-proxy pattern uses an upstream, try_files, host and forwarded-client headers, proxy_redirect off, and proxy_pass; adapt timeout and request-body limits to the application rather than copying an arbitrary internet configuration.

Check socket permissions and reload safely

Nginx must be able to traverse every parent directory and read/write to the socket as required by the chosen Puma setup. If Nginx reports permission denied, inspect directory ownership and mode before changing them broadly. Keep the socket in a shared path so a release switch does not orphan the endpoint.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo nginx -t
sudo systemctl reload nginx
curl -I http://127.0.0.1/

Run the syntax test before every reload. Test the site locally with the intended Host header if the server hosts more than one domain, then test the public hostname after DNS points to the VPS. A successful Nginx reload does not prove that Puma or Rails is healthy; the local request and logs must agree.

Add HTTPS after DNS is correct

Point the domain’s DNS records to the VPS, verify that the hostname resolves to the expected address, and then issue a certificate with the certificate tooling approved for your distribution and operations policy. The exact commands vary by Ubuntu release and certificate client. Once the certificate is active, add a port 443 server with the certificate paths and redirect port 80 to HTTPS. Keep the forwarded scheme header consistent so Rails can generate secure URLs and cookies correctly.

Do not test certificate automation against a hostname that still resolves elsewhere. Confirm renewal status and keep an emergency procedure for restoring the previous Nginx configuration if a renewal or reload fails.

Best Value
Sale
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Release and restart without guessing

A safe release separates file preparation, database changes, process restart, and external verification. A practical order is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Build and validate the new release directory while the current version serves traffic.
  2. Run dependency installation, compatible migrations, and asset compilation.
  3. Link shared data and verify ownership.
  4. Point current at the new release.
  5. Restart the application service: sudo systemctl restart arcade-puma.service.
  6. Check systemctl status and the Puma journal immediately.
  7. Request the health endpoint through Nginx, then exercise authentication, a database-backed page, an asset, an upload path, and any critical API endpoint.
  8. Only after those checks, remove old releases according to your retention policy.

Systemd sends a stop signal and starts the configured foreground process again. The duration of the interruption depends on boot time, worker count, migrations, and application initialization; do not promise zero downtime unless your topology and restart strategy have been tested for it. For a release that must be reversible, keep the previous symlink target and its dependencies until the new process has handled real requests.

Rollback procedure

  1. Stop traffic changes and record the failing release commit and first error timestamp.
  2. Point current back to the last known-good release.
  3. Restart arcade-puma.service and inspect the journal.
  4. Verify the health endpoint, a database query, static assets, and the public hostname through Nginx.
  5. Do not automatically reverse a database migration. Restore data or apply a specifically designed down migration only after checking whether the failed release changed the schema incompatibly.

Verify every layer before calling the deployment complete

  • Process: systemctl status arcade-puma.service is active, and the journal contains a successful boot rather than a crash loop.
  • Proxy: Nginx syntax passes, its access log records the request, and its error log is clean for the tested paths.
  • Application: the health endpoint returns the expected status, Rails can connect to the production database, and credentials decrypt correctly.
  • Static content: CSS, JavaScript, images, and fingerprinted assets return without a proxy fallback or 404.
  • Stateful features: uploads use persistent storage, sessions behave correctly, and background jobs are running in their intended service rather than inside a web worker.
  • Network: the public hostname resolves to this VPS, HTTP redirects as intended, HTTPS presents the expected certificate, and Rails sees the correct host and scheme.
  • Recovery: the previous release, service commands, log locations, and rollback owner are documented.

Troubleshoot by symptom

Symptom Likely layer Checks and fixes
502 Bad Gateway Nginx-to-Puma connection Check Puma status and journal, confirm the socket or loopback port in both configurations, and inspect socket ownership and parent-directory permissions.
Systemd exits immediately Ruby or Rails boot Run the absolute ExecStart command as the service user, verify WorkingDirectory, Ruby version, Bundler path, environment variables, and credentials.
Assets return 404 Release or Nginx root Confirm compilation completed, files exist under the active public directory, and Nginx’s root follows the current release.
Redirect loop or insecure cookies Forwarded scheme and TLS Preserve X-Forwarded-Proto, verify Rails trusted-proxy settings, and ensure the HTTPS server and HTTP redirect do not point at each other.
Database connection exhaustion Puma sizing or pool configuration Compare worker/thread concurrency with the Rails pool and database limits; reduce concurrency or increase capacity deliberately rather than masking the error with retries.
Uploads disappear after deploy Release layout Move uploads to a shared or external persistent store and link that path into every release.
High memory or swap activity Worker count and workload Reduce workers, check per-worker memory, account for background jobs, and measure again before increasing concurrency.

Tune Puma only after observing production behavior

Use request queue time, latency, CPU utilization, resident memory, database wait time, job bursts, and restart duration as the decision signals. More workers can improve CPU utilization on a multi-core VPS but multiply memory consumption. More threads can help workloads that spend time waiting on I/O, yet they also increase simultaneous database demand. A small VPS should usually begin with the documented five-thread starting point and a conservative worker count, then change settings in controlled releases.

Keep the database pool large enough for the chosen web concurrency without exceeding the database’s connection limit, while reserving capacity for migrations, console sessions, and background jobs. If the machine is consistently memory-bound, adding workers is the wrong fix even when CPU is idle.

Know when a hand-managed VPS is the right choice

This architecture gives an operator direct control over Ubuntu, Nginx, systemd, Puma, filesystem layout, and release timing. It is useful when you need that control or must integrate with an existing server. The current Rails getting-started guidance also presents Kamal, Docker, and an Ubuntu LTS server as viable deployment paths. Those approaches can standardize packaging and orchestration, but they change where networking, secrets, health checks, TLS, and rollbacks are configured. Choose one operating model and document it; mixing assumptions from container deployment guides with a host-managed systemd service is a common source of broken releases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Final deployment checklist

  • Ubuntu LTS is patched, SSH access and firewall rules are tested, and the deploy user is non-privileged.
  • The Ruby version matches .ruby-version; production dependencies and secrets are available.
  • Migrations and assets were prepared in a new release directory.
  • Puma binds privately, uses measured worker/thread settings, and starts through an absolute systemd command.
  • Nginx points at the exact socket or port, serves the active public directory, preserves host and forwarded headers, and passes nginx -t.
  • DNS and HTTPS are verified, including the HTTP redirect and certificate renewal path.
  • Health, database, assets, uploads, jobs, logs, and rollback have all been tested.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More quests from Patch Notes

  1. How to Set Up a RedM (RDR2) Server in 2026: License Key, txAdmin and server.cfg, Step by StepBlog11min
  2. Best RedM (RDR2) Server Hosting in 2026: Comparing Four Hosts on Slots, Memory and PriceBlog10min
  3. How to Host a Mindustry Server in 2026: server-release.jar, Port 6567 and the Commands That MatterBlog7min
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.