Load balancing strategies on nginx - cookies

To tackle expanding server load I have came up with a solution to render plain HTML site for visitors of my site. So the visitors are routed to plain html site whereas registered users are routed to dynamic site.
To separate the two different user groups I have used cookies. The load balancer and web server I'm using is nginx.
The nginx conf looks like this:
set $cookie_set 0;
if ($http_cookie ~ 'mysite.com') {
set $cookie_set 1;
}
location / {
if ($cookie_set ~ 0) {
proxy_pass http://static-site;
}
if ($cookie_set ~ 1) {
proxy_pass http://dynamic-site;
}
}
The mentioned strategy works, but it's not bulletproof. There are some situations where this doesn't work e.g. with browsers that don't support cookies and falsely created cookies.
There must be more sophisticated strategy of doing this. Any experiences, comments and ideas are welcome.

This is where a real load-balancer, such as HAProxy is needed.
with HAProxy, you can route traffic based on current backend farm capacity.
The configuration sniplet below forward the traffic to the static backend when the dynamic one start queueing.
frontend
use_backend bk_static if { queue(bk_dynamic) ge 1 }
default_backend bk_dynamic
backend bk_static
backend bk_dynamic
The same type of configuration could apply to a number of running sessions on bk_dynamic backend.
Baptiste

Related

CSRF fails on Route 53 redirect

I have two EC2 instances, which one has main Django-based backend app and another one has separate React-based frontend app using some of backend data. The backend app has its own views and endpoints and some frontend separate from the app in another EC2 instance. I got a new domain in AWS Route 53 which redirects to the frontend app and its location is configured on nginx. The missing thing are session cookies and csrftoken from the backend to make use of database. What may be useful is the frontend app is already reachable from the redirect set up in Django view but from the base server.
In the example code below I don't paste the whole config but just the concept what I want to reach.
Is there a way to redirect domain traffic to frontend app but through the backend to retrieve the cookies required to reach the backend data? Or should I think about other solution to make use of the domain?
server {
... some server data ...
$backend = "aws-backend-dns";
$frontend = "aws-frontend-dns";
location #backend {
proxy_pass http://$backend;
return #frontend; # but with some magic to keep the cookies!
}
location #frontend {
proxy_pass http://$frontend; # and I have backend cookies here
}
}

GCP: load balancer rewrite path

