How to use Nginx with different physical machines? - nginx

I have many VMs running with different web servers and such. I want to be able to use the SSL port on more than one machine, which is where Nginx comes in.
I have looked and dug, and I do not understand if you can achieve using different physical VMs with Nginx.
I have a:
CentOS machine running Apache as my main (no virtual hosts) website. IP of 10.40.1.12 internally, reachable at kodysalak.com
Windows Server 2016 with exchange on it. IP of 10.40.1.17 internally, reachable at mail.kodysalak.com
Windows Server 2016 with Spiceworks' HelpDesk software (Apache). IP of 10.40.1.14 internally, reachable at help.kodysalak.com
Those are the hosts that use 80/443. I have a separate CentOS machine running Nginx with no configuration done with it. IP of 10.40.1.18.
Any help would be SO helpful, of course.

Yes you can.
nginx's proxy_pass (reverse proxy) and server_name (vhost).
http://nginx.org/en/docs/http/server_names.html
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
Portforwarding from Firewall, then with the HTTP Header "Host" (SSL/TLS: SNI) aka virtual hosting.
Edit:
server {
listen 443 ssl;
server_name www.kodysalak.com kodysalak.com;
location / {
proxy_pass https://10.40.1.12;
}
}
server {
listen 443 ssl;
server_name mail.kodysalak.com owa.kodysalak.com;
location / {
proxy_pass https://10.40.1.17;
}
}
server {
listen 80;
server_name help.kodysalak.com;
location / {
proxy_pass http://10.40.1.14;
}
}

Related

Basic proxy_pass from nginx from one local ip to another local ip

I am a new user of nginx and I am following a video guide from Linode on youtube (How to Set Up an NGINX Reverse Proxy).
I have a working nginx and apache server both on port 80. I know that because when I type the ip address of both in firefox, it directs me to nginx/apache welcome page.
The youtube video configuration template is as follow (where the server_name is the linode ip) :
server {
listen 80;
listen [..]:80;
server_name 172.105.104.226;
location / {
proxy_pass http://localhost:3000/;
}
On my Proxmox machine, the nginx server is on a VM at 192.168.1.241 and the apache server on another VM at 192.168.1.243.
Looking at nginx documentation we find that this :
location /some/path/ {
proxy_pass http://www.example.com/link/;
}
should proxy all the traffic received on the nginx listening port and redirect it to the address specified by proxy pass.
With all these information, my configuration file is like this :
server {
listen 80;
listen [::]:80;
server_name 192.168.1.241;
location / {
proxy_pass http://192.168.1.243;
}
}
My understanding is that this configuration file should listen at the address 192.168.1.241 on port 80 (nginx server) and redirect it to the specified address 192.168.1.243 (apache server)/
If i understand correctly, Location / should take the request as is received on the nginx server and redirect it to the apache server.
However, when I enter 192.168.1.241 in my browser, it doesn't show the apache welcome message but shows the nginx welcome message. That means that the proxy isn't working.
My nginx understanding is extremely limited as I am just starting to learn, but to me it seems like this should work but doesn't.
Thank you for your help
It turns out that the configuration is correct.
The problem was that the webpage was cached. By forcing a full refresh, 192.168.1.241 redirected to 192.168.1.243 successfully.

How to let the backend api handle https certificate?

I'm new to nginx.
I have a machine, behind my router, that runs a server and handles correctly 80 and 443 request with Https.
Problem is that I want to host a second website on another device but I have only one IP address. I bought a raspberry pi zero to use it as a reverse proxy behind my router. I install nginx and want to redirect all the request to my other machines. Both the RPI 0 and the old machine have local IP.
To redirect requests from my router to RPI 0 and then to my old machine, I used proxy_pass. On port 80 everything works fine, but on port 443 I get a certificate error on my browser.
Is it possible to let the whole request go on the old machine and let the old machine handles the https certificate like before ? Or is it mandatory to have the certificate processed by nginx ?
Diagram of the old but functional installation
Current installation with certificate error
My configuration:
upstream backend_a {
server 192.168.0.20:80;
}
upstream backend_a_s {
server 192.168.0.20:443;
}
server {
listen 80;
server_name mydomain;
location / {
include proxy_params;
proxy_pass http://backend_a;
}
}
server {
listen 443 ssl;
server_name mydomain;
location / {
include proxy_params;
proxy_pass https://backend_a_s;
}
}
I found a solution. I need to use port forwarding. To do this in nginx, I need to use stream keyword.
stream {
server {
listen 443;
proxy_pass 192.168.0.20:443;
}
}
The stream keyword need to be at the same level as http, so I needed to edit /etc/nginx/nginx.conf source. Other solution is to manually compile a version of nginx, with the parameter --with-stream source.

Nginx redirecting too many times with reverse proxy

I have a debian server with MySQL and Meilisearch, I want to use Nginx as a reverse proxy for future load balancing and also having TLS security.
I'm following Meilisearch's Documentation to set up Nginx with Meilisearch and Lets Encrypt with success, but they force Nginx to proxy everything to port 7700, I want to proxy to 3306 for MySQL, 7700 for Meilisearch, and 80 for an error page or a fallback web server. But after modifying /etc/nginx/nginx.conf, the website reloads too many times.
This is the configuration I'm trying at /etc/nginx/nginx.conf:
user www-data;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
stream {
upstream mysql {
server 127.0.0.1:3306;
}
upstream meilisearch {
server 127.0.0.1:7700;
}
server {
listen 6666;
proxy_pass mysql;
}
server {
listen 9999;
proxy_pass meilisearch;
}
}
http {
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com;
return 301 https://\$server_name$request_uri;
}
server {
server_name example.com;
location / {
proxy_pass http://127.0.0.1:80;
}
listen [::]:443 ssl ipv6only=on;
listen 443 ssl;
# ssl_certificate managed by Certbot
# ssl_certificate_key managed by Certbot
}
}
The only difference is example.com is replaced by my domain, which has been already set to redirect to the server ip.
As ippi pointed out, it isn't necessary to reverse proxy MySQL in this particular case.
I used proxy_pass http://127.0.0.1:7700 as Meilisearch docs suggest.
For future DB load balancing, I'd use MySQL Clusters, and point out to them on another Nginx implementation that proxies everything (ie. HTTPS to web server, DB access to list of clusters, etc.).
Also, in this particular case, I don't actually require encrypted connections to the DB, but if I needed them, I'd use a self signed certificate in MySQL, and a CA certificate for the website, since my front ends communicate with a "central" Nginx proxy that could encrypt communication between backend servers and the proxy.
If I actually wanted to use the Let's Encrypt certificates for MySQL, I've found a good
recipe, but instead of copy pasting the certificate (which is painful) I'd mount the Let's Encrypt certificates' directory into MySQL's and change the permissions to 600 with chown. But then again, this is probably bad practice and would be better to use self signed certificates for MySQL as it's own docs suggest.

