Nginx: Rewriting Request using Regex during fcgi_pass - regex

Any incoming request of the form:
http://localhost:19090/wms?map=world&layer=world&mode=map&FORMAT=image/jpg
needs to be rewritten to:
http://localhost:19090/wms?map=/home/balajeerc/Projects/mapserver/data/wms/world_map/world.map&layer=world&mode=map&FORMAT=image/jpg
i.e. the ?map=<mapname> needs to be transformed into ?map=<full path to mapname.map file>
Here is the nginx configuration that I have tried so far:
location /wms {
rewrite (^.*map=)([^\&]*)(\&.*) $1/home/balajeerc/Projects/mapserver/data/wms/world_map/$2.map$3 break;
fastcgi_pass 127.0.0.1:19097;
fastcgi_index mapserve*;
fastcgi_param SCRIPT_FILENAME /home/balajeerc/Projects/mapserver/bin/mapserve;
fastcgi_buffers 16 256k;
fastcgi_buffer_size 256k;
rewrite_log on;
include fastcgi_params;
}
I get the error:
msLoadMap(): Regular expression error. MS_DEFAULT_MAPFILE_PATTERN validation failed. when I try this.
What could I be doing wrong?
EDIT:
I did some more investigation and I found that the query string is not getting re-written at all. The way I established this was by running the echo-cpp fastcgi application. The query string as seen by the final fcgi application is the unmodified original that was sent to nginx.
I suppose that means that this is not a mapserver issue but an nginx issue. It appears that rewrite is doing nothing at all.

Managed to solve this after clues from a lot of other nginx related posts. Posting here for posterity.
Apparently, the regex in the 'rewrite' section operates only on paths. That means that everything after the '?' is NOT included in the regex.
What I was trying to do was not just a URL rewrite but modifying one of the request parameters itself. So the way I solved it was as follows:
location /wms {
if ($args ~* (.*map=)([^\&]*)(\&.*)){
set $args $1/home/balajeerc/Projects/mapserver/data/wms/world_map/$2.map$3;
}
fastcgi_pass 127.0.0.1:19097;
fastcgi_index mapserve*;
fastcgi_param SCRIPT_FILENAME /home/balajeerc/Projects/mapserver/bin/mapserve;
fastcgi_buffers 16 256k;
fastcgi_buffer_size 256k;
rewrite_log on;
include fastcgi_params;
}

fastcgi_param world /home/balajeerc/Projects/mapserver/data/wms/world_map/world.map,
should result in:
http://localhost:19090/wms?map=world

Related

How to rewrite the URL in Nginx Regex and debug?

I am trying to remove /api/v1 from the request URL and simply pass the rest of the part. For example /api/v1/test/ as simply /test. /api/v1/test/ready as simply /test/ready.
Here is what I have tried. I am thinking the first parameter i.e. $1 will be captured in ^(/api/v1) and the rest of the part will be captured (.*?).
So, I am simply passing $2 and breaking it. However, it is not working. I am unsure what am I doing wrong. I tried some debugging but failed to do so.
location /api/v1 {
rewrite ^(/api/v1)(.*?) $2; break;
# tried return 200 $2;
# but this will never hit since it is rewriting
# the rules will be evaluated again.
# I guess break will not allow it to re run again for the rules.
include uwsgi_params;
uwsgi_pass 10.0.2.15:3031;
}
I was trying to debug it but I couldn't.
It never hit the location /. For example.
location / {
return 200 $request_uri;
}
Finally, I could spot the problem. Here is my solution.
I think the obvious way to figure out what was going wrong was after enabling the redirection logs -
error_log /var/log/nginx/error.log notice;
rewrite_log on;
Here is the location context.
location /api/v1 {
# uncomment the below two lines to see the redirection.
# the re-direction happens from /api/v1/ to /
# error_log /var/log/nginx/error.log notice;
# rewrite_log on;
rewrite ^(/api/v1)(.*)/$ https://$host$2 break;
}
location / {
uwsgi_pass unix:///tmp/sb_web_wsgi.sock;
include uwsgi_params;
}

Nginx try_files not working with domain that appends trailing slash

I have a dockerised Django app where nginx uses proxy_pass to send requests to the Django backend. I am looking to pre-publish certain pages that dont change often so Django doesnt have to deal with them.
I am trying to use try_files to check if that page exists locally and pass to Django if not.
Our URL structure requires that all URLs end with a forward slash and we dont use file type suffixes e.g. a page might be www.example.com/hello/. This means the $uri param in nginx in this instance is /hello/ and when try_files looks at that it is expecting a directory due to the trailing slash. If I have a directory with a list of files how do I get try_files to look at them without re-writing the URL to remove the slash as Django requires it?
My nginx conf is below.
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name example.com;
root /home/testuser/example;
location / {
try_files $uri uri/ #site_root;
}
location #site_root {
proxy_pass http://127.0.0.1:12345;
}
}
If I have a file "hello" at /home/testuser/example/hello and call https://www.example.com/hello/ how can I get it to load the file correctly?
P.S. the permissions on the static content folder and its contents are all 777 (for now to rule out permissions issues)
Cheers in advance!
You can point the URI /hello/ to a local file called hello or hello.html using try_files, but you must first extract the filename using a regular expression location. See this document for details.
The advantage of using .html is that you will not need to provide the Content-Type of the response.
For example, using hello.html:
root /path/to/root;
location / {
try_files $uri uri/ #site_root;
}
location ~ ^(?<filename>/.+)/$ {
try_files $filename.html #site_root;
}
location #site_root {
proxy_pass ...;
}
If you prefer to store the local files without an extension, and they are all text/html, you will need to provide the Content-Type. See this document for details.
For example, using hello:
root /path/to/root;
location / {
try_files $uri uri/ #site_root;
}
location ~ ^(?<filename>/.+)/$ {
default_type text/html;
try_files $filename #site_root;
}
location #site_root {
proxy_pass ...;
}
In my case using NextJS, leaving the final slash causes errors.
So here is the solution I found to make it work nicely:
root /path/to/static/files/directory; # no trailing slash
rewrite ^/(.*)/$ /$1 permanent; # automatically remove the trailing slash
location / {
try_files $uri $uri.html $uri/index.html /404.html;
# try the provided uri
# then try adding .html
# then try uri/index.html (ex: homepage)
# finally serve the 404 page
}

