Configure Nginx to direct traffic to http or https based on URL - nginx

I am using Nginx for a website which also exposes API's.
I want to add an SSL certificate to the website and:
direct all website traffic to https (443)
but keep all the API calls going to http (80)
All the API traffic is unique in that it calls a URL with api after the site name:
www.example.com/api/...
I am hoping this can be done with a combination of Nginx server/location blocks. So something like the following:
# http
server {
listen 80;
server_name example.com www.example.com;
# direct all api traffic (www.example.com/api/) via http
location /api/ {
root /full_path_to_api_code # '/api/' location value will be appended
}
# redirect all non api traffic to https block
location / {
return 301 https://$server_name$request_uri;
}
}
# https
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
...
}
I am hoping the 'location /api/' block catches all the api calls and just lets them pass through unchanged as it were. Maybe there is better way to do this?
I would appreciate if anyone can tell me if this is possible and if this is the right way to go about it?

Your config is good. The only thing you can change is combine them into same block if you are ok someone calling the api on http or https. Then you can do it like below
# http
server {
listen 80;
listen 443 ssl;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
server_name example.com www.example.com;
# direct all api traffic (www.example.com/api/) via http
location /api/ {
root /full_path_to_api_code
}
# redirect all non api traffic to https block
location / {
if ($scheme ="http") {
# redirect all non api traffic to https block
return 301 https://$server_name$request_uri;
}
normal https request processing
}
}
I would still go with your config, the reason being if is evil

Related

How CDN knows which Edge sever should it redirect the client to?

