• Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
logo logo
  • Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
ENEN
  • 简体简体
  • 繁體繁體
Client Area

How to Deploy Ruby on Rails on Hong Kong VPS: Puma and Nginx Guide (2026)

August 29, 2026

Ruby on Rails remains a productive choice for full-stack web applications, particularly for teams that value convention-over-configuration and rapid development velocity. Deployed on a Hong Kong VPS with CN2 GIA routing, a Rails application with Puma, Nginx, and Sidekiq provides a proven production stack that scales from startup to thousands of concurrent users.


Step 1: Install Ruby via rbenv

<code">apt update && apt upgrade -y
apt install -y git curl libssl-dev libreadline-dev zlib1g-dev \
  autoconf bison build-essential libyaml-dev libncurses5-dev \
  libffi-dev libgdbm-dev libjemalloc-dev nginx postgresql \
  postgresql-contrib redis-server certbot python3-certbot-nginx ufw

# Create deploy user
useradd -m -s /bin/bash deploy

# Install rbenv as deploy user
su - deploy
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc

# Install Ruby 3.3 (latest stable)
rbenv install 3.3.3
rbenv global 3.3.3

# Install Bundler
gem install bundler --no-document

ruby --version  # Should show ruby 3.3.3

Step 2: Database Setup

<code">exit  # Back to root
sudo -u postgres psql << 'SQL'
CREATE DATABASE myapp_production;
CREATE USER myapp_user WITH PASSWORD 'StrongRailsDBPass!';
GRANT ALL PRIVILEGES ON DATABASE myapp_production TO myapp_user;
ALTER DATABASE myapp_production OWNER TO myapp_user;
SQL

Step 3: Deploy Rails Application

<code">su - deploy
mkdir -p /var/www/myapp && cd /var/www/myapp

git clone https://github.com/your-org/myapp.git .
bundle config set --local without 'development test'
bundle install

# Configure credentials
cat > /var/www/myapp/.env << 'EOF'
RAILS_ENV=production
SECRET_KEY_BASE=GENERATE_WITH_rails_secret
DATABASE_URL=postgresql://myapp_user:StrongRailsDBPass!@localhost/myapp_production
REDIS_URL=redis://:RedisPass@localhost:6379/0
EOF
chmod 600 /var/www/myapp/.env

Generate Secret Key Base

<code">bundle exec rails secret  # Copy this value to SECRET_KEY_BASE in .env

Run Database Migrations and Precompile Assets

<code">source .env
bundle exec rails db:migrate RAILS_ENV=production
bundle exec rails assets:precompile RAILS_ENV=production

Step 4: Configure Puma

<code">cat > /var/www/myapp/config/puma.rb << 'EOF'
workers ENV.fetch("PUMA_WORKERS") { 2 }
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count

preload_app!

rackup DefaultRackup
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "production" }

pid "tmp/pids/server.pid"

# Socket for Nginx
bind "unix:///var/www/myapp/tmp/sockets/puma.sock"

on_worker_boot do
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end

before_fork do
  ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
end
EOF

mkdir -p /var/www/myapp/tmp/{pids,sockets,cache,log}

Systemd Service for Puma

<code">exit  # Back to root

cat > /etc/systemd/system/puma.service << 'EOF'
[Unit]
Description=Puma HTTP Server for myapp
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/myapp
EnvironmentFile=/var/www/myapp/.env
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -C /var/www/myapp/config/puma.rb
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now puma
systemctl status puma

Step 5: Nginx Configuration

<code">cat > /etc/nginx/sites-available/myapp << 'EOF'
upstream puma {
    server unix:///var/www/myapp/tmp/sockets/puma.sock fail_timeout=0;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    root /var/www/myapp/public;

    # Serve static assets directly
    location ~* \.(ico|css|js|gif|jpe?g|png|svg|woff2|ttf)$ {
        expires max;
        add_header Cache-Control "public, immutable";
        gzip_static on;
        try_files $uri =404;
    }

    # Rails asset pipeline output
    location /assets {
        gzip_static on;
        expires max;
        add_header Cache-Control "public, immutable";
        try_files $uri =404;
    }

    location / {
        try_files $uri/index.html $uri @puma;
    }

    location @puma {
        proxy_pass http://puma;
        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_set_header X-Real-IP $remote_addr;
        proxy_redirect off;
        proxy_read_timeout 60s;
    }

    client_max_body_size 50m;
    keepalive_timeout 10;
    error_page 500 502 503 504 /500.html;
}
EOF

ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
certbot --nginx -d yourdomain.com -d www.yourdomain.com
nginx -t && systemctl reload nginx

Step 6: Sidekiq Background Jobs

<code">cat > /etc/systemd/system/sidekiq.service << 'EOF'
[Unit]
Description=Sidekiq Background Worker
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/myapp
EnvironmentFile=/var/www/myapp/.env
ExecStart=/home/deploy/.rbenv/shims/bundle exec sidekiq -e production -C config/sidekiq.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
<code">cat > /var/www/myapp/config/sidekiq.yml << 'EOF'
:concurrency: 5
:queues:
  - [critical, 3]
  - [default, 2]
  - [low, 1]
:logfile: log/sidekiq.log
EOF

systemctl enable --now sidekiq

Example Sidekiq Job