nginx invalid number of arguments in "proxy_pass" directive

nginx: [emerg] invalid number of arguments in "proxy_pass" directive in /etc/nginx/sites-enabled/django_direct:12
My nginx conf file:
server {
listen 80;
server_name 94.154.13.214;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /root/django_direct/main_app/;
}
location / {
include proxy_params;
proxy_pass unix: /root/django_direct/django_direct.sock;
}
}
What do I do?
UPD:
I have changed file like this:
proxy_pass http://unix:/root/django_direct/django_direct.sock;
But didn't help, I've restarted nginx and now
I am getting now a 502 Bad Gateway error.
If someone else finds this and has this error. Check that you have a semi-colon at the end of the parameters line. goes for all of the lines, not just proxy_pass.
Well the nginx sees two parameters: unix, and /root/django_redirect/.... I have the idea however that you want to specify a UNIX domain socket path. You can do this with:
proxy_pass http://unix:/root/django_direct/django_direct.sock;
As is described in the documentation.
Your argument is wrong.
It needs an URL:
Sets the protocol and address of a proxied server and an optional URI to which a location should be mapped. As a protocol, “http” or “https” can be specified. The address can be specified as a domain name or IP address, and an optional port:
proxy_pass http://localhost:8000/uri/;
or as a UNIX-domain socket path specified after the word “unix” and enclosed in colons:
proxy_pass http://unix:/tmp/backend.socket:/uri/;
See the documentation: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
I can also happen when you mistakenly put a = character in, trying to assign a value that way.
proxy_pass = http://other_node;
The same thing might happen to you with for example auth_basic = "restricted site".
Just remove the =.

Nginx location block matching rule

I'm new to nginx server.
I'm gonna deploy the php framework such as codeigniter to the nginx server.
My config file is following.
server {
index index.html index.php index.htm;
# set expiration of assets to MAX for caching
location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
expires max;
log_not_found off;
}
location / {
# Check if a file exists, or route it to index.php.
try_files $uri $uri/ /index.php;
}
location ~* \.php$ {
fastcgi_pass unix:/var/run/php/php7-fpm.sock;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
My question is following.
1)The request uri is like this "www.domain.com/controllername/functionname/param1/param2/"
How does nginx work with this url?
2)The third location block matches the regular expression ".php$".
Is this true only if the uri has ended with ".php"?
(I think so , but that block's fastcgi_split_path_info has different regular expression.)
Question 1) Yes this should work, because the line
try_files $uri $uri/ /index.php;
is handled one by one for a request. First nginx tries to find the file described by the URI, if there's no match, it checks if it is a directory. If not it calls your index.php file. The original URI is handed over with a lot of other HTTP_REQUEST variables and the code from codeigniter takes care of parsing the url, if you config (codeigniter is correct).
The call convention for codeigniter is "www.domain.com/controllername/public_function/param1/param2/"
So normally you don't give the viewname, but the controller and the function name in your URI.
Question 2) The "location" directive only uses the URI path without any GET parameters. The split_path works differen and so it need a different regexp.

Nginx: How to rewrite all URLs except of images?

I'm new to nginx and I want to migrate my website from Apache to nginx. My site has URLs like:
www.mywebsite.com/category/product/balloon
www.mywebsite.com/category/product/shoe
www.mywebsite.com/information/help
etc.
Since I'm using PHP I need to rewrite all URLs to index.php except if it's an image OR if it's a "fake-request". My nginx.config so far:
#block fake requests
location ~* \.(aspx|jsp|cgi)$ {
return 410;
}
#rewrite all requests if it's not a image
location / {
root html;
index index.php 500.html;
if (!-f $request_filename) {
rewrite ^(.*)$ /index.php?q=$1 last;
break;
}
}
error_page 404 /index.php;
# serve static files directly
location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
access_log off;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME E:/test2/html/$fastcgi_script_name;
include fastcgi_params;
}
This configuration does not work because:
1. It doesn't block fake request to .php files and I can't add .php to (aspx|jsp|cgi)$
2. It doesn't rewrite the URL if the file exists which is wrong: It should only serve static files directly if it's a defined file-type in(jpg|jpeg|gif|css|png|js|ico)$
How can I solve these problems? I really appreciate every answer, clarification or feedback you can give me.
Thanks
Mike
You need to configure the HttpRewriteModule. This module makes it possible to change URI using regular expressions (PCRE), and to redirect and select configuration depending on variables.
If the directives of this module are given at the server level, then they are carried out before the location of the request is determined. If in that selected location there are further rewrite directives, then they also are carried out. If the URI changed as a result of the execution of directives inside location, then location is again determined for the new URI.