Nginx Rails website and Passenger with multiple ports - ruby-on-rails-3

I would like to run two versions of my rails site, one for production and one for development. The production one will listen on port 80 and the development will listen on port 9033. Here are my config server blocks which are located in the same file
server {
listen 80 default_server;
server_name mywebsite.com;
passenger_enabled on;
passenger_app_env production;
root /path/to/public/dir;
}
server {
listen 9033 default_server;
server_name mywebsite.com;
passenger_enabled on;
passenger_app_env development;
root path/to/public/dir;
passenger_friendly_error_pages on;
}
The problem lies in that when I try to connect to the website through my browser, regardless of which port I use I always get the version of the website corresponding to the environment specified in the first server block. So in the example I gave above, it'd always serve the production version of my website.
Why is it that the first server block overrides the second, and how can I make it so that I can access either version of my website without going in a manually changing the config files and reloading nginx?
UPDATE:
None of the suggestions were working, even after clearing the browser cache before sending every HTTP request. I changed my server blocks to the following in the hopes of my server returning different version of the website
server {
listen *:80;
server_name mywebsite.com;
passenger_enabled on;
passenger_app_env production;
root /home/alex/code/m2m/public/;
}
server {
listen *:80;
server_name dev.mywebsite.com;
passenger_enabled on;
passenger_app_env development;
root /home/alex/code/m2m/public/;
passenger_friendly_error_pages on;
}
and then added the following line in my /etc/hosts file
my.ip.addr.ess dev.mywebsite.com
But requests to both domains result in only the production version of my website being returned. Note I'm using the default nginx.conf file. Is there a way I can debug my browser (Chrome v40.0.2214.111 (64-bit)) to see if/where my requests are being altered? I'm thinking the problem lies clientside since the advice the commenters have given me seems like it should work.

And if you try this :
listen *:80;
and
listen *:9033;
This was my recommendation regarding the question that aims nginx config.
By putting those listen directives, according to nginx doc, nginx will first match ip:port server blocks and then look at server_name directives in server blocks that matched IP:port. So if request containing right 'port' end in the wrong environment this has something to do with either the app or the passenger directives.

Related

How do I fix an infinite redirect loop on a self-hosted nginx server?