<code"># app/jobs/order_confirmation_job.rb
class OrderConfirmationJob < ApplicationJob
  queue_as :critical

  def perform(order_id)
    order = Order.find(order_id)
    OrderMailer.confirmation(order).deliver_now
    order.update(confirmation_sent_at: Time.current)
  end
end

# Enqueue from controller:
OrderConfirmationJob.perform_later(order.id)

Step 7: Deployment with Capistrano

<code"># Gemfile — add Capistrano
gem 'capistrano', require: false
gem 'capistrano-rbenv', require: false
gem 'capistrano-rails', require: false
gem 'capistrano3-puma', require: false

bundle exec cap install STAGES=production
<code"># config/deploy.rb
lock "~> 3.19"
set :application, "myapp"
set :repo_url, "git@github.com:your-org/myapp.git"
set :branch, "main"
set :deploy_to, "/var/www/myapp"
set :linked_files, %w[.env]
set :linked_dirs,  %w[log tmp/pids tmp/cache tmp/sockets public/uploads]
set :keep_releases, 5

# config/deploy/production.rb
server "YOUR_VPS_IP", user: "deploy", roles: %w[app db web], port: 22222
<code"># Deploy from local machine:
bundle exec cap production deploy

# Capistrano:
# - Connects to VPS via SSH
# - Pulls latest code from Git
# - Installs gems (production only)
# - Runs db:migrate
# - Precompiles assets
# - Symlinks linked files (.env)
# - Restarts Puma gracefully (zero-downtime)

Rails Performance Optimisations for Asia-Pacific

<code"># config/environments/production.rb

# HTTP caching headers for Nginx proxy cache
config.public_file_server.headers = {
  'Cache-Control' => 'public, max-age=31536000'
}

# Fragment caching with Redis
config.cache_store = :redis_cache_store, {
  url: ENV['REDIS_URL'],
  connect_timeout: 30,
  read_timeout: 0.2,
  write_timeout: 0.2,
  reconnect_attempts: 1,
}

# Database connection pool optimisation
# In config/database.yml:
production:
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  checkout_timeout: 5
  prepared_statements: true  # Significant performance boost with PgBouncer disabled

Monitoring Rails in Production

<code"># Check Puma status
systemctl status puma
cat /var/www/myapp/tmp/pids/server.pid | xargs ps -p

# Check Sidekiq
systemctl status sidekiq
tail -f /var/www/myapp/log/sidekiq.log

# Rails production log
tail -f /var/www/myapp/log/production.log | grep -E "ERROR|WARN|Completed 5"

# Database connections
sudo -u postgres psql -c "SELECT count(*), state FROM pg_stat_activity GROUP BY state;"

Conclusion

Ruby on Rails with Puma, Sidekiq, and Nginx on a Hong Kong VPS provides a mature, battle-tested production stack. Puma’s multi-threaded architecture handles concurrent requests efficiently, Sidekiq processes background jobs reliably via Redis, and Capistrano automates zero-downtime deployments. CN2 GIA routing delivers your Rails application to mainland Chinese users at 30–60ms response times — a far better experience than Rails applications hosted in the US or Europe.

Deploy your Rails app: Browse Server.HK Hong Kong VPS plans — a 4 GB plan with 4 vCPU handles Puma, Sidekiq, and PostgreSQL for most Rails production workloads.

Leave a Reply

You must be logged in to post a comment.

Recent Posts

  • Self-Hosted Private Search Engine on Hong Kong VPS: SearXNG (2026)
  • WireGuard Site-to-Site VPN with Hong Kong VPS: Connect Your Offices (2026)
  • Deploy Elixir Phoenix on Hong Kong VPS: Real-Time Apps for Asia (2026)
  • GPU Dedicated Server in Hong Kong: AI Model Training and Inference (2026)
  • Vector Database on Hong Kong VPS: Build a RAG System with pgvector (2026)

Recent Comments

  1. Hong Kong VPS Uptime and SLA: What 99.9% Uptime Really Means for Your Business (2026) - Server.HK on How to Monitor Your Hong Kong VPS: Uptime, Performance, and Alert Setup Guide (2026)
  2. Best Hong Kong VPS Providers in 2026: Compared by Speed, Routing, and Value - Server.HK on How to Migrate Your Website to a Hong Kong VPS: Zero-Downtime Transfer Guide (2026)
  3. vibramycin injection on How to Choose the Right Hong Kong VPS Plan: A Buyer’s Guide for 2026
  4. allopurinol for gout on CN2 GIA vs BGP vs CN2 GT: What’s the Real Difference for China Connectivity?
  5. antibiotics online purchase on How to Set Up a WordPress Site on a Hong Kong VPS with aaPanel (Step-by-Step 2026)

Knowledge Base

Access detailed guides, tutorials, and resources.

Live Chat

Get instant help 24/7 from our support team.

Send Ticket

Our team typically responds within 10 minutes.

logo
Alipay Cc-paypal Cc-stripe Cc-visa Cc-mastercard Bitcoin
Cloud VPS
  • Hong Kong VPS
  • US VPS
Dedicated Servers
  • Hong Kong Servers
  • US Servers
  • Singapore Servers
  • Japan Servers
More
  • Contact Us
  • Blog
  • Legal
© 2026 Server.HK | Hosting Limited, Hong Kong | Company Registration No. 77008912
Telegram
Telegram @ServerHKBot