I'm currently trying to deploy a Rails 5 app to production on a local server (not a VPS!). I decided to go for Puma as application server and nginx as reverse proxy. In development, everything of the Rails app is working fine. The app also includes one subpage using ActionCable to send updates to the client, which are shown in a log there. The app does not use a database, as there is no need to store something in it. Additionally the project needs to use SSL.
When I try to launch it with the current settings, opening the URL of the website gets me the message of not being able to establish a connection to the server. But in the logs I can actually see the requests getting handled by nginx, just nothing happens afterwards. I'm not very familiar with nginx and puma, but from the log I would guess that ActionCable might be the problem here?
Update 29th of march:
This information might be helping: The system on the server is Debian 9, the nginx version is 1.10.3, rails 5.1.4 and puma 3.9.1.
I also have some more for nginx. I did a strace for the nginx worker while I was trying to access the website:
>>> strace -f -s 512 -a 512 -o /tmp/nginx.out -p 23518ls
23518 recvfrom(11, "\26", 1, MSG_PEEK, NULL, NULL) = 1
23518 read(11, "\26\3\1\2\0\1\0\1\374\3\3\250\365,\30\333\35\37\26\1\240R\25\246\310\10\356\20z\357M\n)\356\364E\26\350L\336\266k\364 \267\23\322\2666\20\23H\257\274U\0\227}PH_\340\352\342\245\263\215:1\"\326U\1773\202\227\0\36\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\23\300\24\0003\0009\0/\0005\0\n\1\0\1\225\0\0\0$\0\"\0\0\37website-url-was-here.com\0\27\0\0\377\1\0\1\0\0\n\0\n\0\10\0\35\0\27\0\30\0\31\0\v\0\2\1\0\0#\0\340\236L\256\5\352\303t\10R\33L\200L\253n\363\1\24:\250\4\231\204\242\3769\273\326\35C\202\25\234R\35\343\0bYM\341\214\256\4S\32\32\2542V\313\3658G\320\215\314\273\323\243\327:N\200\227\266\212\2463\311\36_\31sy\3\347\31@\327\254k\300\344\215\336\263\207\376|30Z\317:r;~#4\34\340\37sy$\231\310\240\217\266\222\311(\372r\213_\"\220W.\343\363\214+/%p\25\272\6\365\227t\221\303\256\33Q\21\344k\372\334\343W[\206\235\300\332\276{\3205#\253\351bh\3629j\231\276\216\325-M\233\224Q\323i\347\312Tt\366h\277_\223\331\236\22\372\350\324j6R\3164X\312F\362OF\7\365\225\3272\353D4\353O@\370\37\345\260b*\200\37\242\247\31p\0\20\0\16\0\f\2h2\10http/1.1\0\5\0\5\1\0\0\0\0\0\r\0\30\0\26\4\3\5\3\6\3\10\4\10\5\10\6\4\1\5\1\6\1\2\3\2\1\0\25\0001\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 16709) = 517
23518 getpid() = 23518
23518 getpid() = 23518
23518 write(11, "\26\3\3\0d\2\0\0`\3\3a\274\256\7\v\303\275\327\v\21gPo\1\342\311e\303\310\252,]\213\223+\332\325\221\324\327S\371 \267\23\322\2666\20\23H\257\274U\0\227}PH_\340\352\342\245\263\215:1\"\326U\1773\202\227\300/\0\0\30\377\1\0\1\0\0\27\0\0\0\20\0\v\0\t\10http/1.1\24\3\3\0\1\1\26\3\3\0(\372)\17\301\347\237c\204\321\32_J\371i\31\332N\252R\227\220\22e\0109Y3\344]?\207\31\240Ya\377S\231\31r", 156) = 156
23518 read(11, 0x55f00c064ec3, 16709) = -1 EAGAIN (Resource temporarily unavailable)
23518 epoll_wait(8, [{EPOLLIN, {u32=2553787544, u64=140520998810776}}], 512, 58183) = 1
23518 read(11, "\24\3\3\0\1\1\26\3\3\0(\0\0\0\0\0\0\0\0yR\24\270\26\34x\264?\250\251\0344m\350c\210\357/da#C\261\211\37\335\351J\342\213\34", 16709) = 51
23518 read(11, 0x55f00c05f963, 16709) = -1 EAGAIN (Resource temporarily unavailable)
23518 epoll_wait(8, [{EPOLLIN|EPOLLOUT, {u32=2553787080, u64=140520998810312}}], 512, 58182) = 1
23518 recvfrom(10, "\201${\"type\":\"ping\",\"message\":1522309419}", 4096, 0, NULL, NULL) = 38
23518 write(3, "\27\3\3\0>\235\365\306=\362$44K\3429\240\322\262\246D\24M\271\371=\334\236\202\373\30TDI-'\225\v\343\37\341\224[\351\342NZ\340\335\355\274d~\351Z\312@\326\240\275\234g\312X\3517w", 67) = 67
23518 recvfrom(10, 0x55f00c054ec0, 4096, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
23518 epoll_wait(8, [{EPOLLIN|EPOLLOUT, {u32=2553787080, u64=140520998810312}}], 512, 58817) = 1
23518 recvfrom(10, "\201${\"type\":\"ping\",\"message\":1522309422}", 4096, 0, NULL, NULL) = 38
23518 write(3, "\27\3\3\0>\235\365\306=\362$45\3245\275\352S~\330m\244\312{\346\267\217\347\335\224\323\324n\276\304\220D\255K\16\217\317\25\322&\325J\346AV\1c\277,2\334\363\344\241\342*\367Db\361\37\216", 67) = 67
23518 recvfrom(10, 0x55f00c054ec0, 4096, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
23518 epoll_wait(8, <detached ...>
Maybe this is helping? Also I found this in the puma error log:
=== puma startup: 2018-03-29 09:34:16 +0200 ===
[2018-03-29 09:34:24.505] ERROR -- Specified 'redis' for Action Cable pubsub adapter, but the gem is not loaded. Add `gem 'redis'` to your Gemfile (and ensure its version is at the minimum required by Action Cable).: nil
Doesn't ActionCable also work without redis? I do not have it installed.
This is from the logs:
172.19.28.1 - - [27/Mar/2018:16:13:49 +0200] "GET /cable HTTP/1.1" 301 185 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
and
host, request: "GET /cable HTTP/1.1", upstream: "http://unix:/path/to/app/shared/sockets/puma.sock:/500.html", host: "hips-wordpress.helmholtz-hzi.de:9292"
2018/03/27 15:36:06 [error] 15944#15944: *154 connect() to unix:/path/to/app/shared/sockets/puma.sock failed (111: Connection refused) while connecting to upstream, client: 172.19.28.1, server: local
config/environments/production.rb:
[...]
# Mount Action Cable outside main process or domain
config.action_cable.url = [/ws:\/\/*/, /wss:\/\/*/]
config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/]
#Use of SSL
config.force_ssl = false
[...]
config/puma.rb:
#!/usr/bin/env puma
# directory '/path/to/app/'
# Change to match your CPU core count
workers 2
# Min and Max threads per worker
threads 0, 1
app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"
# Default to production
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env
# Set up socket location
bind "unix://#{shared_dir}/sockets/puma.sock"
# Logging
stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true
# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restartq
config/nginx.cfg:
events {
worker_connections 1024;
}
http {
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/path/to/app/shared/sockets/puma.sock;
}
server {
listen 9292 ssl;
server_name app.de ;
ssl_certificate /path/to/app/config/cert/certificate.pem ;
ssl_certificate_key /path/to/app/config/cert/public_key.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
root /path/to/app;
try_files $uri/index.html $uri @app;
location @app {
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://app;
}
location /cable {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
}
To start everything I use a startup script:
#!/bin/bash
PATH=/path/to/app
cd $PATH
nginx -c config/nginx.cfg
export SECRET_KEY_BASE= <secret_key_base>
export RAILS_SERVE_STATIC_FILES=true
RAILS_ENV=production rails assets:precompile
puma -vvv -C config/puma.rb
At this point I tried to fix several things already, which is why the configs are partly assembled from different tutorials and stackoverflow questions. To my understanding, SSL shouldn't be the problem, at least not from the nginx side. puma seems to never receive any requests, as the logs stay empty. and nginx seems to not be able to redirect the /cable request to puma (which is the url to subscribe to the ActionCable Channel). Did I do something wrong with the configs for ActionCable? I'm not really able to find a tutorial about how to setup a rails app using ActionCable and SSL in production with nginx/puma combination.
If you need any other information, I will include it in the question.