nginx responding "301 moved permanently" - node.js

Consider the following nginx config file:
server {
listen 443;
ssl on;
ssl_certificate /etc/tls/cert.pem;
ssl_certificate_key /etc/tls/key.pem;
location / {
proxy_pass http://api.default.svc.cluster.local;
}
}
All incoming TCP requests on 443 should redirect to my server running on api.default.svc.cluster.local:80 (which is a node REST-Api btw). This works fine, I can curl https://<nginx-IP>/ nginx and get a correct response, as expected.
Now, I'd like to change the location from / to /api, so I can fire a curl https://<nginx-IP>/api in order to get the same response as before.
1. Attempt
So I change the location line in the config to:
location /api {
Unfortunately this won't work, instead I get an error Cannot GET /api which is a node error, so obviously it gets routed to the api but something's still smelly.
2. Attempt
It seems as the trailing slash in an URI is required so I added it to the location:
location /api/ {
Now something changed. I won't get the same error as before, instead I get an "301 moved permanently". How can I fix my nginx config file?
Additional information regarding the environment
I'm using a kubernetes deployment that deploys the nginx reverse proxy incl. the config introduced. I then expose nginx using a kubernetes service. Also, I tried using kubernetes ingress to deal with this situation, using the same routes, however, the ingress service would respond with a default backend - 404 message.

As mentioned in the question, trailing slashes in URIs are important. I fixed this in the location, however, I didn't add it to the URI I pass using proxy_pass.
As for the nginx proxy I got it to work using the following config:
server {
listen 443;
ssl on;
ssl_certificate /etc/tls/cert.pem;
ssl_certificate_key /etc/tls/key.pem;
location /api/ {
proxy_pass http://api.default.svc.cluster.local/;
}
}
Concerning the ingress solution, I was not able to get it to work by adding the missing trailing slash to the path. The service is specified due its name and therefore no trailing slash can be added (i.e. it would result in an error).

Related

Jelastic Enforce SSL on NodeJS

I'm trying to enforce the SSL protocol in a Jelastic Enviroment.
My setup is:
one node, with a Nginx Load balancer (+ public ip + custom ssl certificate) and a NodeJS application server.
The SSL setup is working, but i want to enforce the use of HTTPS no HTTP (a redirect).
I've tried to modify the nginx.conf but no success.
Any ideas how should I do that?
Create the config file /etc/nginx/conf.d/nginx_force_https.conf and add the lines below:
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
It will redirect all configured sites to https.
If you want only exact site example.com:
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
Make sure that you have these includes enabled in /etc/nginx/nginx.conf
include /etc/nginx/nginx-jelastic.conf;
in /etc/nginx/nginx-jelastic.conf:
include /etc/nginx/conf.d/*.conf;
Check for errors in the configuration:
sudo service nginx configtest
Reload configuration (this would be enough to make changes "work"):
sudo service nginx reload
Check if all works as expected. Restart the whole webserver (if needed):
sudo service nginx restart
The detailed answer can be found in this post Force www. and https in nginx.conf (SSL)

Block direct IP access using nginx

I have following nginx configurations
if ($host != mydomain.com) {
return 403;
}
When I hit the url http://127.0.0.1/test/test2/index.php (from POSTMAN) I get 403. Fine. But adding a Host -> mydomain.com in Headers I get 200.
When I added add_header Host "$host"; in nginx configurations I noticed in response that nginx has mydomain.com in its host variable. I know intentionally mentioning Host header in http request overrides 127.0.0.1 according to nginx documentation.
But in this way an attacker can send requests direct to web server by bypassing Cloudflare WAF. so what's the solution to block such requests from nginx?
I have tried following solutions but didn't work for me.
https://www.digitalocean.com/community/questions/how-to-block-access-using-the-server-ip-in-nginx
https://blog.knoldus.com/nginx-disable-direct-access-via-http-and-https-to-a-website-using-ip/
When I hit the url http://127.0.0.1/test/test2/index.php (from POSTMAN) I get 403. Fine. But adding a Host -> mydomain.com in Headers I get 200.
If I understand correctly, you seem to think that "adding a Host" header in your request is somehow a bypass. And it's not ... it's how hostnames work in HTTP.
A server doesn't magically know that you typed http://domain.tld/test/ in your browser address bar. Your browser makes a DNS lookup for domain.tld and establishes a TCP connection with the resolved IP address; it then sends headers, which is where the server gets the information from:
GET /test/ HTTP/1.1
Host: domain.tld
That's the only way the server knows you requested http://domain.tld/test/.
add this block:
server {
listen 80 default_server;
server_name "";
return 444;
}
OR
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
The “default_server” parameter cannot be present in any other server block. NGINX Block direct IP access.

HTTP to HTTPS redirect - Nginx vs Node Express

I want to redirect the HTTP traffic to the secure HTTPS version of my website. I am running NodeJS Express on an nginx server. What would be the best way to do the redirect: using nginx or Express? Is there any significant difference between the two options, like performance for example?
It all depends on how you do it but the performance difference will likely be insignificant. What I usually do is when nginx handles the SSL keys and certificates then I also let it take care of the redirects. That way the Node app doesn't even need to know about the HTTP - all it cares is serving the requests coming from the reverse proxy.
Example nginx config:
server {
listen 80;
server_name example.com;
add_header Strict-Transport-Security "max-age=3600";
root /www/example.com/html;
index index.html index.htm;
location / {
return 302 https://example.com$request_uri;
}
}
Keep in mind that you will need to temporarily turn off the redirect to HTTPS if you're using Let's Encrypt but only for the time of certification renewal - something worth noting because it can be hard to diagnose when your certification renewal fails.

Serving index.html displays "Internal Error: Missing Template ERR_CONNECT_FAIL" in browser

I'm trying to get my Node server up and running on Ubuntu 14.04. I followed a tutorial from DigitalOcean to set up nginx and server blocks to serve my content.
I have the server setup correctly, I believe because I can whois my-site.com and also ping my-site.com. when I visit the web address in the browser, however I get just this error that displays in the page: "Internal Error: Missing Template ERR_CONNECT_FAIL".
I thought that maybe I pointed the nginx server block to the incorrect path, because of of the "Missing Template", but it points to the right file. It is supposed to display a simple index.html file located in /var/www/my-site.com/html.
Here is my server block if this sheds some light on the error:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=off;
root /var/www/my-site.com/html;
index index.html index.htm;
# Make site accessible from http://localhost/
server_name my-site.com www.my-site.com;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
}
This file is located in /etc/nginx/sites-available/my-site.com and I've copied it to the sites-enabled directory as well.
What am I missing here?
This is a pretty standard error message, and in fact as of this moment nodejs.org is displaying that exact same message. I believe it is generated by a reverse proxy: for example, https://searchcode.com/?q=ERR_CONNECT_FAIL shows that ERR_CONNECT_FAIL appears in the squid reverse proxy software. I couldn't find something similar a quick search through the nginx source code.
When I encountered this error message, I was deploying through the digitalocean one-click dokku app and I did not have a domain in /home/dokku/VHOST, so it was being assigned a random internal IP address. I accessed it using [domain]:[port]. Hope that gives you a clue.

Passing parameters to nginx url

How to pass parameters in nginx url. When I hit http://127.0.0.1:1000/samp/test1/result?num1=10&num2=30, it should redirect me to http://127.0.0.1:80/samp/test1/result?num1=10&num2=30. Is this possible? Below is my nginx config file.
upstream apache {
server 127.0.0.1:1000;
}
server {
listen 80;
server_name 127.0.0.1;
location / {
#root html;
#index index.html index.htm;
#return 503;
proxy_pass http://apache;
}
}
I think what you want to do is possibe, but you'd have to make that configuration change on the apache end of things.
If 'apache' handles a request coming into port 1000 directly, it will see a URI like this:
http://127.0.0.1:1000/samp/test1/result?num1=10&num2=30
However, if it is sent through nginx, it will look more like this:
http://apache/samp/test1/result?num1=10&num2=30
So, you could check the incoming URL for :1000 and then rewrite the request on the apache side to go to port 80 instead ( which is the default, so you don't need :80 - you can just leave the port unspecified entirely.
If the backend really is apache, you can use a rewrite rule there to handle the rewriting.
However, if you're not already on port 80, you're not connecting to nginx - so nginx can't rewrite this for you.
Hope it makes sense!
Here's how I tested:
Apache side I used a quick sinatra (ruby) app to print out the full URI of the request it sees:
require 'sinatra'
set :bind, "0.0.0.0"
set :port, 1025
get "/*" do
"<p>Hello from \"apache\"! You've just requested:
<code>#{request.url}</code></p>
"
end
Then nginx is configured thusly:
upstream apache {
server 192.168.70.1:1025;
}
server {
server_name localhost;
location / {
proxy_pass http://apache;
}
}
Note I used port 1025, because port 1000 is a privileged port.
I used curl to generate the requests to test:
$ curl 'http://192.168.70.1:1025/samp/test1/result?num1=10&num2=30'
<p>Hello from "apache"! You've just requested:
<code>http://192.168.70.1:1025/samp/test1/result?num1=10&num2=30</code></p>
$curl 'http://127.0.0.1:80/samp/test1/result?num1=10&num2=30'
<p>Hello from "apache"! You've just requested:
<code>http://apache/samp/test1/result?num1=10&num2=30</code></p>
If I wanted to do the redirect you're describing, I could match with a regular expression of IPV4 address and port and redirect as such:
get "/*" do
if request.url =~ %r|^http://([0-9]{1,3}\.){3}[0-9]{1,3}:1025/|
redirect "http://localhost:80/#{request.fullpath}"
else
"<p>Hello from \"apache\"! Tou've just requested:
<code>#{request.url}</code></p>
"
end
end
Now I tell curl to follow redirects (-L) and we see it redirect me over to the "correct" route.
$ curl -L 'http://192.168.70.1:1025/samp/test1/result?num1=10&num2=30'
<p>Hello from "apache"! Tou've just requested:
<code>http://apache/samp/test1/result?num1=10&num2=30</code></p>
I know it's not the language you're using, but I hope it iwll help you get started.

Resources