Nginx proxy_pass then try_file - ruby-on-rails

I am setting up a Rails app with nginx in front.
What I want is first to check if the URL makes sense for Rails then serve content of the public folder.
I can't achieve this:
upstream extranet {
server localhost:3000;
}
server {
location / {
try_files #extranet $uri;
root /var/www/extranet/public;
}
location #extranet {
proxy_pass http://extranet;
proxy_read_timeout 90;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;
client_max_body_size 100m;
}
}
I get: *1 rewrite or internal redirection cycle while internally redirecting to "/" error.
It seems like try_files $uri #extranet; works but in my case it feels safer to check the Rails app first because the public folder might change.

try_files checks for the presence of a file on the local file system and cannot respond to the response code from a proxy.
Presumably, the proxy response with a 404 response if the remote page does not exist, which can be intercepted by an error_page statement.
For example:
location / {
proxy_pass http://extranet;
proxy_set_header ...
proxy_set_header ...
proxy_set_header ...
proxy_intercept_errors on;
error_page 404 = #fallback;
}
location #fallback {
root /var/www/extranet/public;
try_files $uri =404;
}
See this document for more.

Related

The URLs in the content of the page are broken when I use Nginx to proxy pass a subdirectory to a server

I am using proxy_pass in Nginx to redirect /phpmyadmin[/] to a container where PHPMyAdmin is running (the project is available here on Github). The problem is that when I use https://localhost/phpmyadmin/, I get the HTML and content of PHPMyAdmin in the correct way, but, when I drop "/" at the end of the URL, it returns me the HTML with the wrong resource URLs (such as https://localhost/favicon.ico instead of https://localhost/phpmyadmin/favicon.ico). My Nginx config file looks like this:
upstream backend {
server app1:9000;
server app2:9000;
server app3:9000;
server app4:9000;
}
upstream docker_phpmyadmin {
server phpmyadmin:443;
}
server {
server_name localhost;
listen 443 ssl http2;
root /var/www;
location ~ /phpmyadmin {
# (START) some queries don't work when modsecurity is on
modsecurity off;
# (END) some queries don't work when modsecurity is on
# (START) large databases might demand long time and large memory
client_max_body_size 100m;
client_body_buffer_size 10M;
proxy_read_timeout 6000;
proxy_send_timeout 6000;
# (END) large databases might demand long time and large memory
rewrite /phpmyadmin/?(.*)$ /$1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass https://docker_phpmyadmin;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
location / {
index index.php;
try_files $uri $uri/ /index.php;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
error_page 404 error.html;
location = /error.html {
root /var/www;
}
location ~* \.(ico|css|js|gif|jpe?g|png)$ {
expires 10d;
}
location ~* \.php$ {
try_files $uri =404;
fastcgi_pass backend;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
The same issue arises when I try to use MailCow in my project using:
location ~ /mailcow {
rewrite /mailcow/?(.*)$ /$1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass https://docker_nginx_mailcow;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto https;
# proxy_redirect off;
}

HTTP Origin header (https://example.com) didn't match request.base_url (http://example.com) rails

I am running Nginx server with the puma on https. I configured Letsencrypt for SSL verification. The problem is that the server is running fine but when I try to create a user through devise it throws this error
"HTTP Origin header (https://example.com) didn't match request.base_url (http://example.com)"
I tried to modify the nginx.conf configuration as specified over here
https://github.com/rails/rails/issues/22965#issuecomment-172929004
but still, no luck here is my configuration file
upstream puma {
server unix:///home/ubuntu/blue_whale/example/shared/tmp/sockets/gofickle-puma.sock;
}
server
{
listen 443 ssl default;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /home/ubuntu/blue_whale/example/current/public;
access_log /home/ubuntu/blue_whale/example/current/log/nginx.access.log;
error_log /home/ubuntu/blue_whale/example/current/log/nginx.error.log info;
add_header Strict-Transport-Security “max-age=31536000”;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on; # Optional
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://puma;
}
I have the exact same setup as you and mine is working with the below proxy config:
location #rails {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://rails_app;
}
I think it might be the X-Forwarded-Proto and SSL that might be causing your issue, it isn't necessary behind the proxy.

nginx: remove path from proxy_pass on named location

I have this nginx config to serve a rails app:
location ^~ /api/ {
alias /srv/www/rails/public/;
try_files $uri #unicorn;
}
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:2007;
}
I want to remove /api/ from the start of path before passing it to rails app, but since it's a named location I can't add "/" at the end of proxy_pass directive, how can I remove /api/ before passing request to rails?
Use:
location #unicorn {
rewrite ^/api(.*)$ $1 break;
...
}
See this document for details.

Why I can't access to subdomain through nginx proxy pass?

I wanna to deploy my Ruby on Rails application in my local computer by Nginx and RoR web servers (like Unicorn, Thin or WEBrick).
As shown below, I wanna access to my web-app by post subdomain:
upstream sub {
server unix:/tmp/unicorn.subdomain.sock fail_timeout=0;
# server 127.0.0.1:3000;
}
server {
listen 80;
server_name post.subdomain.me;
access_log /var/www/subdomain/log/access.log;
error_log /var/www/subdomain/log/error.log;
root /var/www/subdomain;
index index.html;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
try_files /system/maintenance.html $uri $uri/index.html $uri.html #ruby;
}
location #ruby {
proxy_pass http://sub;
}
}
Everything is working fine and when I type post.subdomain.me I can see my RoR app.
Problem: When I use post.subdomain.me url I can't access to my subdomain (request.subdomain returns empty and request.host returns subdomain instaed of subdomain.me). But when I use post.subdomain.me:3000 every things work perfect (I lost half of my hairs to realize that). Why and How can I resolve it?
When you access app with port - you are accessing the rails server directly, not proxied by nginx, this is fine for debug, but usually is not well for production.
Probably host header is not passed over by client, $host defaults to nginx host
Try
location #ruby {
proxy_set_header Host $host;
proxy_pass http://sub;
}
And a 'hardcode'-way: proxy_set_header Host post.subdomain.me;
The proxy_set_header and proxy_redirect directives configure the proxy_pass directive and need to be within the same location block or inherited from the enclosing server block. You need to format your configuration file like this:
location / {
try_files /system/maintenance.html $uri $uri/index.html $uri.html #ruby;
}
location #ruby {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://sub;
}
EDIT: Assuming that nginx is not passing the information to RoR correctly, as #Vasfed suggested, try other values for proxy_set_header Host. There are three other candidates, all with slightly different meanings.
proxy_set_header Host post.subdomain.me;
proxy_set_header Host $server_name;
proxy_set_header Host $host;

Nginx per location / pass rewriten uri to proxy_pass

What the quickest and cleanest solution if you want to proxy URL request to two different backends via proxypass based on location.
location /app1/ {
alias /var/www/ruby/public;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
try_files $uri $uri/ #ruby;
}
location #ruby {
proxy_pass http://127.0.0.1:3000;
}
location /app2/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
try_files $uri $uri/ #other;
}
location #other {
proxy_pass http://127.0.0.1:8080;
}
With this config nginx pass "/app1" or "/app2" to proxy and backend doesn't recognize the url/command ..
as for instance would like to pass to http://127.0.0.1:3000 only /messages when accessing http://<nginx>/app1/messages - but in configuration above also pass /app1/ as http://127.0.0.1:3000/app1/messages. Same goes for /app2
Try putting "/" at the end of upstream name
e.g
proxy_pass http://127.0.0.1:8080/;
Please see this post:
How to preserve request url with nginx proxy_pass

Resources