Configure Nginx to reverse proxy requests to backend server based on port number

I have have four web applications running in one ec2-instance with hostname "ip-10-176-225-83.us-west-2.compute.internal" on the ports 8888, 8088, 8042 and 8890. All those web application are on HTTP.
Our security team doesn't allow to open http port from onpremise to AWS. The suggest to setup a reverse proxy in same VPC subent which takes HTTPS requests and forward the same to back end webservers using HTTP.
I have created a new instance in same subnet with hostname "ip-10-176-225-84.us-west-2.compute.internal" and installed Niginx Server.
How can i configure Nginx so that it does as below
https://ip-10-176-225-84.us-west-2.compute.internal:8080 call http://ip-10-176-225-83.us-west-2.compute.internal:8080 and responds back
same for other ports
TL;DR: There are several methods of accomplishing what you're looking for here.
Adhering to the principle of reducing attack surface where possible, it's usually best to not expose ports to the public internet unless absolutely necessary. A reverse proxy is an excellent way to accomplish this. Generally, you'd want all of the backend web apps to be reverse proxied over HTTPS on port 443, and you would access each service either:
with different host names, such as app1.example.com and app2.example.com, or
with different subdirectories, such as example.com/app1 and example.com/app2
Depending on the method you choose, the configuration may vary significantly, either with multiple server blocks for the former scenario, or location blocks for the latter. In either case, we'll be making use of the upstream and proxy_pass directives. I'll give an example of both scenarios.
Multiple Hosts
If you're using multiple hostnames (or multiple ports) for the frontend, you'll need to create multiple server blocks for them:
# Nginx reverse-proxy configuration
upstream app1 {
server 10.176.225.83:8888;
}
upstream app2 {
server 10.176.225.83:8088;
}
upstream app3 {
server 10.176.225.83:8042;
}
upstream app4 {
server 10.176.225.83:8890;
}
server {
listen 443 ssl;
server_name app1.example.com;
ssl_certificate_key /path/to/your/ssl-key.pem;
ssl_certificate /path/to/your/ssl-cert.pem;
location / {
proxy_pass http://app1;
}
}
server {
listen 443 ssl;
server_name app2.example.com;
ssl_certificate_key /path/to/your/ssl-key.pem;
ssl_certificate /path/to/your/ssl-cert.pem;
location / {
proxy_pass http://app2;
}
}
server {
listen 443 ssl;
server_name app3.example.com;
ssl_certificate_key /path/to/your/ssl-key.pem;
ssl_certificate /path/to/your/ssl-cert.pem;
location / {
proxy_pass http://app3;
}
}
server {
listen 443 ssl;
server_name app4.example.com;
ssl_certificate_key /path/to/your/ssl-key.pem;
ssl_certificate /path/to/your/ssl-cert.pem;
location / {
proxy_pass http://app4;
}
}
Several things to note here:
All of the backends have been defined at the top, using the upstream directive, and can now be referenced by name.
If you don't want to do it this way, you can omit the upstream blocks, and the proxy_pass lines would look like this: proxy_pass http://10.176.225.83:8888;
Because each app is being served on a different hostname, each gets its own server block. This would also be the case if they were each being served on different ports.
The ssl_certificate and ssl_certificate_key in each server block can point to different certificates, or even the same certificate, if you defined multiple SANs in the certificate.
Each app will be available from its own hostname, which all point to the frontend server:
App 1: https://app1.example.com
App 2: https://app2.example.com
App 3: https://app3.example.com
App 4: https://app4.example.com
Multiple Directories
For a configuration using a single host and port, serving the backend apps from subdirectories, you'll be using a single server block with multiple location blocks:
# Nginx reverse-proxy configuration
upstream app1 {
server 10.176.225.83:8888;
}
upstream app2 {
server 10.176.225.83:8088;
}
upstream app3 {
server 10.176.225.83:8042;
}
upstream app4 {
server 10.176.225.83:8890;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate_key /path/to/your/ssl-key.pem;
ssl_certificate /path/to/your/ssl-cert.pem;
location /app1 {
proxy_pass http://app1;
}
location /app2 {
proxy_pass http://app2;
}
location /app3 {
proxy_pass http://app3;
}
location /app4 {
proxy_pass http://app4;
}
}
A few more things to note with this one:
We still define all four upstream services, as before. And you can still omit them if you prefer the direct route. This directive is more useful in complex configurations.
Because all the apps are being served from the same hostname, they share a server block, but have separate location blocks for their respective subdirectories.
Since they all share the same hostname, multiple SANs aren't necessary for the server certificate in this case.
Each backend app will be available from a subdirectory on the frontend server:
App 1: https://example.com/app1
App 2: https://example.com/app2
App 3: https://example.com/app3
App 4: https://example.com/app4
TLS Configuration
In either scenario, you'll need to configure SSL certificates, either signed by a public CA, or your internal PKI, if applicable. If your apps are to be public facing, you will need to use public certificates. Then you'd add their location to the above Nginx config.
Further Reading
For a real world example, you can check out the Nginx configuration I'm using for a Genieacs TR-069 server, which implements SSL and reverse proxies several other services, albeit on their original ports, not to 443. This may be useful if you wanted to keep them on their original ports.
The Nginx site also has a decent primer on reverse proxy basic configuration.

