Authorization (401) issue with Nginx - nginx

I have a Nginx virtualhost with the following content:
server {
listen 80;
location /.well-known {
alias /usr/local/etc/letsencrypt-webroot/.well-known;
}
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dh.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
location / {
proxy_pass http://127.0.0.1:3000;
proxy_cookie_path / "/; secure; HttpOnly";
auth_basic "No no no!";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
I'm having a problem when the URL is /.well-known/.... I get a 401 because it keeps asking for credentials.
So my questions are:
Why is /.well-known user-protected? Shouldn't it be processed before reaching the location / in the SSL section, which is the one requiring authentication?
How can I fix this? Basically I need that everything requested to the proxy needs authentication except for /.well-known.

location /.well-known {
auth_basic off;
}

Try opening http://yourserver/.well-known/ instead of https://yourserver/.well-known.
If this works reconsider moving both location blocks to single server {...} block.
//edit to make it working you have to either remove redirect from. well-known block or adding it to block in https server definition.

Related

How to redirect API calls with nginx?

Using nginx I am trying to redirect API calls to an external API provider website but after a lot of research and tries I feel I miss something important.
For example, my goal is when I open https://mywebsite/api/somedata, then a remote API provider is called https://api-somewebsite.com/somedata.
My basic try was:
location /api/ {
proxy_pass https://api-somewebsite.com/;
}
I added a log format to try to get more informations:
log_format upstreamlog '[$time_local] $remote_addr - $remote_user - $server_name $host to: $upstream_addr: $request $status upstream_response_time $upstream_response_time msec $msec request_time $request_time';
Then used it to log the calls:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
And it seems that the /api/ part is not well removed:
[21/Sep/2022:11:23:17 -0400] 88.163.105.196 - - - mywebsite.com mywebsite.com to: xxx.xx.xx.xx:xxx, xxx.xx.xx.xx:xxx: GET /api/somedata HTTP/1.1 502 upstream_response_time 0.005, 0.008 msec 1663773797.354 request_time 0.012
So basically it seems to call https://api-somewebsite.com/àpi/somedata which does not exist and thus return 502 error.
I have read that with the trailing / the /api/ part should be well removed automatically. But it does not work. So I tried to rewrite it by myself:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
}
Still no luck.
I ended up trying some stuff found on the web but that I do not fully understand... like adding proxy_redirect instruction:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
proxy_redirect https://api-somewebsite.com/ /api/;
}
Well, I feel that I lack some basic stuff to make it work, but I cannot find what. Any insights would be greatly appreciated.
====== EDIT 1 ======
According to Stephen Dunne answer, i tried to add an upstream for the server.
Here is my edited code:
upstream magiceden {
server api-mainnet.magiceden.dev:443 max_fails=0;
zone magiceden-api 64k;
keepalive 60;
}
server {
server_name genoverse.me www.genoverse.me;
location / {
root /home/hcomere/genoverse.me;
index index.html;
}
location /magiceden_api/ {
proxy_pass https://magiceden/;
access_log /var/log/nginx/access_magiceden.log upstreamlog;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/genoverse.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/genoverse.me/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
I still have error 502 - Bad Gateway - when visiting https://www.genoverse.me/magiceden_api/
where i should get an error 400 - Not found - from the api provider
https://api-mainnet.magiceden.dev/
====== EDIT 2 ======
Oh well, i discovered that browsers have a redirect cache, this explain why sometimes things did not work where they should work.
Once i cleared the redirect cache after each config modification, things were way more smooth and understandable !...
I think the issue here is that you are using a Uri and not an upstream.
I have read that with the trailing / the /api/ part should be well removed automatically.
This is correct.
Try adding an upstream for the server.
upstream somesite {
server api-somewebsite.com:443 max_fails=0;
zone somesite-api 64k;
keepalive 60;
}
And then use the upstream in your location block (keeping the trailing slash)
location /api/ {
proxy_pass https://somesite/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
Now when you browse to the /api location you should be redirected as expected.

Allow nginx access only from IP address

I have a domain, e.g. www.domain.com which is registered on IP XXX.XXX.XXX.XXX, where my site is running on port 80.
I was wondering if there is a way, to block user access www.domain.com , forcing users to use only the IP address to enter the site.
Is it possible to set something like this using nginx?
Anyway, I am using Ubuntu as server, and any configurations on OS to solve this will be appreciated too.
Thank you so much.
Update:
Thanks to #mettalic the configuration now looks like this configuration looks like this:
server {
listen 80;
server_name _;
return 403;
}
server {
listen 80;
server_name XXXX;
add_header 'Access-Control-Allow-Origin' "http://XXX";
add_header x-frame-options "DENY" always;
location /api {
proxy_pass http://localhost:5000;
}
location / {
add_header 'Access-Control-Allow-Origin' "http://XXXX";
root /usr/share/nginx/html/dist;
index index.html;
try_files $uri $uri/ /index.html;
}
}
It is fully working.
If you have only one host on this server on port 80. You can create nginx configuration file without server name. Just listen XXX.XXX.XXX.XXX:80;.
UPD:
You could try add server which will be return error to all users who will try reach your site by domain:
server {
listen 80;
server_name _;
return 403;
}
or redirect them to ip:
server {
listen 80;
server_name _;
return 301 http://XXX.XXX.XXX.XXX;
}
Set server_name 192.168.19.24; in your host's config block.
On Ubuntu, the default virtual host is in /etc/nginx/sites-available/default, but that may be different on other distributions.

Nginx reverse proxy doesn't work as expected

I have two domains on different nginx(1.15.0) servers (server1 example.com and server2 example.net). I've tried to set up server2 as a reverse proxy with ngx_http_substitutions_filter_module but it doesn't work as expected.
Due to my config, subs_filter directive should replace example.com to example.net but when I type example.net in browser it redirects me to example.com.
nginx.conf
http {
//other settings
.....
include /etc/nginx/sites-enabled/*;
upstream example.com {
server example.com;
}
}
example.net.conf
server {
listen 80;
server_name example.net www.example.net;
rewrite ^/(.*)$ https://example.net/$1 permanent;
}
server {
listen 443 ssl;
server_name example.net;
ssl_certificate /etc/letsencrypt/live/example.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
root html;
try_files $uri #example.com;
}
location #example.com {
include replace.conf;
proxy_pass http://example.com;
proxy_cookie_domain example.com example.net;
proxy_set_header Accept-Encoding "";
proxy_set_header Host example.com;
proxy_redirect http://example.com http://example.net;
}
}
replace.conf
# replace direct links
subs_filter "www.example.com" "example.net" gi;
subs_filter "example.com" "example.net" gi;
Seems like nginx ignores subs_filter directive.
Could someone explain me how can I replace uri properly using ngx_http_substitutions_filter_module? Thank you for advice!
Problem solved.
First of all I removed upstream from nginx.conf:
upstream example.com {
server example.com;
}
Then I changed following lines in example.net.conf:
location / {
...
try_files $uri #static;
}
location #static {
...
proxy_pass https://example.com;
...
...
...
proxy_redirect https://example.com https://example.net;
}
All works fine except login form. Firefox works correctly but Chrome returns error 422. I suppose this is because the login form works on javascript.
Anyway thanks to all!

nginx as https proxy, but want to intercept one static path for Let's Encrypt /.well-known challenges

There is lots of material about using ngix as a reverse proxy and it is working well for me as a basic proxy for a strange web server app I need to use. I even have redirect on so http gets redirected to https.
server {
listen 80;
server_name <my server>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name <my server>;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";
ssl on;
ssl_certificate cert1.crt.pem;
ssl_certificate_key cert1.key.pem;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://localhost:81; # my existing apache instance
proxy_set_header Host $host;
}
Now I have one new wrinkle. I'd like to pick off one particular path and NOT have it get forwarded to the main server app. I need to do this to add in some Let's Encrypt challenge responses. Whenever the incoming url is http:///.well-known/acme-challenge/ then I want to use a static nginx path and NOT fwd to the main server.
Any ideas? I tried adding in a location directory but that wasn't working.
server {
listen 80;
server_name video.maritimeopscorp.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name video.maritimeopscorp.com;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";
ssl on;
ssl_certificate cert1.crt.pem;
ssl_certificate_key cert1.key.pem;
ssl_session_cache shared:SSL:10m;
location ~ /.well-known {
<I've tried lots of combinations here.>
}
location / {
proxy_pass http://localhost:81; # my existing apache instance
proxy_set_header Host $host;
}
I'd also prefer to get this up into the 80 block rather than the 443 block but little steps first.
Any ideas?
You will need to use a root directive, to inform nginx where the .well-known directory can be found:
server {
listen 80;
server_name video.maritimeopscorp.com;
location / {
return 301 https://$server_name$request_uri;
}
location /.well-known {
root /path/to/enclosing/directory;
}
}
Enclose the return statement inside the default location block, otherwise it will always take precedence.

How to set nginx so that it will show a specific page for IE users?

Below is my nginx config. I want to redirect IE users to a specific page. But if I change "return 403" to "return 301 mysite.com/a_page.html, there will be a redirection loop. How could I fix that?
server {
listen 80;
listen 443 default_server ssl;
server_name mysite.com
ssl_certificate /etc/nginx/ssl/mysite.crt ;
ssl_certificate_key /etc/nginx/ssl/mysite.key
if ($http_user_agent ~ MSIE) {
return 403;
}
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
client_max_body_size 10M;
location / {
proxy_pass http://localhost:2368/;
proxy_set_header Host $host;
proxy_buffering off;
}
Try to move the condition inside your generic location / {} block, then create a new location block for the redirect target.

Resources