I'm setting up traffic management for a global external HTTP(S) load balancers. I have two backend Cloud Run services, serverless-lb-www-service and serverless-lb-api-service, that I want to serve from the same IP/domain.
I want to configure them like this:
example.com -> serverless-lb-www-service
example.com/api -> serverless-lb-api-service
I can use the simple routing rules to serve traffic semi-expected:
path
backend
/*
serverless-lb-www-service
/api
serverless-lb-api-service
/api/*
serverless-lb-api-service
However, I'm running into an issue where I try to access an endpoint that is not the root API end, like example.com/api/test. I'm always seeing the response I would expect from example.com/api.
I believe it has something to do with my API (running express.js) receiving the path /api when it is instead expecting to serve that route from there just /test. I think I might need to set up a rewrite to remove /api when it hits the API
Any help would be much appreciated. Thanks
update
I can confirm that the requests as logged in the API are all prefixed with /api. I can solve my issue by changing all API route handlers to expect the /api prefix in production environment. However I would still rather do this via a path rewrite so application code is the same in all environments
You can customize the host and path rules. You can follow the steps through this link. It is also using Cloud Run services and might help you with the rewrite path issues.
Note: Just scroll all the way down if the link will not redirect and show the "Customize the host and path rules" steps.

Nginx: Is it possible to resolve to different services based on a regexp over the URL and method?

I searched and I couldnt' find any way to do this, so I am wondering if it is possible.
I have a service running that accepts requests and everything works fine. However, I'd like to answer some of these requests with a different service running on the same machine. These requests are the ones going to some/path/{variable}/etc and method POST.
So I would like to know if it possible to do this directly from nginx without adding any overhead.
My first solution was creating a different API that receives all the requests and if it is not the one I want to incercept, just did a proxy request to the origianl service. But this added between 200 and 500ms to every response, which is not acceptable in our use case.
So I thought that doing this through nginx would resolve much faster, but I couldn't find a way or even find out if it is possible.
Any help would be highly appreciated. If you have any other idea or alternative that I could test or implement, it would be welcome as well.
Edit: Per request by Ivan's comment.
We have already nginx running, serving all the requests by service1.
What we would like to do is:
if request.path is in the form of /path/{variable}/etc and request.method==POST:
serve using service2
else:
serve using service1
Assuming you services hosted on the same server and differs in access ports, using a chain of the map blocks should do the trick:
map $uri $service_by_uri {
~^/path/[\w]+/etc 127.0.0.1:10002; # service 2
default 127.0.0.1:10001; # service 1
}
map $request_method $service {
POST $service_by_uri; # select service according to the request URI
default 127.0.0.1:10001; # service 1
}
server {
...
proxy_pass http://$service;
...
}

Static site with netlify + Django on the same url

Let's assume I own the domain:
foobar.com/
I want to use Netlify for my static pages like
foobar.com/features/
foobar.com/pricing/
foobar.com/imprint/
etc.
But I also have a Django application on a seperate server on AWS that has nothing to do with the static sites served by Netlify.
My Django has urls like
foobar.com/login/
foobar.com/dashboard/
etc.
Is it possible to use Netlify for a few static pages and my Django application for other pages?
I don't know how start or if this is event possible.
It will depend on how your Django apps handle the target, but you could use rewrites on Netlify using the HTTP status code 200 with a redirect rule (rewrite).
If the API supports standard HTTP caching mechanisms like Etags or Last-Modified headers, the responses will even get cached by CDN nodes.
Have DNS set foobar.com to the Netlify site.
Decide the domain for the Django site on AWS. (proxy.foobar.com)
Setup _redirects at the root of the Netlify site to use Proxy (rewrites) on Netlify
/login/* https://proxy.foobar.com/login/:splat 200
/dashboard/* https://proxy.foobar.com/dashboard/:splat 200
Note: This is how you can incrementally switch a site over to Netlify without having to refactor a site all at once.
When you set a DNS record (e.g. an A record), you can point foobar.com to your AWS server or netlify, but not both.
Perhaps you can put the sites on different domains, for example dashboard.foobar.com for your Django site.
You could then configure netlify to redirect foobar.com/dashboard/ to dashboard.foobar.com/dashboard/
No, you can't have a foobar.com point to two different servers. You'll have to use subdomains, e.g.:
static.foobar.com -> DNS entry for Netlify
app.foobar.com -> DNS entry for your Django server
or, what you often see, is:
foobar.com and www.foobar.com -> DNS pointing to your main website (Netlify)
api.foobar.com and app.foobar.com -> DNS pointing to your Django app

DNS hosting public and web application on different hosts

Here is my setup.
Public site hosted by squarespace.com (www.example-domain.com)
Web application (AWS EC2/ELB), i would like to be available via the same domain. (my.example-domain.com)
Custom profile pages available as www.example-domain.com/username
My question is how can i setup the DNS to achieve this? If can't do it just through DNS, any suggestions? The problem i am facing is that if squarespace.com is handling the www.example-domain.com traffic how can i have it only partially handle it for certain urls. Maybe i am going about this in the wrong was all together though.
The two first are ok. As you mention, (1) is not compatible with (3) for a pure DNS config as www of example-domain.com has to be configured to a single end-point.
Some ideas of non-DNS workaround:
Having the squarespace.com domain on sqsp.example-domain.com and configure your www domain to a custom web server on which you configure the root (/) to redirect (HTTP 300) to sqsp.example-domain.com. It will be quite transparent for the user, except in his browser address.
The same but setting on / a full page HTML iframe containing sqsp.example-domain.com.
The iframe approach is a "less clean", Google the solutions to build your opinion.
EDIT:
As #mike-ryan mentioned, there is the proxy solution as well where you configure you web server to request another server to get the content to return to your user. If you are already using AWS, a smart way to do this is to use CloudFront: you can setup CloudFront to proxy one server on one URL and proxy another server on other URL. Actually, this is maybe the faster to way to implement you need. Of course, a proxy is one more "hop", so it may add more delay.
If you really want to have content served from different servers while only using a single domain name, you'll need to set up a proxy server to handle the request routing for you. I am assuming your custom profile pages must be served from your EC2 instance.
Nginx will receive all requests, and will then decide whether they should be sent to Square Space or your web app. Requests will be reverse proxied to Square Space or to your app, depending on the URL.
This is similar to #smad's answer, except it will all be invisible to the users which IMHO is better than redirecting the user to a new domain name.
Example steps:
Set up an Nginx server, create two virtual hosts - one for my.example.com, and one for www.example.com
Create two upstreams in your Nginx config - one for Square Space, and one for your app
Configure the www.example.com virtual host to reverse proxy connections to the Square Space upstream, if the URL is "/". Otherwise, traffic should be proxied to your app upstream [0]
Configure the my.example.com virtual host to proxy all traffic to your app upstream
[0] how to reverse proxy via nginx a specific url?