How do I dynamically assign a port in nginx? - nginx

I want http://example.com/test/4000(or some other number) to proxy_pass to http://localhost:4000/test.
Is this possible, and how do I do this?

Here is example:
server {
listen 80;
server_name example.com;
# default port for proxy
set $port 80;
# redirect /4000 --> /4000/ just to be sure
# that next rewrite works properly
rewrite ^(/\d+)$ $1/ redirect;
# rewrite /4000/path/to/file to /path/to/file
# and store port number to variable
rewrite ^/(?<port>\d+)(.+)$ $2;
location / {
# proxy request to localhost:$port
proxy_pass http://localhost:$port;
}
}
It proxies request to /PORT_NUMBER/path/to/file to localhost:PORT_NUMBER/path/to/file. If url doesn't start with port number it falls back to 80 so request to /path/to/file will be proxied to localhost:80/path/to/file.
There is no check if port number is valid so it's not recommended to use it for production. But using variable port number in production is really bad idea anyway.

Related

How to make nginx process only the specified host (alocal, blocal), but ignore the "naked" ip address?

I have two rules for nginx (local):
server_name alocal;
listen 80;
location / {
...
proxy_pass http://localhost:8081;
}
and
server_name blocal;
listen 80;
location / {
...
proxy_pass http://localhost:8082;
}
I also changed the "hosts" file.
C:\Windows\System32\Drivers\etc\hosts
127.0.0.1 alocal
127.0.0.1 blocal
Everything works well. When I make a request through the browser, I get the expected behavior.
http://alocal -> http://127.0.0.1:8081
http://blocal -> http://127.0.0.1:8082
But when I specify just "localhost" as a host, nginx still processes my request, and it takes the first rule that comes along (from those that I gave above).
http://localhost -> http://127.0.0.1:8081
or (depends on which rule comes first)
http://localhost -> http://127.0.0.1:8082
Why does nginx process localhost if other hosts (alocal, blocal) are specified in server_name?
How to make nginx process only the specified host (alocal, blocal), but ignore the "naked" ip address?
Nginx listening to Port 80. If there is a request not matching any server_name the default is taken. Either given by listen 80 default_server; or the first entry if omitted.
If you want to block all requests not matching the specified server_name or with empty Host-Header you need a catch all as last block:
server {
listen 80 default_server;
server_name "";
return 444;
}
It will be not really ignored, but rejected. You can't "ignore" something, nginx is blocking port 80 and handling all requests somehow.

NGINX Configuration :

I am new to NGINX and I am trying to load balance our ERP web servers.
I have 3 webserver running on port 80 powered by websphere which are a black box to me:
* web01.example.com/path/apphtml
* web02.example.com/path/apphtml
* web03.example.com/path/apphtml
NGINX is listening for the virtual URL ourerp.example.com and proxying it to the cluster.
Here is my config:
upstream myCluster {
ip_hash;
server web01.example.com:80;
server web02.example.com:80;
server web03.example.com:80;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ourerp.example.com;
location / {
rewrite ^(.*)$ /path/apphtml break;
proxy_pass http://myCluster;
}
}
When I only use proxy_pass, then NGINX load balances but forwards the request to web01.example.com and not web01.example.com/path/apphtml
When I try adding url rewrite, it simply rewrite the virtual URL and i end up with ourerp.example.com/path/apphtml.
Is it possible to do URL rewrite at the upstream level or append the path to the app at the upstream level?
If you are trying to map / to /path/apphtml/ through the proxy, use:
proxy_pass http://myCluster/path/apphtml/;
See this document for more.
The problem with your rewrite statement is a missing a $1 on the end of the replacement string. See this document for more, but as I indicated above, you do not need the rewrite statement, as the proxy_pass statement is capable of doing the same job anyway.

nginx redirect twice from https to http

