Nginx regex and wildcard for location - regex

I am stuck with one issue. I am trying to hit
http://localhost/api/hello/somename
Now somename could be anything sam or phil,
now my config file of nginx is below.
server {
listen 80 default_server;
server_name _;
location ~ ^/api/(.*)$ {
proxy_pass http://localhost:8081/api/hello/$1;
}
}
Where I am wrong ? Can you pls help me to fix. Actually on 8081 container is running.

You don't need to make it this complex. You could just it as simple as below
server {
listen 80 default_server;
server_name _;
location /api/ {
proxy_pass http://localhost:8081/api/;
}
}
And that should pass anything starting with /api to http://localhost:8081/api/, with the request uri after /api/ appended

/ should be escaped
.* is anything. If you know there should be names and / between them say it
^https?:\/\/\w+\/api(?:\/\w+)*$
http or https then : then //, then a word, then /api, then maybe some /word
test

Related

Bad Gateway python-telegram-bot with webhook and Nginx

I'm trying to set up a webhook with python-telegram-bot and Nginx. I am faced with a problem, my bot doesn't get messages from telegram. I also tried to make GET/POST queries from the postman and I always get a "502 Bad Gateway" error. I also launched the netstat to monitor port 5000 where my telegram bot connects but it is always empty. It seems like webhook doesn't launch at all.
My Nginx default.conf file looks like the following:
upstream django {
server gunicorn:8000;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
ssl on;
server_name example.com www.example.com;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
access_log /var/log/nginx/nginx.vhost.access.log;
error_log /var/log/nginx/nginx.vhost.error.log;
location /TELEGRAM_TOKEN {
proxy_pass http://0.0.0.0:5000/TELEGRAM_TOKEN/;
}
location /static/ {
alias /static/;
}
location / {
proxy_pass http://example.com:8000;
}
}
And my telegram client code:
updater = Updater(api_token)
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(button))
updater.dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, custom_command))
jq = updater.job_queue
job_minute = jq.run_repeating(callback_minute, interval=5)
#updater.start_polling()
updater.start_webhook(listen="0.0.0.0", port=5000, url_path=api_token,
webhook_url=f'https://example.com/{api_token}')
updater.idle()
I also have Django options for the Nginx server but I've never seen any tutorial or documentation on how to tune the webhook with Django and it can be the reason for my problems.
Have anyone any idea about solving my problem?
CallMeStag, your advice to use the following code helped me solve the issue:
print(Bot(api_token).get_webhook_info()))
I had 2 problems with the Nginx config file
First: ssl on
It gave me an error connection refused and I deleted it
Second
I changed this
location /TELEGRAM_TOKEN {
proxy_pass http://0.0.0.0:5000/TELEGRAM_TOKEN/;
}
to this
location /TELEGRAM_TOKEN {
proxy_pass http://example.com:5000/TELEGRAM_TOKEN/;
}
and the webhook is now working.
Thank you.

NGinx location directive with Regex

I'm looking for a way to get my NGinx LB to do the following conversion.
User access URL: https://example.com/t/foo.com/common/<something>
Proxied by LB: https://example.com/<something>?t=foo.com
First of all, is this possible to be done?
I tried the below config but didn't work as expected.
server {
listen 443;
server_name example.com;
ssl on;
ssl_certificate /etc/ssl/certs/example-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/example-selfsigned.key;
location /t/[a-z.]+/common/ {
rewrite ^(/t/.*)/common/(.*)$ https://192.168.1.3:9443/$2?t=$1 break;
proxy_pass https://192.168.1.3:9443/;
}
}
Any help on this would be greatly appreciated!
Regex matching locations should use ~ (or ~* for case-insensitive matching) modifiers. You should not add the scheme or domain part to your rewrite directive when you want to rewrite an URI that to be proxied with proxy_pass directive. Try the following:
location ~ ^/t/(?<t>[a-z.]+)/common(?<path>/.*) {
rewrite ^ $path?t=$t break;
proxy_pass proxy_pass https://192.168.1.3:9443;
}