I'm trying to learn more about how CDN works. How does it knows which Edge sever should it redirect the client to for lowest latency? Thank you.
For this purpose, Upstream configuration is used in Nginx webserver.
nginx redirect users's requests to the destination server.
sample of Nginx upstream is as bellow.
upstream example.com {
server example.com;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
access_log /var/log/nginx/access.log custom;
location / {
proxy_pass http://example.com;
}

NGINX Forward HTTPS from any domain to specific URL

I am implementing an internal DNS server for block specific DNS requests to malicious websites, using a DNSRBL list against bind9. Whenever there's a match, the DNS server responds with the IP of an internal NGINX server that serves a block page.
Example, when the internal client requests http://www.badsite.com/ the DNS server responds with 192.168.0.100 as an example, which is the IP of the NGINX server. Then NGINX uses a 301 to forward the request to an HTTPS site which serves the block page message to the end user.
That works well using a simple NGINX config:
server {
listen 80 default_server;
server_name _;
return 301 https://block.xyz.com;
}
server {
listen 443 ssl;
server_name block.xyz.com;
ssl_certificate /etc/letsencrypt/live/block.xyz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/block.xyz.com/privkey.pem;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
The issue I'm having is when the client requests an HTTPS site, i.e.:https://www.badsite.com/ . I would like to forward any incoming SSL/443 requests to https://block.xyz.com. I've tried adding the following directive:
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/letsencrypt/live/block.xyz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/block.xyz.com/privkey.pem;
return 301 https://block.xyz.com;
}
And I get the typical SSL error saying the certificate doesn't match the domain: NET::ERR_CERT_COMMON_NAME_INVALID, which is understandable. The same thing happens when I change the directive from return to rewrite:
...
rewrite ^ https://block.xyz.com;
....
How would I go about adding a directive in NGINX to accomplish this? This guide (https://sweetcode.io/ad-blocking-with-local-dns-servers-and-nginx/) provided me a way to do the http side for implementing something similar for Ad Blocking, but doesn't speak to https requests.
Any clues?
In your server block try adding:
if ($host != "block.xyz.com") {
rewrite ^/(.*) https://block.xyz.com/$1 permanent;
}

HTTPS on NGINX server running wordpress

I am trying to implement HTTPS on a site ased on nginx server, Now even with the below config it only opens HTTP site
My server config for nginx server is like this
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mydomain.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.in/privkey.pem;
server_name mydomain.in www.mydomain.in;
rewrite ^(.*) http://$server_name$1 permanent;
}
server {
server_name mydomain.in www.mydomain.in;
access_log /var/log/nginx/mydomain.in.access.log rt_cache_redis;
error_log /var/log/nginx/mydomain.in.error.log;
root /var/www/mydomain.in/htdocs;
index index.php index.html index.htm;
include common/redis-php7.conf;
include common/wpcommon-php7.conf;
include common/locations-php7.conf;
include /var/www/mydomain.in/conf/nginx/*.conf;
}
The server does not serve HTTPS Requests i.e even if i specifically put https in browser it still takes me back to http site. I am not able to diagnose if its nginx or wordpress which is at fault ?
Note : the traffic is routed through cloudflare dns and certificate is
switch off in cloudflare so that it doesn't interfere. I am Relatively new to nginx
Well below is the basic idea.
server {
server_name mydomain.in www.mydomain.in;
listen 80;
location / {
return 301 https://mydomain.in$request_uri;
}
}
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mydomain.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.in/privkey.pem;
server_name mydomain.in www.mydomain.in;
access_log /var/log/nginx/mydomain.in.access.log rt_cache_redis;
error_log /var/log/nginx/mydomain.in.error.log;
root /var/www/mydomain.in/htdocs;
index index.php index.html index.htm;
include common/redis-php7.conf;
include common/wpcommon-php7.conf;
include common/locations-php7.conf;
include /var/www/mydomain.in/conf/nginx/*.conf;
}
The top server block listens on port 80 (http). It has one location block which does a return 301. return is preferred over rewrites in most cases. I also put it into a location block because you have a letsencrypt ssl cert which might require another location ^~ /.well-known { block to help handle that.
The second server block listens on port 443 (https). It has the SSL certs and includes the information exposed previously for as the http server block.
This setup will handle redirecting from http on either mydomain.in or www.mydomain.in to https mydomain.in. On https both mydomain.in and www.mydomain.in will receive SSL requests.
If you want it to redirect to a primary https domain you can add another server block for the secondary(ies) like so.
server {
server_name www.mydomain.in;
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mydomain.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.in/privkey.pem;
location / {
return 301 https://mydomain.in$request_uri;
}
}
Of course, this means you would have to change the second server block to remove the secondary(ies) domain names.
Also while testing you might want to change the 301s to 302s so that if you misconfigure the first time that it not be stuck in the browser cache. After you get everything to a good state then change back to 301s.

nginx https redirect adds www

I have two server blocks in my nginx configuration:
server {
listen 80;
server_name domain.com;
return 301 https://domain.com$request_uri;
}
server {
listen 443 ssl;
server_name domain.com;
<ssl stuff>
<root directory>
}
I'm basically redirecting all HTTP traffic to HTTPS using the first server block. I'm hardcoding the redirect domain name because I want to explicitly avoid redirecting to htps://www.domain... - I want https://domain...
When I request non-www HTTP domain, nginx correctly redirects to non-www HTTPS domain
However, when I request the www HTTP domain, nginx is not redirecting to the non-www HTTPS domain. Somehow, it adds a www to the HTTPS redirect even when I explicitly specified not to.
WHY?
Just looking at this without testing, I would say it's not picking up www.domain.com because that's not specified in the config. I belive you need a separate specification for www, or use a regex.
server {
listen 80;
server_name domain.com
www.domain.com;
return 301 https://domain.com$request_uri;
}

Redirect all http to https in nginx, except one file

I am currently running my site on http, and want to move it over to https such that nginx handles the redirection automagically. This is fairly trivial to do, I guess.
However, there is one file that (for several reasons) is hot-linked from other sites, some of which are over http and some over https. I want to ensure that the file is available over both http and https, so as to ensure that browsers don't complain with the "mixed content" dialog. The path of the file looks something like this:
http(s)://mydomain.com/scripts/[some_sha1_hash]/file.js
So, the nginx rule should say: "If the request is already over https, everything is sweet, and just reverse-proxy it. Otherwise, redirect all requests from http to https, except if this one file is requested, in which case don't do any such http->https redirect."
Can anyone either tell me where to look to learn about such a config, or help me with the config itself? Thanks in advance. (I'm sorry, but I'm not skilled enough yet at nginx configuration.)
This is what I did, which works:
server {
listen 80;
server_name example.com;
charset utf-8;
access_log /var/www/path/logs/nginx_access.log;
error_log /var/www/path/logs/nginx_error.log;
location /path/to/script.js {
# serve the file here
}
location / {
return 301 https://example.com$request_uri;
}
}
This one handles only http requests and serves the said file - otherwise redirects to https. Define your ssl server block, which will serve all https requests.
server {
listen 443;
server_name example.com;
ssl on;
# rest of the config
}
This way your script file will be available on http as well as https.
Try this:
server {
listen 80; ssl off;
listen 443 ssl;
server_name example.com;
# <ssl settings>
# ... other settings
location = /scripts/[some_sha1_hash]/file.js {
# Empty block catches the match but does nothing with it
}
location / {
if ($scheme = "http") {
rewrite ^ https://$http_host$request_uri? permanent;
}
# ... other settings
}
}
server {
listen 80;
server_name my.domain.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
server_name my.domain.com;
ssl on;
[....]
}
The above should mostly do the trick if im not wrong

Resources