I'm learning how to build and host my own website using Python and Flask, but I'm unable to make my website work as I keep getting an infinite redirect loop when I try to access my website through my domain name.
I've made my website using Python, Flask, and Flask-Flatpages. I uploaded the code to GitHub and pulled it onto a Raspberry Pi 4 that I have at my house. I installed gunicorn on the RasPi to serve the website and set up two workers to listen for requests. I've also set up nginx to act as a reverse proxy and listen to requests from outside. Here is my nginx configuration:
server {
if ($host = <redacted>.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
# listen on port 80 (http)
listen 80;
server_name <redacted>.com www.<redacted>.com;
location ~ /.well-known {
root /home/pi/<redacted>.com/certs;
}
location / {
# redirect any requests to the same URL but on https
return 301 https://$host$request_uri;
}
}
server {
# listen on port 443 (https)
listen 443;
ssl on;
server_name <redacted>.com www.<redacted>.com;
# location of the SSL certificate
ssl_certificate /etc/letsencrypt/live/<redacted>.com/fullchain.pem; # m$
ssl_certificate_key /etc/letsencrypt/live/<redacted>.com/privkey.pem; #$
# write access and error logs to /var/log
access_log /var/log/blog_access.log;
error_log /var/log/blog_error.log;
location / {
# forward application requests to the gunicorn server
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_set_header X_Forwarded_Proto $scheme;
proxy_set_header Host $host;
location /static {
# handle static files directly, without forwarding to the application
alias /home/pi/<redacted>.com/blog/static;
expires 30d;
}
}
When I access the website by typing in the local IP of the RasPi (I've set up a static IP address in /etc/dhcpcd.conf), the website is served just fine, although it seems like my browser won't recognize the SSL certificate even though Chrome says the certificate is valid when I click on Not Secure > Certificate next to the .
To make the website public, I've forwarded port 80 on my router to the RasPi and set up ufw to allow requests only from ports 80, 443, and 22. I purchased a domain name using GoDaddy, then added the domain to CloudFlare by changing the nameservers in GoDaddy (I'm planning to set up cloudflare-ddns later, which is why I added the domain to CloudFlare in the first place). As a temporary solution, I've added the current IP of my router to the A Record in the CloudFlare DNS settings, which I'm hoping will be the same for the next few days.
My problem arises when I try to access my website via my public domain name. When I do so, I get ERR_TOO_MANY_REDIRECTS, and I suspect this is due to some problem with my nginx configuration. I've already read this post and tried changing my CloudFlare SSL/TLS setting from Flexible to Full (strict). However, this leads to a different problem, where I get a CloudFlare error 522: connection timed out. None of the solutions in the CloudFlare help page seem to apply to my situation, as I've confirmed that:
I haven't blocked any CloudFlare IPs in ufw
The server isn't overloaded (I'm the only one accessing it right now)
Keepalive is enabled (I haven't changed anything from the default, although I'm unsure whether it is enabled by default)
The IP address in the A Record of the DNS Table matches the Public IP of my router (found through searching "What is my IP" on google)
Apologies if there is a lot in here for a single question, but any help would be appreciated!
I only see one obvious problem with your config, which is that this block that was automatically added by certbot should probably be removed:
if ($host = <redacted>.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
Because that behavior is already specified in the location / {} block, and I think the Certbot rule may take effect before the location ~ /.well-known block and break that functionality. I'm not certain about that, and I don't think that would cause the redirects, but you can test the well-known functionality yourself by trying to access http://yourhost.com/.well-known and seeing if it redirects to HTTPS or not.
On that note, the immediate answer to your question is, get more information about what's happening! My next step would be to see what the redirect loop is - your browser may show this in its network requests log, or you can use a command-line tool like curl or httpie or similar to try to access your site via the hostname and see what requests are being made. Is it simply trying to access the same URL over and over, or is it looping through multiple URLs? What are they? What does that point at?
And as a side note, it makes sense that Chrome wouldn't like your certificate when accessing it via IP - certificates are tied to one or more hostnames, so when you're accessing it over an IP address, the hostname doesn't match, so Chrome is probably (correctly) pointing that out and warning you that you're not at the hostname the certificate says you should be at.

SSL Termination on NGINX

I have purchased an SSL cert and bundled it up correctly in so much as when I verify the modulus (i.e. https://kb.wisc.edu/middleware/4064) then the hashes are the same.
I have moved the cert and key to my server # /etc/ssl and ensured that the folder permissions are 700 and each file is 600.
I have then the following nginx config:
server {
listen 80;
listen 443 ;
server_name escapehatch.chrisjowen.uk;
ssl on;
ssl_certificate /etc/ssl/ssl-bundle.crt;
ssl_certificate_key /etc/ssl/secret.txt;
access_log /var/log/nginx/nginx.vhost.access.log;
error_log /var/log/nginx/nginx.vhost.error.log;
location / {
proxy_pass http://localhost:8080;
}
}
Finally, to test this, I have a Python SimpleHTTPServer running on port 8080. When I hit the URL on HTTPS, I receive an error
This site can’t provide a secure connection
Looking at the logs from the Python server, I see:
218.186.183.142 - - [21/Aug/2019 04:45:53] code 400, message Bad HTTP/0.9 request type ('\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03\x01a\x96\x061LE\x88I\xf1i\x7f\xc3\xdc%d\x18r\xbbzq9q<\xeb\x1dD\xa3\x8b\x01\x10\x7f')
218.186.183.142 - - [21/Aug/2019 04:45:53] "�a�1LE�I�i��%dr�zq9q<�D�� n��Z���΀��SN�F���j;X.Zw�s^�"**�+�/�,�0̨̩����/5" 400 -
218.186.183.142 - - [21/Aug/2019 04:45:53] code 400, message Bad request version ('\x0fb\x03g\x8d\x04\x8b\xbe!\xad\x98W\x9bV\xd2\x8e\x1e\xc6\xf3\xaa\xff\xce\x0f\x1b\xc9\x0f\xebY\xae\xc4\x00"\xfa\xfa\x13\x01\x13\x02\x13\x03\xc0+\xc0/\xc0,\xc00\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00/\x005\x00')
So, it seems like nginx is not decrypting the request and terminating the SSL connection, instead it's passing it to the upstream server, which I do not want.
Checking the nginx logs /var/log/nginx/nginx.vhost.access.log shows nothing.
So, now I am stumped what to do to debug the issue, it appears that either nginx config is wrong or there is something wrong with the cert, but as mentioned I checked this with the following method https://kb.wisc.edu/middleware/4064
listen 80;
listen 443 ;
If you want it to listen for plain http on port 80 and https on port 443 the second line should be listen 443 ssl;.
ssl on;
From the documentation:
This directive was made obsolete in version 1.15.0. The ssl parameter of the listen directive should be used instead.
Also you have the following in the logs of your Python server:
218.186.183.142 - - [21/Aug/2019 04:45:53] code 400, ....
This Python server is clearly visited directly by an external IP address. If the request would be forwarded by the local nginx then the source IP should be 127.0.0.1 instead. This shows, that you don't hit nginx at all but somehow make a direct request to the Python server.

nginx proxying to upstream apache server which has self-certificate

As already mentioned in title, I have nginx server and apache server.Apache server has self-certificate because the settings are for development purpose.Also using nginx is for development purpose.Here is my config file for upstream server
server {
server_name enhi.com
listen 80;
listen 443 ssl;
localtion / {
proxy_pass https://172.17.0.3;
proxy_ssl_certificate /etc/nginx/server.pem;
proxy_ssl_certificate_key /etc/nginx/server.key;
}
So here is the tricky thing on which I dont understand.
When I access
http://enhi.com
It will redirect me to my apache app with https protocol.And if I enter
https://enhi.com
The browser gives me some "unexpected close ...." error.
So I don't understand what is going on in here.
Your help will be really appreciated.
Thanks in advance.
The specific directive you want is proxy_ssl_verify. However by default is disabled so out of the box, you should not be having issues. Most likely your issue is elsewhere.
Assuming it has been enabled, you should be see errors in the NGINX error log.

NGINX: set_by_lua doesn't work

I have NGINX running as a proxy service and want to set SSL key depending on the $ENV variable (in Docker Compose file).
I added to the nginx.conf:
env ENVKEY;
And then in the config file:
server {
resolver 10.0.0.4 valid=300s;
resolver_timeout 60s;
server_name _;
listen 443;
ssl on;
# perl_set $envkey 'sub { return $ENV{"ENVKEY"}; }';
set_by_lua $envkey 'return os.getenv("ENVKEY")';
ssl_certificate /etc/nginx/ssl/jm-website-$envkey.crt;
ssl_certificate_key /etc/nginx/ssl/jm-website-$envkey.key;
I also tried to use perl_set - but it can be used in the location only, but ssl_certificate - in the http or server blocks.
Using set_by_lua - I have an error:
nginx: [emerg] BIO_new_file("/etc/nginx/ssl/jm-website-$envkey.crt")
failed (SSL: error:02001002:system library:fopen:No such file or
directory:fopen('/etc/nginx/ssl/jm-website-$envkey.crt','r')
error:2006D080:BIO routines:BIO_new_file:no such file)
Although variable present in the environment:
root#d0718b0a3361:/etc/nginx# echo $ENVKEY
dev
What I'm doing wrong here?
Maybe there is better approach?
I do know that this is an old thread. I'm posting this for posterity's sake.
I was having the same problem as you were/are.
What is happening is that there's an order to when the lua blocks gets executed. set_by_lua happens right after the certificate is validated.
What you could do is either render you nginx.conf using a render engine of your choice (e.g.: python jinja) or you could write your own ssl_certificate_by_lua_block that reads from an environment variable. Here is an exemple of an implementation using said block. You could also check how Kong does it.
Hope it helps :)

Nginx serves different website (on the same sever) when using HTTPS

I have several websites hosted on the same sever. To simplify I have just 2 (http-only.com and https.com) and using nginx to handle requests.
One has SSL enabled. And another doesn't. I noticed links like this in Google Search Console http-only.com/https_server_path and when accessing an http-only.com server with https protocol I get requests served by an https.com server instead.
https.com:
server {
listen 443 ssl;
server_name https.com;
ssl on;
}
only-http.com:
server {
listen 80;
server_name only-http.com;
}
I think I should define something like a default ssl server to handle ssl for http.com, but don't know how to do it properly. I guess nginx should redirect https request to an http url if corresponding server doesn't handle https. Or maybe there is a better solution?