i have 2 servers, one has ssl and i config it like this,
in the server with SSL certification(which is https:// www.example.com):
location ~^/abc/.* {
proxy_pass http://www.example.com:8214/
}
in another server(which is http:// www.anotherExample.com):
server {
listen 8214;
server_name www.anotherExample.com;
rewrite ^/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
and after access https:// www.example.com/abc/api/getGroup
it can't redirect to http:// www.anotherExample.com:8080/api/getGroup
Anything wrong???
There are a couple of things you could do to improve your configuration.
location ^~ /abc/ {
proxy_pass http://www.example.com:8214$uri;
#You should have other directives set here as well.
}
Also, consider setting up an upstream.
Then, for your server block:
server{
listen 8124;
server_name www.anotherExample.com;
rewrite ^/abc/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
server{
listen 8080;
server_name www.anotherExample.com;
location ^~ /api/ {
#your_config_here
}
}
The explanation:
In your first location block, you shouldn't have .* in the expression. Nginx will match this for you. Then, when you're proxying, you can explicitly tell Nginx to send the URI as well.
Next, you're sending the URI www.anotherExample.com:8124, which includes /abc/, so you want to extract everything after that.
Lastly, because you've rewritten it to point to 8080 port, you'll need to define a separate server block for this.
I don't know what you're aiming to achieve, but so much proxying and redirects isn't necessary in most cases, and might lead to poor performance. Another consideration that you should take into account is you're sending unencrypted information to anotherExample.com, which, if not on the same local network, might be a security vulnerability.

redirecting request to a different listener nginx

I am having two listener 80 and 777. Port 80 act as a reverse proxy. And port 777 does some extra stuff and want to redirect to port 80. How do I redirect to a different port in nginx? I was trying with rewrite but later figured out that it is only used for change of path
###
server{
listen 80;
server_name _;
location / {
proxy_pass "http://upstream0;#" is included since links are not allowed in the post
}
}
server{
listen 777;
server_name _;
#doing some other extra stuf
//Want to redirect to port 80 under some condition
}
Is it possible?
Thanks
as far as nginx is concerned there's no real difference to passing something to another nginx listener/server and passing someting ot apache/mongrel/thin/... or any other http server
in other words if you want to pass things through to another listener you'd use proxy_pass
so what you want to do is something like
location / {
if (some condition) {
proxy_pass http://$host:80
}
}
see http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

Nginx rewrite non-www-prefixed domain to www-prefixed domain

I see the Nginx HttpRewriteModule documentation has an example to rewrite a www-prefixed domain to a non-www-prefixed domain:
if ($host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}
How can I do the reverse-- rewrite a non-www-prefixed domain to a www-prefixed domain? I thought maybe I could do something like the following but Nginx doesn't like the nested if statement.
if ($host !~* ^www\.) { # check if host doesn't start with www.
if ($host ~* ([a-z0-9]+\.[a-z0-9]+)) { # check host is of the form xxx.xxx (i.e. no subdomain)
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
}
Also I wanted this to work for any domain name without explicitly telling Nginx to rewrite domain1.com -> www.domain1.com, domain2.com -> www.domain2.com, etc. since I have a large number of domains to rewrite.
As noted in the Nginx documentation, you should avoid using the if directive in Nginx where possible, because as soon as you have an if in your configuration your server needs to evaluate every single request to decide whether to match that if or not.
A better solution would be multiple server directives.
server {
listen 80;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
server_name www.website.com;
...
}
If you're trying to serve an SSL (HTTPS) enabled site, you got more or less three different options.
Set up multiple IP addresses having each server directive listening on their own IP (or different ports if that's an option for you). This options needs SSL certificates for both website.com and www.website.com, so either you have a wild card certificate, a UNI certificate (multiple domains) or just plainly two different certificates.
Do the rewrite in the application.
Use the dreaded if directive.
There is also an option to use SNI, but I'm not sure this is fully supported as of now.
if ($host !~* ^www\.) {
rewrite ^(.*)$ http://www.$host$1 permanent;
}
Well I guess I don't really need the outer "if" statement since I'm only checking for domains of the form xxx.xxx anyways. The following works for me, though it's not robust. Let me know if there is a better solution.
if ($host ~* ^([a-z0-9\-]+\.(com|net|org))$) {
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
Edit: Added hyphen to the regular expression since it is a valid character in a hostname.
if ($host ~* ^[^.]+\.[^.]+$) {
rewrite ^(.*)$ https://www.$host$1 permanent;
}
It's only possible to get valid hostnames because the request will never make it to your server otherwise, so there's no need to build your own validation logic.
The nginx documentation cautions against the use of if for rewriting. Please see the link here: http://wiki.nginx.org/Pitfalls#Server_Name
HTTP & HTTPS without if conditions:
server {
listen 80;
listen 443;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
listen 443 default_server ssl;
server_name www.website.com;
# Your config goes here #
}
Solution for multiple domains, working on nginx 1.17 for me:
server {
listen 80;
server_name .example.com;
set $host_with_www $host;
if ($host !~* www\.(.*)) {
set $host_with_www www.$host;
}
return 301 https://$host_with_www$request_uri;
}
In this config example additionally rewrites HTTP on HTTPS, if you don't want rewrite — replace https:// with http:// in return string.
If you want keep protocol — use $scheme variable.

Resources