Use nginx to proxy request to two different services? - nginx

Goal: Stand up a service that will accept requests to
http://foo.com/a
and turn around and proxy that request to two different services
http://bar.com/b
http://baz.com/c
The background is that I'm using a service that can integrate with other 3rd party services by accepting post request, and then posting event callbacks to that 3rd party service via posting to a URL. Trouble is that it only supports a single URL in its configuration, so it becomes impossible to integrate more than one service this way.
I've looked into other services like webhooks.io (waaaay too expensive for a moderate amount of traffic) and reflector.io (beta - falls over with a moderate amount of traffic), but so far nothing meets my needs. So I started poking around at standing up my own service, and I'm hoping for as hands-off as possible. Feels like nginx ought to be able to do this...
I came across the following snippet which someone else classified as a bug, but feels like the start of what I want:
upstream apache {
server 1.2.3.4;
server 5.6.7.8;
}
...
location / {
proxy_pass http://apache;
}
Rather than round robin request to apache, that will apparently send the same request to both apache servers, which sounds promising. Trouble is, it sends it to the same path on both server. In my case, the two services will have different paths (/b and /c), and neither is the same path as the inbound request (/a)
So... Any way to specify a destination path on each server in the upstream configuration, or some other clever way of doing this?

You can create local servers. Local servers proxy_pass add the different path (b,c).
upstream local{
server 127.0.0.1:8000;
server 127.0.0.1:8001;
}
location / {
proxy_pass http://local ;
}
server {
listen 8000;
location / {
proxy_pass http://1.2.3.4/b;
}
server {
listen 8001;
location / {
proxy_pass http://5.6.7.8/c;
}

Related

Super basic question on linking domain to server

I have a super basic question. I have a GoDaddy account set up with subdomain xxx.mydomain.com. I also have some services running in an AWS instance on xxx.xxx.xxx.xxx:7000. My question is, what do I do to configure so that when people click xxx.mydomain.com it goes to xxx.xxx.xxx.xxx:7000?
I am not talking about domain forwarding. In fact, I also hope to do the same for yyy.mydomain.com to link it to xxx.xxx.xxx.xxx:5000. I am running Ngnix in xxx.xxx.xxx.xxx. Maybe I need to configure something there?
You want a reverse proxy.
Add two A-records to your DNS configuration to map the subdomains to the IP address of the AWS instance. With GoDaddy, put xxx / yyy in the "Host" field and the IP address in the "Points to" field. (more info)
Since you already have Nginx running, you can use it as a reverse proxy for the two subdomains. Therefore, add two more server blocks to Nginx's configuration file. A very simple one could look like this:
http {
# ...
server {
server_name xxx.mydomain.com;
location / {
proxy_pass http://localhost:7000;
}
}
server {
server_name yyy.mydomain.com;
location / {
proxy_pass http://localhost:5000;
}
}
}
You might want to rewrite some headers depending on your services/applications (more info). Also, consider to use Nginx for SSL termination (more info).

Using Proxy server to switch between Golang Applications

I have a server with CentOS, and there I will have at least 4 Golang applications running, every one of them is a different site that I should be able to access in the browser with domain/subdomains as follows:
dev00.mysite.com
dev01.mysite.com
dev02.mysite.com
dev03.mysite.com
So, I need to configure some kind of software that redirects the requests to the correct Golang process. Every site will be running in a different port, so for example if someone calls dev00.mysite.com I should be able to send that request to the process of dev00 site (this is for development porpouses, not production). So, here I'm starting to believe that I need Nginx or Caddy as I read, but I have no experience with none of them.
Can someone confirm that this is the way to fix that problem? and where can I find some example of configuration of any of that servers redirecting to Golang applications?
And, in the future if a have a lot (really a lot) of domains running in the same server, which of that servers is better? who is better with high load?
Yes, Nginx can solve your problem:
Start a web server using the standard library of Go or Caddy.
Redirect request to Go application using Nginx:
Example Nginx configuration:
server {
listen 80;
server_name dev00.mysite.com;
...
location / {
proxy_pass http://localhost:8000;
...
}
}
server {
listen 80;
server_name dev01.mysite.com;
...
location / {
proxy_pass http://localhost:8001;
...
}
}

Nginx - Redirect requests to all backends

I have 5 backend servers. I want nginx to forward the POST request for /myapp/refresh to all 5 backend servers. For any other request, it can do load balancing. Is this possible ? Can you please give a sample configuration ?
I'm not aware about ready to use solution to do what you want.
It is definetely possible to implement such behavior in C or Lua.
You may develop nginx C module, but it not trivial task with serious learning curve.
You may use https://github.com/openresty/lua-nginx-module and use something like https://github.com/openresty/lua-nginx-module#ngxlocationcapture_multi.
But in both cases you should implement some kind of logic when and which response you will send back.
Question to think about - do you need to respond with 200 OK if one of the backend will time out or responds with error?
You can try use the The ngx_http_mirror_module module (1.13.4), this implements mirroring of an original request by creating background mirror subrequests. Responses to mirror subrequests are ignored. https://nginx.org/en/docs/http/ngx_http_mirror_module.html
You should be able to use nginx as a load balancer using a simple config such as:
http {
upstream myproject {
server 127.0.0.1:8000 weight=3;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
listen 80;
server_name www.domain.com;
location / {
proxy_pass http://myproject;
}
}
}
docs:
https://www.nginx.com/resources/admin-guide/load-balancer/
This should route all requests including the POST request you mentioned.

Domain name and port based proxy

I think I finally grasped how Docker works, so I am getting ready for the next step: cramming a whole bunch of unrelated applications into a single server with a single public IP. Say, for example, that I have a number of legacy Apache2-VHost-based web-sites, so the best I could figure was to run a LAMP container to replicate the current situation, and improve later. For argument sake, here is what I have a container at 172.17.0.2:80 that serves
http://www.foo.com
http://blog.foo.com
http://www.bar.com
Quite straightforward: publishing port 80 lets me correctly access all those sites. Next, I have two services that I need to run, so I built two containers
service-a -> 172.17.0.3:3000
service-b -> 172.17.0.4:5000
and all is good, I can privately access those services from my docker host. The trouble comes when I want to publicly restrict access to service-a through service-a.bar.com:80 only, and to service-b through www.foo.com:5000 only. A lot of reading after, it would seem that I have to create a dreadful artefact called a proxy, or reverse-proxy, to make things more confusing. I have no idea what I'm doing, so I dove nose-first into nginx -- which I had never used before -- because someone told me it's better than Apache at dealing with lots of small tasks and requests -- not that I would know how to turn Apache into a proxy, mind you. Anyway, nginx sounded perfect for a thing that has to take a request a pass it onto another server, so I started reading docs and I produced the following (in addition to the correctly working vhosts):
upstream service-a-bar-com-80 {
server 172.17.0.3:3000;
}
server {
server_name service-a.bar.com;
listen 80;
location / {
proxy_pass http://service-a-bar-com-80;
proxy_redirect off;
}
}
upstream www-foo-com-5000 {
server 172.17.0.4:5000;
}
server {
server_name www.foo.com;
listen 5000;
location / {
proxy_pass http://www-foo-com-5000;
proxy_redirect off;
}
}
Which somewhat works, until I access http://blog.bar.com:5000 which brings up service-b. So, my question is: what am I doing wrong?
nginx (like Apache) always has a default server for a given ip+port combination. You only have one server listening on port 5000, so it is your defacto default server for services on port 5000.
So blog.bar.com (which I presume resolves to the same IP address as www.foo.com) will use the default server for port 5000.
If you want to prevent that server block being the default server for port 5000, set up another server block using the same port, and mark it with the default_server keyword, as follows:
server {
listen 5000 default_server;
root /var/empty;
}
You can use a number of techniques to render the server inaccessible.
See this document for more.

nginx conditional proxy pass based on header

I'm trying to manage a deployment to servers running behind an nginx plus server configured as a load balancer. The app servers are sent traffic from nginx using the proxy_pass directive, and what I'd like to do is to direct traffic to one upstream by default, but a different one for testing as we deploy to spare instances; I'm trying to select this by having developers set a header in their browser, which nginx then looks for and sets a variable for the relevant proxy.
It seems all to be sensible, but it simply doesn't work - I'm not sure if I misunderstand how it works, but it does seem odd.
The upstreams are configured as
upstream site-cluster {
zone site 64k;
least_conn;
server 10.0.6.100:80 route=a slow_start=30s;
server 10.0.7.100:80 route=b slow_start=30s;
sticky route $route_cookie $route_uri;
}
upstream site-cluster2 {
zone site 64k;
least_conn;
server 10.0.6.30:80 route=a slow_start=30s;
server 10.0.7.187:80 route=b slow_start=30s;
sticky route $route_cookie $route_uri;
}
And then this code is in the location / block.
map $http_x_newsite $proxyurl {
default http://site-cluster;
"true" http://site-cluster2;
}
proxy_pass $proxyurl;
What happens is it's always the default servers which get sent the traffic, irrespective of whether I set the header or not.
Any ideas?
map directive should be in http context not location:
Syntax: map string $variable { ... }
Default: —
Context: http
The rest looks sensible, works for me.

Resources