So on the server for work we use apache2+passenger to host all our rails servers. We now have about 10-ish, not too much, not all are used heavily, all are long-living, most are still rails 4. On my own server, with a similar setup, the rails versions vary from 4 to 6.
Recently I started a new project, and of course used rails 6. And I had the awesome idea to try out stimulus-reflex as this seems an interesting addition in the js front-end world. It really is a very interesting and different approach, and since the new/upcoming version 3.3 includes morphs, actually well-suited for our use-case which almost always involves a leaflet map (so we definitely need control over which area of the page to refresh). It works! Great. I will write in more detail about that at some other time.
So I had a working part of the website, enriched using stimulus/stimulus-reflex, and now I wanted to deploy it.
Only to realise ... passenger
does not support ActionCable
on apache2
. ActionCable
is one of those new tools I still need to investigate in detail, but yes, stimulus-reflex uses ActionCable
to get a highly efficient channel between the browser and the server.
So now I am presented with two options:
apache2
on our server with nginx
. Frankly: this does not feel like a bad thing to do, however I am a bit hesitant to do this, since this seems to be a larger operation and will cause some down-time for our other applications.passenger-standalone
and make apache2
proxy to it ---ha this seems interesting!So I had to perform a few steps:
Actually, this is amazing, but in development everything just works. Of course in production there are apparently a lot of options to deploy it.
I choose for the simplest setup: let my rails process host the websockets (and thus passenger), and use postgresql as the backend (I am not using redis yet).
So in my config/routes.rb
I had to make sure we mount the ActionCable
server
mount ActionCable.server => '/cable'
In my config/environment/production.rb
I specified our allowed domains:
config.action_cable.allowed_request_origins = [ 'http://geotrax.be', /http:\/\/geotrax.*/ ]
And to use postgresql
instead of redis
is actually really simple (we were already using postgresql as our db backend). In your config/cable.yml
just write
production:
adapter: postgresql
I imagined this was easy, but it was only until I got all the steps correctly it worked. In short:
First I added the passenger
gem to my Gemfile
in the production
block and move the puma
to :development/:test
then create a Passengerfile.json
file specifying the environment, port, user and instance_registry_dir
{
// Run the app in a production environment. The default value is "development".
"environment": "production",
// Run Passenger on the given port. In this example, we use port 80,
// the standard HTTP port.
"port": 4000,
// Tell Passenger to daemonize into the background.
"daemonize": true,
// Tell Passenger to run the app as the given user. Only has effect
// if Passenger was started with root privileges.
"user": "geotrax",
"instance_registry_dir": "/srv/geotrax/tmp"
}
Somehow we still had to start passenger with the correct instance-registry-dir
(specifying it in the Passengerfile
did not work?). So we start passenger as follows
RAILS_ENV=production bundle exec passenger start --instance-registry-dir=/srv/geotrax/tmp
Then we have a running/waiting passenger instance. Now all that remains ...
This was actually the hardest part. Also the passenger document just glosses over the subject. It is easy to write an apache site configuration that passes all http requests to passenger, but the websockets ... ?
To start you need the correct modules
sudo a2enmod proxy proxy_http proxy_wstunnel rewrite
(in my case this ment just adding the proxy_wstunnel
mod, the other were already installed/used)
Then I edited my site.conf
as follows:
<VirtualHost *:80>
DocumentRoot /srv/geotrax/applications/geotrax/current/public
ServerName www.geotrax.be
ServerAlias geotrax.be
ErrorLog /srv/geotrax/applications/geotrax/current/log/error.log
CustomLog /srv/geotrax/applications/geotrax/current/log/access.log combined
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule /(.*) "ws://127.0.0.1:4000/$1" [P,L]
ProxyPass / http://127.0.0.1:4000/
ProxyPassReverse / http://127.0.0.1:4000/
ProxyRequests Off
</VirtualHost>
Since we are using both http and websockets from the same domain, we are using the rewrite rules as explained in mod_proxy_wstunnel documentation
This took me a #$@!#$$%@#@ while to figure all out, I hope this helps someone to get started a little quicker (even if it is me the next time).
Next step: switch out apache2 and use nginx (but for now it is a little less urgent).
Comments
Add comment