I was having trouble configuring an nginx reverse proxy within my development environment when I stumbled on a behaviour that I do not quite get.
So nginx is listening on port 8080. When I make a request to my development-server, I can access my development server on
localhost:8080
With the following directives:
server {
listen 8080;
server_name site.com;
location / {
proxy_pass http://localhost:3000/;
proxy_redirect off;
}
But when I put a known website in the proxy pass_directive like google or apple the behaviour is different. I can not access e. g. apple.com as localhost:8080 with the following directives - I am immediately pushed to the real website and not the localhost:
server {
listen 8080;
server_name site.com;
location / {
proxy_pass http://apple.com/;
proxy_redirect off;
}
How is that behaviour called and how is it achieved? Can you guys put me in the right direction to understanding this? Thanks.
This is the correct behavior for the proxy service, you can find docs here https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
Some information regarding proxies here https://en.wikipedia.org/wiki/Proxy_server
Example: if you want to go to http://apple.com/apple-card/, you can point out to localhost:8080/apple-card and you will be redirected to /requested_path
I'm using proxies with docker containers just to route the requests to the correct application using different ports.
Related
I'm a newbie at Nginx, and have been searching a lot for the right answer to my question, but couldn't find it; not because it is not there, but my newbie condition limits me to adapt a generic solution to my issue.
The situation is this:
I have a Mantis Bug Tracker in my private LAN (http://10.111.111.12).
On the other hand, i have an OwnCloud website also on my LAN (IP 10.111.111.5), with URL http://10.111.111.5/owncloud/.
What i want to do is to deploy a Nginx Reverse Proxy that handles all requests from Internet at publicdomain.com, and use trailing slash for each internal webserver. The desired result would be:
http://www.publicdomain.com/bugtracker -> redirects to http://10.111.111.12/index.php
http://www.publicdomain.com/cloud -> redirects to http://10.111.111.5/owncloud/ (note that "cloud" is preferred over "owncloud")
On the future, it is necessary to continue using trailing slash for other web servers to be deployed.
Questions are:
is this scenario possible? if so, is it enough with configuring nginx or I have to reconfigure internal web servers as well?
I really appreciate your help, by indicating me a possible solution or pointing me to the right direction on previous posts.
Thanks a lot in advance.
Yes it is possible to achieve such configuration and it's commonly used when NGINX is acting as a reverse proxy. You can use this configuration as an inspiration for building your own:
upstream bugtracker {
server 10.111.111.12;
}
upstream cloudupstream {
server 10.111.111.5;
}
server {
listen 80;
location /bugtracker/{
proxy_pass http://bugtracker;
}
location /cloud/{
proxy_pass http://cloudupstream/owncloud;
}
}
What's happening over here is that nginx will be listening on port 80 and as soon as a request comes for path /bugtracker, it will automatically route the request to the upstream server mentioned above. Using this you can add as many upstream servers and location blocks as you want.
Reference: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
Thanks a lot Namam for your quick answer. However, it isn't working yet. It seems that "server" at upstream directive does not allow slash, like this:
server 10.111.111.5/owncloud;
If i used it, i obtained
nginx: [emerg] invalid host in upstream "10.111.111.5/owncloud" in /etc/nginx/nginx.conf:43
I started with the first upstream bugtracker, only, and nginx.conf like this:
upstream bugtracker {
server 10.111.111.12;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
location /mstic{
proxy_pass http://bugtracker;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
After that, when accesing to my Nginx Reverse proxy http://10.111.111.10/mstic/ i obtain the following:
Not Found The requested URL /mstic/ was not found on this server.
and no further details on error or access logs.
Thanks a lot in advance for any extra help you could bring me.
Through Jelastic's dashboard, I created this:
I just clicked "New environment", then I selected nodejs. I added a docker image (of mailhog).
Now, I would like that port 80 of my environment serves the nodejs application. This is by default so. Therefore nothing to do.
In addition to this, I would like port 8080 (or any other port than 80, like port 5000 for example) of my environment serves mailhog, hosted on the docker image. To do that, I added the following lines to the nginx-jelastic.conf (right after the first server serving the nodejs app):
server {
listen *:8080;
listen [::]:8080;
server_name _;
location / {
proxy_pass http://mailhog_upstream;
}
}
where I have also defined mailhog_upstream like this:
upstream mailhog_upstream{
server 10.102.8.215; ### DEFUPPROTO for common ###
sticky path=/; keepalive 100;
}
If I now browse my environment's 8080 port, then I see ... the nodejs app. If I try any other port than 80 or 8080, I see nothing. Putting another server_name doesn't help. I tried several things but nothing seems to work. Why is that? What am I doing wrong here?
Then I tried to get rid of the above mailhog_upstream and instead write
server {
listen *:5000;
listen [::]:5000;
server_name _;
location / {
proxy_pass http://10.102.8.215;
}
}
Browsing the environment's port 5000 doesn't work either.
If I replace the IP of the nodejs' app with that of my mailhog service, then mailhog runs on port 80. I don't understand how I can make the nodejs app run on port 80 and the mailhog service on port 5000 (or any other port than 80).
Could someone enlighten me please?
After all those failures, I tried another ansatz. Assume the path my env is example.com/. What I've tried above is to get mailhog to work upon calling example.com:5000, which I failed doing. Then I tried to make mailhog available through a call to example.com/mailhog. In order to do that, I got rid of all my modifications above and completed the current server in nginx-jelastic.conf with
location /mailhog {
proxy_pass http://10.102.8.96:8025/;
add_header Set-Cookie "SRVGROUP=$group; path=/";
}
That works in the sense that if I know browse example.com/mailhog, then I get something on the page, but not exactly what I want: it's the mailhog's page without any styling. Also, when I call mailhog's API through example.com/mailhog/api/v2/messages, I get a successful response without body, when I should've received
{"total":0,"count":0,"start":0,"items":[]}
What am I doing wrong this time?
Edit
To be more explicit, I put the following manifest that exhibits the second problem with the nginx location.
Full locations list for your case is a following:
(please pay attention to URIs in upstreams, they are different)
location /mailhog { proxy_pass http://172.25.2.128:8025/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection " upgrade"; }
location /mailhog/api { proxy_pass http://172.25.2.128:8025/api; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection " upgrade"; }
location /css { proxy_pass http://172.25.2.128:8025; }
location /js { proxy_pass http://172.25.2.128:8025; }
location /images { proxy_pass http://172.25.2.128:8025; }
that works for me with your application
# curl 172.25.2.127/mailhog/api/v2/messages
{"total":0,"count":0,"start":0,"items":[]}
The following ports are opened by default: 80, 8080, 8686, 8443, 4848, 4949, 7979.
Additional ports can be opened using:
endpoints - maps the container internal port to random external
via Jelastic Shared LB
Public IP - provides a direct access to all ports of your
container
Read more in the following article: "Container configuration - Ports". This one may also be useful:"Public IP vs Shared Load Balancer"
I've been hitting a wall for 3 days on this. Allow me to explain the matter:
We have a domain named demo1.example.com. We want demo1.example.com:90 to do proxy pass for 123.123.123.123:90, but not any other vhosts in the server like demo2.example.com.
What I mean is, that port should only work for that vhost, if someone tries to access demo2.example.com:90, it should not work. Currently, it is doing proxy_pass for any vhosts:90.
I hope I have explained the situation and that there is an actual solution for this.
Here's my current code:
server {
listen ip:80;
server_name subdomain.url.here;
and other normal server stuff for port 80
}
server {
listen ip:90;
location / {
proxy_pass 123.123.123.123:90;
proxy_set_header Host $host:$server_port;
}
}
I will really appreciate any help.
I have alfresco installed on a server, I want to force alfresco to only serve 1 language (italian) so, since it normally reads the language wanted from the http header, i set up an nginx reverse proxy to change the header.
The proxy runs on the server and listens to connections on port 80 and redirects them to the port 8080 where the alfresc otomcat server is running.
This is my server code in the nginx conf file:
server {
set $language 'it-IT';
add_header Accept-Language $language;
listen 80;
server_name alfresco
access_log logs/host.access.log main;
location / {
root html;
proxy_pass http://<serverip>:8080;
proxy_set_header Accept-Language $language;
proxy_set_header Host $host;
}
}
Everything works nicely, now i wanted to substitue with localhost (or 127.0.0.1), i thought that it should work since nginx is running on the same server as alfresco but it doesn't.
In particular, when i use and type the ip in the address bad of another machine i will get redirected correctly to http:///share/page/ and the page will be in italian (as expected)
but when i try to put localhost or 127.0.0.1 i will get redirected to http://:8080/share/page/ and the page will have the language i have in my browser.
Does anyone have an idea as to why this happens?
My title isn't the best, my knowledge of webstuff is quite basic, sorry.
What I want to achieve
I have one box fanbox running nginx on Archlinux that I use as main entry point to my home LAN from the internet (namely work where I can only get out to port 80 and 443) via the reverse proxy facility using a changing domain name over which I have no control and that we will call home.net for now.
fanbox has its ports 80 and 443 mapped to home.net, that part was easy.
I have 2 webservers behind the firewall, web1.lan, web2.lan, web2ilo.lan. Both of these have various applications (which may have same name on different machines) that can directly be accessed on the LAN via standard URLs (the names are given as examples, I have no control over the content):
http://web1.lan/phpAdmin/
http://web1.lan/gallery/
http://web2.lan/phpAdmin/
http://web2.lan/dlna/
...and so on...
Now web2ilo.lan is a particular case. It's the out of band management web interface of the HP server web2.lan. That particular webserver offers only 1 application, so it can only be accessed via its root URL:
http://web2ilo/login.html
My goal is to access these via subpath of home.net like this:
http://home.net/web1/phpAdmin/
http://home.net/web1/gallery/
http://home.net/web2/phpAdmin/
http://home.net/web2/dlna/
http://home.net/web2ilo/login.html
My problem
That nearly works but the web applications tend to rewrite URLs so that after I login to, respectively:
http://home.net/web1/phpAdmin/login.php
http://home.net/web2ilo/login.html
the browser is redirected respectively to
http://home.net/phpAdmin/index.php
http://home.net/index.html
Note that the relative subpaths web1 and web2ilo have gone, which logically give me a 404.
My config
So far, I've searched a lot and I tried many options in nginx without understanding too much what I was doing. Here is my config that reproduces this problem. I've left SSL out for clarity.
server {
listen 443 ssl;
server_name localhost;
# SSL stuff left out for clarity
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /web1/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web1.lan/;
}
location /web2/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web2.lan/;
}
location /web2ilo/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web2ilo.lan/;
}
}
After first answers
After the first couple of answers (thanks!), I realise that my setup is far from common and that I may be heading for trouble all alone.
What would then be a better idea to access the webserver behind the firewall without touching frontend ports and domain/hostname ?
You may wish to consider the use of setting proxy_redirect to let nginx know that it should modify the "backend" server response headers (Location and Refresh) to the appropriate front-end URLs. You can either use the default setting to allow nginx to calculate the appropriate values from your location and proxy_pass directives, or explicitly specify the mappings like below:
proxy_redirect http://web1.lan/ /web1/
See: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
Note: This only affects response headers - not any links in HTML content, or any Javascript.
If you experience problems with links in content or Javascript, you can either modify the content on the backend servers (which you've indicated may not be possible), or adjust your proxy solution such that front end paths are the same as the back end ones (e.g., rather than http://frontend/web1/phpAdmin you simply have http://frontend/phpAdmin). This would entail adding location directives for each application, e.g.,
location /phpAdmin/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web1.lan/phpAdmin/;
}
Here is a tested example.
In my docker-compose.yml I use the demo image whoami to test:
whoareyou:
image: "containous/whoami"
restart: unless-stopped
networks:
- default
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoareyou.rule=Path(`/whoareyou`)"
- "traefik.http.routers.whoareyou.entrypoints=web"
- "traefik.http.routers.whoareyou.middlewares=https-redirect#file"
- "traefik.http.routers.whoareyou-secure.rule=Path(`/whoareyou`)"
- "traefik.http.routers.whoareyou-secure.entrypoints=web-secure"
- "traefik.http.routers.whoareyou-secure.tls=true"
In my config.yaml I have my https redirect:
http:
middlewares:
https-redirect:
redirectScheme:
scheme: https
I did not find an answer to my question and decided to try a different approach:
I now have containerized most of my servers
I use Traefik (https://containo.us/traefik/) as my "fanbox" (= reverse proxy) as it covers my needs but also solves in a quite easy fashion the SSL certificates stuff.
Thanks all for your suggestions.