Nginx redirect (non-www to www) not working with Certbot

I have a website running with a Python/Django/uWSGI/Nginx setup. I also use Certbot to enable https on my site. My redirects from non-www to www (e.g. "example.com" to "www.example.com") result in a "Bad Request (400)" message even though I couldn't spot any deviations from the Nginx/Certbot documentation. Here is the relevant part of my sites-available Nginx code:
server {
listen 80;
server_name example.com www.example.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/myname/example;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/activities.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; #managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/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
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
}
I found a similar StackOverflow answer (Nginx: redirect non-www to www on https) but none of the solutions worked for me. I have SSL certificates for both example.com and www.example.com. I also tried creating a separate 443 ssl server block for example.com based on the comments in that answer but it didn't work either. My sites-available and sites-enabled code is the same.
What am I doing wrong?
It seems that server_name when translated to the $host variable selects the first in the list of server_name. Let me know if that works. I can't quite test this currently.
Try swapping server_name to server_name www.example.com example.com; as well as changing return 301 https://$host$request_uri; to return 301 https://$server_name$request_uri;
server {
server_name www.example.com example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
# SSL CERT STUFF.
server_name example.com;
return 301 https://www.$server_name$request_uri;
}
server {
listen 443 ssl;
# SSL CERT STUFF.
server_name www.example.com;
# LOCATION STUFF
}
This is not an efficient configuration for Nginx request processing. It's messy, your if condition gets evaluated on every request and I don't see where your non www to www is even meant to happen.
I'd split http and https:
server {
listen 80 default_server;
return 301 https://www.example.com$request_uri;
}
Thats all non https traffic taken care of in a single redirect. Now for the https:
server {
listen 443 default_server ssl;
server_name www.example.com;
root # should be outside location blocks ideally
......
}
The default server directive means this server will handle any requests which do not have a matching server configuration. If you don't want that then add example.com after www.example.com, not before it. Any requests ending up here will display the first entry in the client browser bar.
Based on your comments you might need to add a separate block for the other domain to avoid an SSL certificate mismatch. Try this:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate .....;
ssl_certificate_key .....;
return https://www.example.com$request_uri;
}
Although the OP has accept one of the answers as the solution, I just want to point out that it may not be the best practice.
The correct way is to use $host instead of $server_name (as per Mitchell Walls' example) or hardcoded www.exmple.com (as per miknik's example). Both results an extra 443 server directive that is not necessary and messy.
server {
listen 80 default_server;
server_name www.example.com example.com;
root /var/www/html; # define your root directory here
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
# SSL CERT STUFF.
#server_name www.example.com; you don't need to specify again here
# LOCATION STUFF
}
There is a difference between $host and $server_name:
$host contains "in this order of precedence: host name from the request line, or host name from the 'Host' request header field, or the server name matching a request".
$server_name contains the server_name of the virtual host which processed the request, as it was defined in the nginx configuration. If a server contains multiple server_names, only the first one will be present in this variable.

regex infinite subdomains in nginx

I've following nginx config that matches main domain and redirects to new one, also matches 1 level down subdomain and redirects to new domain.
I'm missing case of subdomain of subdomain. e.g. sub.sub.domain.com or sub.sub.sub.sub.domaon.com or infinite levels really.
Any ideas how to safely regex this out?
server {
listen 80;
server_name domain.de.com;
return 301 $scheme://domain.com$request_uri;
}
server {
listen 80;
server_name ~^(?<subdomain>[^.]+)\.domain\.de\.com$;
return 301 $scheme://$subdomain.domain.com$request_uri;
}

nginx remove extra trailing slash ate the end of URL

I have this configuration inside server block which redirects all http requests to the https server with a 301, moved permanently status.
The problem is that in Screaming Frog or Chrome I can see that http://kida.al is redirected to https://kida.al// and then to https://kida.al/.
How can I prevent such a thing?
Thanks!
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name kida.al;
return 301 https://$server_name$request_uri/;
}
You should remove the extra trailing slash from the end of your redirection path:
return 301 https://$server_name$request_uri;