403 Forbidden on Rails app w/ Nginx, Passenger - ruby-on-rails

First off, apologies: I know the 403 Forbidden question is a common one for Rails/Nginx installs, but none of the answers I've read so far have solved it for me.
Disclaimer: This is my first time deploying a Rails app somewhere that isn't Heroku. Please be gentle. ;)
Situation: I have a Rails app running on an Ubuntu 12.04 server, running Nginx (installed with Passenger).
I've deployed my app to my server correctly, but when I attempt to access the site, I receive a 403 Forbidden error.
Checking my error logs, I see:
2013/10/23 22:47:01 [error] 27954#0: *105 directory index of "/var/www/colepeters.com/current/public/" is forbidden, client: 50.3…server: colepeters.com, request: "GET / HTTP/1.1", host: "colepeters.com"
2013/10/23 22:47:10 [error] 27954#0: *106 directory index of "/var/www/colepeters.com/current/public/" is forbidden, client: 184…server: colepeters.com, request: "GET / HTTP/1.1", host: "colepeters.com"
2013/10/23 22:47:12 [error] 27954#0: *107 directory index of "/var/www/colepeters.com/current/public/" is forbidden, client: 151…server: colepeters.com, request: "GET / HTTP/1.1", host: "colepeters.com"
However, when checking permissions on this directory, I see that the user I have setup to use Nginx had both read and execute permissions on it.
Here's the relevant info from my nginx.conf:
user XXXX;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
passenger_root /home/cole/.rvm/gems/ruby-2.0.0-p247/gems/passenger-4.0.21;
passenger_ruby /home/cole/.rvm/wrappers/ruby-2.0.0-p247/ruby;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name colepeters.com www.colepeters.com;
passenger_enabled on;
root /var/www/colepeters.com/current/public/;
rails_env production;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /var/www/colepeters.com/current/public;
index index.html index.htm;
# autoindex on;
}
I would greatly appreciate any help on resolving this. Thanks!
UPDATE
I have since corrected the erroneus passenger_ruby path, but the 403 Forbidden is persisting, even after restarting Nginx.

You can check the path of your passenger installation with
passenger-config --root
and the path of your ruby installation with
which ruby
then compare with the inserted in nginx.conf.

Adding passenger_enabled on; to the server directive worked for me.

I got the same error. In my case, I fixed it by removing the location / {} entry.
- or make sure that your user have permission to your rails project
...
server {
listen 80;
server_name 127.0.0.1;
passenger_enabled on;
rails_env production;
root /www/kalender/public ;
#charset koi8-r;
access_log /var/log/nginx/host.access.log;
#location / {
#root html;
#index index.html index.htm;
#}

I was running a similar setup to yours and having the same problem with my nginx.conf file. Stumbling across the Nginx pitfalls page helped me solve it.
Your file looks similar to mine, so I'll share two things you may want to try that worked for me:
first, you have the root path in both the server {} block AND the location {} block. While not necessarily a problem, according to the docs linked above "If you add a root to every location block then a location block that isn't matched will have no root." I got rid of the roots in the location blocks but kept it in the server block.
move the 'index' directives (index index.html index.htm;) out of the location block up to within the http {} block. The location blocks will inherit from this.
doing those two things and restarting the server worked for me.

The problem lies in the location / {...} section: the passenger_enabled on doesn't propagate from the server {...} into the location / {...}.
If you either remove location / {...}, or add passenger_enabled on to it, it should work.

you also have config-file for passenger called passenger.conf by default in /etc/nginx/conf.d/passenger.conf
there you have to put correct roots.
you can check the roots with these two commands
passenger-config --root
and
which ruby
so when you get these roots you have to compare them with such in your passenger.conf file and it can be e.g. smth like this
#passenger-config --root
passenger_root /usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini;
#which ruby
passenger_ruby /usr/local/rvm/rubies/ruby-2.4.0/bin/ruby;
passenger_instance_registry_dir /var/run/passenger-instreg;
so if you use this way don't forget to make in http section of your nginx.conf
include /etc/nginx/conf.d/passenger.conf
as well as inserting in server section
passenger_enabled on;

The key things are:
Remove the location block for the / section, assuming that the Rails application is accessible at /
Ensure the passenger_ruby is pointing to the rvm wrapper script for the selected ruby version
Add execute permissions to user, group and others to all the directories reaching to
/var/www/rails_app/public folder
/var
/var/www
/var/www/rails_app
/var/www/rails_app/public_foler

You are declaring the root twice inside the server block and inside the /location block as well as directing nginx to use the index directive. Also remove the "/" after public folder
try doing this
user XXXX;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
passenger_root /home/cole/.rvm/gems/ruby-2.0.0-p247/gems/passenger-4.0.21;
passenger_ruby /home/cole/.rvm/wrappers/ruby-2.0.0-p247/ruby;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name colepeters.com www.colepeters.com;
passenger_enabled on;
root /var/www/colepeters.com/current/public;
rails_env production;
#charset koi8-r;
#access_log logs/host.access.log main;
}
}

