I have 2 clustered EC2 instances with 2 Classic ELB's one is for the DNS xxx.com and one for xxx.net. Both point to the same cluster of EC2 instances. My application needs to know whether the incoming request came from the .com or the .net URL.
The problem is that technically the ELB forwards the request, so I lose that in the header. I can get the IP address of the ELB, but Amazon will occasionally drop the ELB and give us a new one with a different IP, so it works for a while, then breaks out of nowhere.
Does Amazon offer something like a "static" ELB? I can't find anything so I assume not.
Is there any other way around this?
My application needs to know whether the incoming request came from the .com or the .net URL.
Read this from the incoming HTTP Host header. If it doesn't contain one of the two expected values, throw an error (503, 421, whatever makes the most sense) and don't render anything.
The problem is that technically the ELB forwards the request, so I lose that in the header.
I don't know what this statement is intended to convey. The Host header is set by the user agent and is not modified by the ELB so your application can read it from the incoming request.
You should not be looking at the internal IP address of the ELB for anything except to log it for correlation/troubleshooting if needed.
Of course, you also don't actually need 2 Classic ELBs for this application. You can use a single classic balancer with a single certificate containing both domains, or a single Application Load Balancer with either a combo cert or two separate certs.
Related
our company just moved to a new office and therefore also got new network equipment. Es it turns out, our new firewall does not allow pushing routes over VPN that it first has to look up ip addresses for.
As we all know, amazon aws does not allow static ip addresses for its application load balancer.
So our idea was to simply put a network load balancer in front of the application load balancer (there is a pretty hacky way described by aws itself (https://aws.amazon.com/blogs/networking-and-content-delivery/using-static-ip-addresses-for-application-load-balancers/) that seemed to work fine (even if I don't really like the approach with the lambda script registering and deregistering targets)
So here is our problem: as it turns out, the application load balancer only gets to see the network load balancers ip address. This prevents us to use security groups for ip whitelisting which we do quite heavily. On top of that some of our applications (Nginx/PHP based) also do ip address verification and the alb used to pass the clients ip address as an x-forwarded-for header. Now our application only sees the one from the nlb.
We know of the possibility to use the global accelerator but that is a heavy investment as we don't really need what the GA is trying to solve.
So how did you guys solve this problem ?
Thankful for any help :)
Greetings
You could get the list of AWS IP addresses for the region your ALB is located, and allow for them in your firewall. They do publish the list and you can filter through it https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html
I haven't done this myself and I'm unsure if the addresses for ALB are included under the EC2 category of you would take the whole of AMAZON service "to be safe".
Can you expand on this? "We know of the possibility to use the global accelerator but that is a heavy investment as we don't really need what the GA is trying to solve."
GA should give you better, more consistent performance, especially if your office is far away from the AWS Region where the ALB is running
I don't know if it's even possible to do so, but I will still ask. The thing is that I want to have (using ECS) one service A with tasks that do some job with the clients (create TCP connection, then form a group from multiple players and send to each player that they are formed in this group). Then I want this clients to make request to some specific task (some ENI with private IP, because I use awsvpc) from other service B behind an ALB (and then that task sends a response to those clients and starts working with them).
So my question is: "How can I forward multiple clients to the same specific ENI if that ENI is behind ALB?". Maybe in service's A tasks I should use AWS SDK to figure out the IPs of a service B tasks? But I still don't know how to reach that task by private IP. Is that even possible to "tell" ALB that I want to connect to some specific ENI?
Yes, you can configure the ALB to route to a specific IP. The listener on your ALB has routing rules that you can edit. Rules can be based on the domain name and path to which the HTTP request was sent.
Here is a detailed Tutorial on how to do that.
I want to develop my application separately (API, JOBS, WEB), so that it stays in this manner:
API: api.myaddress.com
JOBS: jobs.myaddress.com
WEB: myaddress.com
I know how to do that with distinct instances with Amazon and GoogleComputing, however, I was wondering IF, I could setup a single instance to do all that, and each DNS namespace, going to a different port on that machine, like:
api.myaddress.com resides in xxx.xxx.xxx.xxx:8090
jobs.myaddress.com resides in xxx.xxx.xxx.xxx:8080
myaddress.com resides in xxx.xxx.xxx.xxx:80
Also if that is possible, I don't know where I should configure that (Is it in the DNS, or a specific setup on my instance in Amazon/Google?)
Why do you want them to go to a different port? Its certainly not necessary. You can use DNS to point all of those domains/subdomains to a single server/ip address, and then thru your webserver configuration bind the various subdomain names to each particular website on that server.
In IIS you bind in the IIS Manager tool, and apache has a similar ability:
http://httpd.apache.org/docs/2.2/vhosts/examples.html
It sounds like what you are looking for is an HTTP reverse proxy. This would be a web server on your machine that binds to port 80 and, based on the incoming Host: header (or other criteria) it forwards the request to the appropriate Node.js instance, each of which is bound to a (different) port of its own.
There are several alternatives. A couple that immediately come to mind are HAProxy and Nginx.
DNS cannot be used to control which port a request arrives at.
Another approach, which is (arguably) unconventional but nonetheless would work would be to set up 3 CloudFront distributions, one for each hostname. Each distribution forwards requests to an "origin server" (your server) and the destination port can be specified for each one. Since CloudFront is primarily intended as a caching service, you would need to return Cache-Control: headers from Node to disable that caching where appropriate... but you could also see some performance improvements on responses that CloudFront can be allowed to cache for you.
what you are looking for is a load balancer (ELB in case of amazon).
setup the load balancer to send traffic to the different ports and at DNS level setup CNAMES for your services that point to the 3 load balancers that you have.
Scenario:
I have an EC2 server which houses the api currently setup to accept connections from several iPads. I do not wish for network sniffers to see the JSON requests that are being exchanged between the servers and the devices. The idea is to have a secure protocol in place so that communication will be secured.
I have been told purchasing a SSL certificate is the way forward. The Amazon server instance I have running has an address in this format:
ec2-xx-xxx-xx-xxx.ap-southeast-1.compute.amazonaws.com/
this is where my web root is with all the appropriate web service files. My webservice urls look something similar to this:
ec2-xx-xxx-xx-xxx.ap-southeast-1.compute.amazonaws.com/Agent/Create
so on so forth. There is no hosting plan whatsoever (in the case that information is necessary).
I have been recommended to buy an SSL Cert from http://www.Godaddy.com and have thought about getting the up to 5 multiple domains SSL certificate package.
Question: 1
What things do I need to be made aware of in order to make sure nothing fails?
I have recently read that I may need to associate an elastic IP address to my instance, otherwise the IP of my instance will change on reboots? And if that is the case, that means that the SSL certificate that was used for this: ec2-xx-xxx-xx-xxx.ap-southeast-1.compute.amazonaws.com domain would no longer work since the ip address would have changed upon reboot and therefor me losing my secure domain?
Question: 2
If my thoughts in question 1 stands true, then my question would then be what is the most user friendly way or lets say, the way for beginners to create a dedicated url for my server instance (so that 1) the domain name doesnt randomly change upon server reboot (not sure when i would reboot anyway) and 2) does this mean I can have easier webservice urls that one can remember? such as.... www.pk.com/Agent/Create instead of the long ec2 ugly url?!
Any easy to follow tutorials would be very helpful. I have looked at a few articles that spoke about elastic ip address, SSL certificates, and other articles about renaming ec2 url, but I'm in a position where I dont actually know which one applies to me. lol
Hope someone can help. thanks
What you want to do is to get an elastic IP address. This lets you bind your instance to a particular IP address when you start it up. You can then register a hostname in DNS (Amazon don't help you with this part) and state that that hostname has the IP address that is the elastic IP address that you have registered.
The final piece is to get a server certificate (strictly, a keypair where the public part is the server certificate) that has the hostname in the CN field of its Distinguished Name, and to install that server keypair on the instance. (This is another part that Amazon don't help you with, and is in fact the same process as if you were hosting the hardware yourself.) Like that, the client
looks up the hostname and gets the elastic IP address,
connects and gets the server certificate, and
checks the server certificate and sees that the hostname it is for is the hostname that they expected. (There's a few other checks as well, such as whether the certificate was signed by a trusted certificate authority and whether the certificate is within its validity period.)
That allows the client to trust that who they have securely connected to is who they expected to securely connect to, which is a key part of establishing trust.
What you do not do is use the AWS machine names (internal or external) in the certificate you apply for. Those change and you really do not want to trust other people's VMs.
Donal's answer is the way to go. You need to explicitly register a domain and generate the SSL certificate containing the CN as that domain. Elastic IP addresses definitely are your friends in this issue. You will need them.
I added another answer in order to give another point of view: if you ever want to scale your backend solution, going that way will be more difficult. If you ever thought about adding more servers to host your web service, you should definitely set up an Elastic Load Balancer, add your instances to it, and point the domain you just registered to your Elastic Load Balancer. Then, you can purchase the SSL certificate and install it directly on your ELB, configuring SSL termination on the ELB. You will also configure the ELB so that connections arriving at port 443 will map to port 80 (or whatever port) on your servers. Don't worry, this is plain easy to set up.
Whenever you want to add more servers to your web service, it will just be a matter of setting up another EC2 instance (this process can - and should - be automated) and adding it to the ELB.
With this setup, you get rid of the need for Elastic IP addresses. All the connections go through the ELB.
I'm currently running a REST API app on two EC2 nodes under a single load balancer. Rather than the standard load-balancing scenario of small amounts of traffic coming from many IPs, I get huge amounts of traffic from only a few IPs. Therefore, I'd like requests from each individual IP to be spread among all available nodes.
Even with session stickiness turned off, however, this doesn't appear to be the case. Looking at my logs, almost all requests are going to one server, with my smallest client going to the secondary node. This is detrimental, as requests to my service can last up to 30 seconds and losing that primary node would mean a disproportionate amount of requests get killed.
How can I instruct my ELB to round-robin for each client's individual requests?
You cannot. ELB uses a non-configurable round-robin algorithm. What you can do to mitigate (and not solve) this problem is adding additional servers to your ELB and/or making the health check requests initiated by your ELB more frequent.
I understand where you're coming from. However, I think you should approach the problem from a different angle. Your problem it appears isn't specifically related to the fact that the load is not balanced. Lets say you do get this balancing problem solved. You're still going to loose a large amount of requests. I don't know how you're clients connect to your services so I can't go into details on how you might fix the problem, but you may want to look at improving the code to be more robust and plan for the connection to get dropped. No service that has connections of 30+ seconds should rely on the connection not getting dropped. Back in the days of TCP/UDP sockets there was a lot more work done on building for failures, somehow that's gotten lost in today's HTTP world.
What I'm trying to say, is if you write the code you're clients are using to connect, build the code to be more robust and handle failures with retries. Once you start performing retries you'll need to make sure that your API calls are atomic and use transactions where necessary.
Lastly, I'll answer your original question. Amazon's ELB's are round robin even from the same computer / ip address. If your clients are always connecting to the same server its most likely the browser or code that is caching the response. If they're not directly accessing your REST API from a browser most languages allow you to get a list of ip's for a given host name. Those ip's will be the ip's of the loadbalancers and you can just shuffle the list and then use the top entry each time. For example you could use the following PHP code to randomly send requests to a different load balancer.
public function getHostByName($domain) {
$ips = gethostbynamel($domain);
shuffle($ips);
return $ips[0];
}
I have had similar issues with Amazon ELB however for me it turned out that the HTTP client used Connection: keep-alive. In other words, the requests from the same client was served over the same connection and for that reason it did not switch between the servers.
I don't know which server you use but it is probably possible to turn off keep-alive forcing the client to make a new connection for every request. This might be a good solution for requests with a lot of data. If you have a large amount of requests with small data it might affect performance negatively.
This may happen when you have the two instances in different availability zones.
When one ELB is working with multiple instances in a single availability zone, it will round-robin the requests between the instances.
When two instances are in two different availability zones, the way ELB works is create two servers (elb servers) each with its own IP, and they balance the load with DNS.
When your client asks the DNS for the IP address of your server, it receives two (or more) responses. Then the client chooses one IP and caches that (the OS usually does). Not much you can do about this, unless you control the clients.
When your problem is that the two instances are in different availability zones, the solution might be to have at least two instances in each availability zone. Then one single ELB server will handle the round-robin across two servers and will have just one IP so when a server fails it will be transparent to the clients.
PS: Another case when ELBs create more servers with unique IPs is when you have a lot of servers in a single availability zone, and one single ELB server can't handle all the load and distribute it to connected servers. Then again, a new server is created to connect the extra instances and the load is distributed using DNS and multiple IPs.