Search code examples
rubyapacheubuntusinatrapuma

How to deploy Ruby (Sinatra Framework) using Apache with Puma on Ubuntu?


I am running an Ubuntu 22.04 server on Linode and trying to deploy a simple Sinatra app using Apache with Puma, but currently, I am only able to display the index page, so I believe I am missing a simple step. I'm not sure how to connect Puma to Apache, so there is probably something related to that that I am missing. Here are the key files:

/var/www/example.com/web.rb

require 'sinatra'

get '/' do
  "Hello World"
end

/var/www/example.com/config/puma.rb

workers 2
threads 5, 5

preload_app!

port        5000
environment 'development'

/etc/apache2/sites-available/example.conf

<VirtualHost *:80>
     ServerAdmin info@example.com
     ServerName sinatra.example.com

     DocumentRoot /var/www/example.com

     <Directory /var/www/example.com>
          DirectoryIndex web.rb
          Allow from all
     </Directory>

     ErrorLog /var/www/example.com/logs/errors.log
     CustomLog /var/www/example.com/logs/access.log combined

     RewriteEngine on
     RewriteCond %{SERVER_NAME} =sinatra.example.com
     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

I have then run these commands without issue:

bundle install a2ensite systemctl reload apache2


Solution

  • You need to set up a reverse proxy (as @konstantin-strukov mentioned). Here is the full list of files that I set up and the commands I ran (not including installing apache and ruby), so that there is no ambiguity.

    /var/www/example/web.rb

    require 'sinatra'
    
    get '/' do
      "Hello World"
    end
    

    /var/www/example/Procfile

    web: bundle exec puma -C config/puma.rb
    

    /var/www/example/GEMFILE

    source 'http://rubygems.org'
    ruby '3.0.4'
    gem 'sinatra', '~>2'
    gem 'puma', '~>5'
    

    Note: Sinatra recently released a 3.0.0 version and Puma released a 6.0.0 and this caused conflicts with Rack, so I needed to use the previous version to get it to work.

    /var/www/example/config.ru

    require './web'
    run Sinatra::Application
    

    /var/www/example/config/puma.rb

    workers 2
    threads 1, 2
    
    preload_app!
    
    port        5000
    environment "development"
    
    app_dir = File.expand_path("../..", __FILE__)
    bind "unix://#{app_dir}/tmp/puma/puma.sock"
    stdout_redirect "#{app_dir}/logs/puma.stdout.log", "#{app_dir}/logs/puma.stderr.log", true
    pidfile "#{app_dir}/tmp/puma/pid"
    state_path "#{app_dir}/tmp/puma/state"
    directory "#{app_dir}/"
    activate_control_app "unix://#{app_dir}/tmp/puma/pumactl.sock"
    prune_bundler
    

    /etc/apache2/sites-available/example.conf

    <VirtualHost *:80>
         ServerAdmin info@example.com
         ServerName sinatra.example.com
         ProxyRequests Off
         <Proxy *>
            Order Allow,Deny
            Allow from all
         </Proxy>
         ProxyPass / http://localhost:5000/
         ProxyPassReverse / http://localhost:5000/
         ProxyVia On
    
         DocumentRoot /var/www/example
    
         <Directory /var/www/example>
              DirectoryIndex web.rb
              Allow from all
         </Directory>
    
         ErrorLog /var/www/example/logs/errors.log
         CustomLog /var/www/example/logs/access.log combined
    
         RewriteEngine on
         RewriteCond %{SERVER_NAME} =sinatra.example.com
         RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
    </VirtualHost>
    

    /etc/systemd/system/puma.service

    [Unit]
    Description=Puma HTTP Server
    After=network.target
    Requires=puma.socket
    
    [Service]
    Type=notify
    WatchdogSec=10
    WorkingDirectory=/var/www/example
    ExecStart=/usr/local/bin/puma -C /var/www/example/config/puma.rb
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    /etc/systemd/system/puma.socket

    [Unit]
    Description=Puma HTTP Server Accept Sockets
    
    [Socket]
    ListenStream=0.0.0.0:5000
    
    # Socket options matching Puma defaults
    NoDelay=true
    ReusePort=true
    Backlog=1024
    
    [Install]
    WantedBy=sockets.target
    
    1. cd /var/www/example

    2. bundle install

    3. mkdir /var/www/example/logs

    4. mkdir /var/www/example/tmp

    5. mkdir /var/www/example/tmp/puma

    6. chmod 777 /var/www/example/logs

    7. chmod 755 /var/www/example/tmp

    8. chmod 755 /var/www/example/tmp/puma

    9. a2ensite example

    10. a2enmod

      proxy proxy_ajp proxy_http rewrite deflate headers proxy_balancer proxy_connect proxy_html

    11. systemctl daemon-reload

    12. systemctl enable puma.service

    13. systemctl enable puma.socket

    14. systemctl start puma.socket

    15. systemctl start puma.service

    16. systemctl reload apache2