Related

Deploying multiple versions of a Rails API using nginx

I use nginx, with passenger, to serve a Rails API. In preparation for our 1.0 launch, I would like to version this API using the method described in this answer.
I have a version number that is pulled from a specification, along with capistrano recipes set up to create the following directory structure:
/var/www/foamfactory.io/dev.api.foamfactory.io
- v0
- current (points to v0.0)
- v0.0
- current (points to v0.0.15)
- v0.0.15 (this is the capistrano directory)
- current (points to latest release under releases/)
- releases
- 20210308162204 (rails directory)
Now, my nginx setup was as follows, in order to rewrite, for example, dev.api.foamfactory.io/version to dev.api.foamfactory.io/current/current/current/current/current/public (I'm working on getting this basic example working before I struggle with, e.g dev.api.foamfactory.io/v0/v0.0/version.
server {
rewrite_log on;
server_name dev.api.foamfactory.io;
access_log /var/log/nginx/dev.api.foamfactory.io-access.log;
error_log /var/log/nginx/dev.api.foamfactory.io-error.log notice;
passenger_enabled on;
passenger_ruby /home/www-data/.rvm/rubies/default/bin/ruby;
passenger_sticky_sessions on;
passenger_app_env development;
passenger_env_var SECRET_KEY_BASE redacted;
location / {
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
rewrite ^/(.*)$ /current/current/current/current/public/$1 last;
rewrite ^/v([0-9]+)/(.*)$ /v$1/current/current/current/public/$2 last;
rewrite ^/v([0-9]+).([0-9]+)/(.*)$ /v$1/v$1.$2/current/current/public/$3 last;
rewrite ^/v([0-9]+).([0-9]+).([0-9]+)/(.*)$ /v$1/v$1.$2/v$1.$2.$3/current/public/$4 last;
}
I modified this first rewrite statement to be a location/ statement:
server {
rewrite_log on;
server_name dev.api.foamfactory.io;
access_log /var/log/nginx/dev.api.foamfactory.io-access.log;
error_log /var/log/nginx/dev.api.foamfactory.io-error.log notice;
passenger_enabled on;
passenger_ruby /home/www-data/.rvm/rubies/default/bin/ruby;
passenger_sticky_sessions on;
passenger_app_env development;
passenger_env_var SECRET_KEY_BASE redacted;
location / {
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location ~ ^/(.*)$ {
rewrite ^/(.*)$ /current/current/current/current/public/$1 break;
root /var/www/foamfactory.io/dev.api.foamfactory.io/current/current/current/current/public;
}
}
I can now access the Rails app, BUT, when I try to access an endpoint (e.g. /version, as in dev.api.foamfactory.io/version, Rails reports the following error:
ActionController::RoutingError: No route matches [GET] \"/current/current/current/current/public/version\"
My suspicion is that it has something to do with the relative_url_root configuration variable inside of the Rails configuration, so inside of environments/development.rb, I modified the configuration to include:
config.relative_url_root = '/current/current/current/current/public'
However, this did not alleviate the error.
I'm wondering if someone might be able to help me with what I need to do to get this working. I feel like I'm not even sure if it's an nginx configuration problem or a Rails configuration problem at this point.

Nginx + Puma + Sidekiq web interface not showing css styles

I have an angularJS web app running in a Nginx server that sends request to a Rails API running in a Puma server. I have integrated Sidekiq 5.2.8 and everything works great but the Sidekiq web interface.
In my Nginx config file, I have a rule to pass request to the API. Please find the whole nginx.conf document:
events {
worker_connections 1024;
}
http {
upstream api.development {
# Path to Puma SOCK file, as defined previously
server unix:/tmp/puma.sock fail_timeout=0;
}
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# set client body size to 10M #
client_max_body_size 10M;
gzip on;
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
#charset koi8-r;
#access_log logs/host.access.log main;
root /Users/Rober/Projects/domain/dev/domain/app;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
# Proxy requests to the backoffice Rails API
location /api {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
#proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
rewrite ^/api(.*) /$1 break;
proxy_pass http://api.development;
}
# Rule to proxy the sidekiq web UI
location /sidekiq {
proxy_pass http://api.development;
}
# Expire rules for static content
# RCM: WPO
# Images
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
root /Users/Rober/Projects/domain/dev/domain/app;
expires 1w;
add_header Cache-Control "public";
}
# This rule is the root cause of the problems with the sidekiq css
# I have commented it for testing purposes
# CSS and Javascript
#location ~* \.(?:css|js)$ {
# root /Users/Rober/Projects/domain/dev/domain/app;
# expires 1w;
# add_header Cache-Control "public";
#}
# I have replaced the previous location above for this as suggested by #Beena Shetty.
location ~* \.(?:css|js)$ {
add_header X-debug-message "Into the location css" always;
if ($uri !~* "^/sidekiq/\w*(.*)+$") {
add_header X-debug-message "Into the location css if" always;
root /Users/Rober/Projects/domain/dev/domain/app;
expires 1w;
add_header Cache-Control "public";
}
}
# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
root /Users/Rober/Projects/domain/dev/domain/app;
expires -1;
}
}
include servers/*;
}
In Rails:
routes:
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
I have included next rule in Nginx config file and now when I request http://localhost/sidekiq I can see the web interface and navigate, but still cannot see the styles.
location /sidekiq {
proxy_pass http://api.development;
}
See screenshot.
The dev tools shows that when I load sideqik is trying to get bootstrap.css and some other css and javascript in http://localhost/sidekiq/stylesheets/bootstrap.css
What am I missing?
UPDATE:
I have found out the root cause of the problem in my nginx.conf. I have next rule that set a cache expiration time for performance purposes. If I comment this code, everything works. But how can I have both things living together?
CSS and Javascript
location ~* \.(?:css|js)$ {
root /Users/Rober/Projects/domain/dev/domain/app;
expires 1w;
add_header Cache-Control "public";
}
UPDATE 2: Just in case the problem comes from another point, I have included my whole nginx conf.
Now, with the provided config, the expiration rules in my web app are still working, but the css in the sidekiq webapp do not.
I have included two headers as debug. One when the server is accessing the location rule and the second when the server is accessing inside the if condition. When I request my home page with localhost and I check the request for my own css, such as app.css, I can see the header X-debug-message: Into the location css if, which is right.
If I request sidekiq with localhost/sidekiq I still get 404 error for css, let´s say http://localhost/sidekiq/stylesheets/bootstrap.css and I can see the header X-debug-message: Into the location css.
Current conclusions:
As soon as I include the location ~* .(?:css|js)$ rule, sidekiq css stops working. Even if the rule is empty, like:
location ~* \.(?:css|js)$ {
}
As soon as I delete or comment the whole rule, the sidekiq css works perfectly, but unfortunately this is not compatible with the expires rules that we need to include for performance purposes.
Try this:
location ~* \.(?:css|js)$ {
if ($uri !~* "^/sidekiq/\w*(.*)+$"){
root /Users/Rober/Projects/domain/dev/yanpy/app;
expires 1w;
add_header Cache-Control "public";
}
}
I wasn't able to find a fix for this, so I hacked it with the following method: I copied sidekiq's assets to the public folder and it started working ( since they're referenced by the UI ).
|- images
|-- favicon.io
|-- logo.png
|-- status.png
|- javascripts
|-- application.js
|-- dashboard.js
|- stylesheets
|-- application.css
|-- application-rtl.css
|-- application-dark.css
|-- application-rtl.min.css
|-- bootstrap.css
Mainly, these files: https://github.com/mperham/sidekiq/tree/master/web/assets

Nginx shows public directory content instead of executing Rails App

I am trying to execute my Rails Application on Nginx and Passenger but it shows the public directory content instead of executing the application.
server {
server_name 104.236.218.36;
listen 80 default_server;
root /var/www/noise/public;
passenger_enabled on;
rails_spawn_method smart;
rails_env production;
autoindex on;
}
If i remove autoindex on; i am getting the following error.
2015/02/02 06:16:06 [error] 13528#0: *3 directory index of "/var/www/noise/public/" is forbidden, client: 122.178.204.27, server: 104.236.218.36, request: "GET / HTTP/1.1", ho$
The config you show works ok for me, but maybe you have something else set wrong outside the system scope.
You could also specify the Rails app directory try adding:
passenger_app_root /var/www/noise;

rails app on nginx+passenger not showing custom error pages

I have a Rails app running on nginx 1.2.0 and passenger 3.0.7. I would like to have the custom error pages in the rails app (e.g. /rail_app/public/500.html) be displayed when the appropriate http error occurs within the app.
Here is my current nginx config file:
http {
passenger_root /usr/lib/ruby/gems/1.8/gems/passenger-3.0.7;
passenger_ruby /usr/bin/ruby;
include mime.types;
default_type application/octet-stream;
#access_log /opt/nginx/logs/access.log main;
sendfile on;
#tcp_nopush on;
server {
listen 80;
server_name localhost;
root /var/www/dashboard/current/public;
passenger_enabled on;
passenger_min_instances 1;
# listen 443;
# ssl on;
# ssl_certificate /opt/nginx/conf/server.crt;
# ssl_certificate_key /opt/nginx/conf/server.key;
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/dashboard/current/public/;
}
}
}
This configuration does not show the rails app customer error page rather just sends the http error status code to the client.
Anyone know what it takes to have nginx/passenger send the rails app custom error page to the client with the http error status code?
Please try the following:
# We use the x just because it is for all 5xx errors.
error_page 500 502 503 504 /5xx.html;
location = /5xx.html {
alias /var/www/dashboard/current/public/;
}
Reconfiguring the root directive makes no sense, as it is already set to the path you specified before. The alias ensures that the specific location is internally matched to a different location on the file system. All incoming request parameters should be passed along and if your Rails app is taking care of things at this point it should answer. Just make sure that your Rails app isn't answering with a 500 status again (I don’t know what would happen then).
Related Links
alias
You're probably missing passenger_intercept_errors on; in your nginx config
see the passenger docs for this directive for more info
The config I use:
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

nginx with passenger don't handle static assets

I have rails app running with helpfull nginx and passenger, and I want to add static page (conteins code coverage analysis tool - simplecov).
Localy this works fine (without passenger), but on the server this don't works.
My nginx.conf:
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
#speed up for linux 2.6+
use epoll;
}
http {
passenger_root /home/demo/.rvm/gems/ruby-1.9.3-p0#gm/gems/passenger-3.0.9;
passenger_ruby /home/demo/.rvm/wrappers/ruby-1.9.3-p0#gm/ruby;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name *.dev.mysite.com;
root /var/www/projects/mysite/qa/current/public;
passenger_enabled on;
rails_env qa;
charset utf-8;
error_log /var/www/projects/mysite/qa/shared/log/host.error.log;
}
#Coverage code tool (SimpleCov gem)
server {
listen 4444;
server_name coverage.mysite.com;
location / {
root /var/lib/jenkins/jobs/WebForms/workspace/coverage;
index index.html index.htm;
}
}
#Yard server
server {
listen 5555;
server_name yard.mysite.com;
location / {
proxy_pass http://127.0.0.1:8808;
}}}
And nothing receive when I try to hit to coverage.mysite.com:4444.
I think I remember coming across something similar to this on one of my rails apps.
Have you tried commenting and uncommenting the lines below?:
# in config/environments/production.rb
# Specifies the header that your server uses for sending files
#config.action_dispatch.x_sendfile_header = "X-Sendfile"
# For nginx:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
It should be near the top, around line 12 through 16.
Try that, then redploy and test in the browser.

Resources