Nginx Reverse Proxy upstream not working

I'm having trouble figuring out load balancing on Nginx. I'm using:
- Ubuntu 16.04 and
- Nginx 1.10.0.
In short, when I pass my ip address directly into "proxy_pass", the proxy works:
server {
location / {
proxy_pass http://01.02.03.04;
}
}
When I visit my proxy computer, I can see the content from the proxy ip...
but when I use an upstream directive, it doesn't:
upstream backend {
server 01.02.03.04;
}
server {
location / {
proxy_pass http://backend;
}
}
When I visit my proxy computer, I am greeted with the default Nginx server page and not the content from the upstream ip address.
Any further assistance would be appreciated. I've done a ton of research but can't figure out why "upstream" is not working. I don't get any errors. It just doesn't proxy.
Okay, looks like I found the answer...
two things about the backend servers, at least for the above scenario when using IP addressses:
a port must be specified
the port cannot be :80 (according to #karliwsn the port can be 80 it's just that the upstream servers cannot listen to the same port as the reverse proxy. I haven't tested it yet but it's good to note).
backend server block(s) should be configured as following:
server {
# for your reverse_proxy, *do not* listen to port 80
listen 8080;
listen [::]:8080;
server_name 01.02.03.04;
# your other statements below
...
}
and your reverse proxy server block should be configured like below:
upstream backend {
server 01.02.03.04:8080;
}
server {
location / {
proxy_pass http://backend;
}
}
It looks as if a backend server is listening to :80, the reverse proxy server doesn't render it's content. I guess that makes sense, since the server is in fact using default port 80 for the general public.
Thanks #karliwson for nudging me to reconsider the port.
The following example works:
Only thing to mention is that, if the server IP is used as the "server_name", then the IP should be used to access the site, means in the browser you need to type the URL as http://yyy.yyy.yyy.yyy or (http://yyy.yyy.yyy.yyy:80), if you use the domain name as the "server_name", then access the proxy server using the domain name (e.g. http://www.yourdomain.com)
upstream backend {
server xxx.xxx.xxx.xxx:8080;
}
server {
listen 80;
server_name yyy.yyy.yyy.yyy;
location / {
proxy_pass http://backend;
}
}

Resources