Re: Consistent hashing based on cookie - across multiple HAProxy boxes
For those interested, this turned out to be some wierdness in haproxy - one of the servers was only storing the first 24 (despite being configured for 32, and the other identical binary/config working fine). The way to debug was the following on both servers for a given cookie value: echo show table webservers | socat /var/lib/haproxy/stats - | fgrep 4start_of_session From my config, it was also important to store text not binary data in the table. -Alex On Sat, Mar 2, 2013 at 5:32 PM, Alex Davies a...@davz.net wrote: I was trying to troubleshoot this with a packet dump on the peer traffic. The raw tcpdump does not mean anything to me, and Wireshark is decoding it as Java RMI traffic which isnt much use, and it looks like a binary protocol. So I can report that 'peer' traffic is certainly working because when I restart one of the haproxy processes there are a bunch of different packets sent (Wireshark doesent even attempt to decode these). I was hoping to be able to grep for one of the offending session IDs to see if that gave me a hint. Does anybody have a working configuration for multi peer persistence based on a cookie that I could test, by chance? Thanks, -Alex -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
[PATCH] DOCS: Add explanation of intermediate certs to crt paramater
This change makes the crt block of the documentation easier to use for those not clear on what needs to go in what file, specifically for those using CAs that require intermediate certificates. --- doc/configuration.txt | 44 +--- 1 files changed, 29 insertions(+), 15 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 398ce87..a94fe21 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7107,23 +7107,37 @@ crl-file crlfile crt cert This setting is only available when support for OpenSSL was built in. - It designates a PEM file from which to load both a certificate and the - associated private key. This file can be built by concatenating both PEM - files into one. If the OpenSSL used supports Diffie-Hellman, parameters - present in this file are also loaded. If a directory name is used instead of a - PEM file, then all files found in that directory will be loaded. This - directive may be specified multiple times in order to load certificates from - multiple files or directories. The certificates will be presented to clients - who provide a valid TLS Server Name Indication field matching one of their CN - or alt subjects. Wildcards are supported, where a wildcard character '*' is - used instead of the first hostname component (eg: *.example.org matches - www.example.org but not www.sub.example.org). If no SNI is provided by the - client or if the SSL library does not support TLS extensions, or if the client - provides and SNI which does not match any certificate, then the first loaded - certificate will be presented. This means that when loading certificates from - a directory, it is highly recommended to load the default one first as a file. + It designates a PEM file containing both the required certificates and any + associated private keys. This file can be built by concatenating multiple + PEM files into one (e.g. cat cert.pem key.pem combined.pem). If your CA + requires an intermediate certificate, this can also be concatenated into + this file. + + If the OpenSSL used supports Diffie-Hellman, parameters present in this file + are loaded. + + If a directory name is used instead of a PEM file, then all files found in + that directory will be loaded. This directive may be specified multiple times + in order to load certificates from multiple files or directories. The certificates + will be presented to clients who provide a valid TLS Server Name Indication + field matching one of their CN or alt subjects. Wildcards are supported, where + a wildcard character '*' is used instead of the first hostname component + (eg: *.example.org matches www.example.org but not www.sub.example.org). + + If no SNI is provided by the client or if the SSL library does not support TLS + extensions, or if the client provides an SNI hostname which does not match any + certificate, then the first loaded certificate will be presented. This means + that when loading certificates from a directory, it is highly recommended + to load the default one first as a file. + Note that the same cert may be loaded multiple times without side effects. + Some CAs (such as Godaddy) offer a drop down list of server types that do + not include HAProxy when obtaining a certificafte. If this happens be sure + to choose a webserver that the CA believes requires a intermediate CA + (for Godaddy, selection Apache Tomcat will get the correct bundle, but many + others, e.g. nginx, result in a wrong bundle that will not work for some clients). + crt-ignore-err errors This setting is only available when support for OpenSSL was built in. Sets a comma separated list of errorIDs to ignore during verify at depth == 0. -- 1.7.1
Re: Experience with HAProxy SSL intermediate certificates - Godaddy and others
Hi Willy, I've just sent a simple patch for this (sorry for the delay). While preparing this, I was not sure what the difference is between the block in section 5.2 (Server and default-server options) and the main documentation; it seems in the case of crt the former has the first few sentances and misses off the last few. Since i'm making teh crt block significantly longer, it seems silly to duplicate this - at the same time it would be a shame for someone to read the top version. I wonder if its worth mentioning that many of the settings are further explained, in more detail, lower down the file in section 4.2, but i've not included this in my patch because its possible i'm missing something! I considered adding something mentioning the very useful tools in my email, but it seems wrong to signpost the ones I selected; I am far from an expert in this area. If there was a intro to SSL section in teh docs, i'd write something explaining that its important to check that non-SNI compliant browsers and ones with older root certificate databases (Java being the one that bit me - as PayPal use it for their API requests) rather than just testing in modern IE/Chrome/FF. But i'm not quite sure where to put this, so i've left it out; if you think this would be helpful i'd be very happy to add it. Thanks, Alex On Sun, Feb 10, 2013 at 10:23 PM, Willy Tarreau w...@1wt.eu wrote: Hi Alex, On Sun, Feb 10, 2013 at 08:46:46PM +, Alex Davies wrote: Hi All, I saw some traffic on the list from Guillaume and others about this, but I thought i'd confirm a real world production use of a GoDaddy[1] SSL certificate (which requires an intermediate certificates for some use cases, specifically Java applications). I used the following line in haproxy.cfg: bind :443 ssl crt /path/to/domain.com.crt ca-file /path/to/ca.pem ciphers ECDHE-RSA-AES256-SHA:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM In /path/to/domain.com.crt, I have My private key (the one used to generate the CSR) The final certificate for my domain (downloaded from the provider) The intermediate certificate (from the .zip file with the CA bundle provided by godaddy) In /path/to/ca.pem I just took the gd_bundle file provided by GoDaddy. I took the ciphers restriction from an exceliance blog post[2]; it seems to effectively shut up the BEAST attack alerts on teh SSL checker websites. I found the utility at https://www.digicert.com/util/ and the online check at https://www.ssllabs.com/ssltest/ super useful. I wonder if it might be helpful to ammend the crt cert documentation to say that Intermediate certificates should be loaded with this (either with multiple crt lines, or concatenation as it already says). This was not obvious to me, and I spent some time failing to get it working using the intermediate certificate within the SSL. I have said it before, but i'd like to say it again - HAProxy is awesome, and the removal of one more chain in the link is fantastic. Thanks guys! Thank you for the informative feedback. You're right, if it took you some time to figure how to do this, then the doc needs to be updated. Could you propose some prose that you think would have helped you ? That would be really great. Do you think it would also be worth adding some scripts in the contrib/ directory to better handle the certificates concatenation into a single file ? Or maybe to check some certs, I don't know. You surely have ideas after all the tests you've performed ! Thanks, -Alex [1] Godaddy ask you to choose your type of SSL provider. I selected nginx as I have used that before, but for some reason it does not provide the intermediate certificate in this case. Select Apache Tomcat to get a zip file with both gd_bundle and the intermediate Cert. This could go into the doc as well, until they add haproxy :-) Cheers, Willy -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
Re: Consistent hashing based on cookie - across multiple HAProxy boxes
I was trying to troubleshoot this with a packet dump on the peer traffic. The raw tcpdump does not mean anything to me, and Wireshark is decoding it as Java RMI traffic which isnt much use, and it looks like a binary protocol. So I can report that 'peer' traffic is certainly working because when I restart one of the haproxy processes there are a bunch of different packets sent (Wireshark doesent even attempt to decode these). I was hoping to be able to grep for one of the offending session IDs to see if that gave me a hint. Does anybody have a working configuration for multi peer persistence based on a cookie that I could test, by chance? Thanks, -Alex
Re: Consistent hashing based on cookie - across multiple HAProxy boxes
H Baptiste and others, I've not been able to get this to work. I have two different haproxy servers with identical config (relevant sections below). When I hit each one with the same PHPSESSID (domain set to .domain.tld) I get put on a (different) consistent server. I've setup cookie capturing in the log to show that PHPSESSID is good; I can telnet across from one peer to the other. I've started both process with -L peer_name_and_also_hostname, but it still wont work. I'm running 1.5-dev17. Relevant log - server 1 [root@frontend1 ~]# tail -f /var/log/haproxy.log | grep /info.php Feb 28 22:55:24 localhost haproxy[18069]: 213.146.182.195:47073[28/Feb/2013:22:55:11.237] main webservers/tc_ww6 13063/0/1/0/13064 200 318 PHPSESSID=d40c28be77d7c9e364ae9fd35f87f62b 11670/11670/17/1/0 0/0 GET /info.php HTTP/1.1 Relevant log - server 2 [root@frontend2 ~]# tail -f /var/log/haproxy.log | grep info.php Feb 28 22:55:37 localhost haproxy[30244]: 213.146.182.195:47120[28/Feb/2013:22:55:36.991] main webservers/tc_ww1 7/0/0/3/10 200 318 PHPSESSID=d40c28be77d7c9e364ae9fd35f87f62b 5/5/0/0/0 0/0 GET /info.php HTTP/1.1 Connection from 1 to 2: [root@frontend1 ~]# telnet 10.99.99.162 1099 Trying 10.99.99.162... Connected to 10.99.99.162. Escape character is '^]'. SOMETHING 501 Connection closed by foreign host. Relevant config: peers frontends peer frontend1 10.99.99.161:1099 peer frontend2 10.99.99.162:1099 frontend main bind :80 capture cookie PHPSESSID len 50 .. backend webservers balance roundrobin stick on cookie(PHPSESSID) stick-table type string size 32k peers frontends expire 24h stick store-response set-cookie(PHPSESSID) server ww1 10.99.99.201:80 weight 5 check observe layer4 inter 1 server ww2 10.99.99.202:80 weight 6 check observe layer4 inter 1 server ww3 10.99.99.203:80 weight 10 check observe layer4 inter 1 ... Thanks, Alex On Sun, Feb 10, 2013 at 9:47 PM, Baptiste bed...@gmail.com wrote: Hi, It's weird you don't need the store-response. Test it as best as you can to avoid any issues later. There is no way to monitor the peering, as far as I know. If a peer is unavailable, it means both haproxy can't reach each others. so you may have a bigger issue to fix before :) This is a multi-master way of working: each haproxy notifies its peers about the changes it made into the table. cheers On Sun, Feb 10, 2013 at 9:36 PM, Alex Davies a...@davz.net wrote: Hi Baptiste (apologies!) I did some testing with this, it actually seemed that stick store-response was not needed. I think this is working, at least it works in my test environment. Will test it for real shortly. One question I had - what is the best way to monitor this peering? I didnt see anything in the logs about the peers, nor anything in the haproxy status URL. Obviously if the peering were to silently break down, this would be bad for me! Thanks, -Alex On Fri, Feb 8, 2013 at 4:22 AM, Baptiste bed...@gmail.com wrote: ahah, you can call me Baptiste :) You miss a stick on cookie(PHPSESSID). Also consider using the same expire delay you have on your application server. And last but not least, add a peers section (and a peer directive on the stick-table definition) where you provide all your HAProxy server IPs in order to get the table of each HAProxy synchronized. then you're done. Baptiste On 2/8/13, Alex Davies a...@davz.net wrote: Hi Willy, Thanks for your suggestion. I'm guessing you mean something like this backend: backend x balance roundrobin stick-table type string size 32k peers other_haproxy_server expire 24h stick store-response set-cookie(PHPSESSID) If I understand you correctly, you are saying that this will only mean that sessions become persistant once PHPSESSID is set. So, to translate into practicality, as long as the login page creates the relevant cooke (and it does not subsequently change once logged in), this should work nicely. Thanks, -Alex On Sun, Feb 3, 2013 at 7:59 AM, Baptiste bed...@gmail.com wrote: Hi, the only way you could do what you want for now is using stick tables (and haproxy 1.5-dev17). You can learn the Set-Cookie from the server and match the Cookie in the table from the client. That way, all the request from a user will be sent to the same server, from the first to the last one. Today, haproxy is able to hash a HTTP header for load-balancing, so a configuration like: balance hdr(Cookie) could do the trick, but it means that ALL clients cookie to load-balance. And worste, since there is no phpsessionid cookie on the first request, there are chances that the first and the second requests won't be routed to the same server. I guess it would be possible soon to have a: balance cook
Re: Consistent hashing based on cookie - across multiple HAProxy boxes
Hi Baptiste (apologies!) I did some testing with this, it actually seemed that stick store-response was not needed. I think this is working, at least it works in my test environment. Will test it for real shortly. One question I had - what is the best way to monitor this peering? I didnt see anything in the logs about the peers, nor anything in the haproxy status URL. Obviously if the peering were to silently break down, this would be bad for me! Thanks, -Alex On Fri, Feb 8, 2013 at 4:22 AM, Baptiste bed...@gmail.com wrote: ahah, you can call me Baptiste :) You miss a stick on cookie(PHPSESSID). Also consider using the same expire delay you have on your application server. And last but not least, add a peers section (and a peer directive on the stick-table definition) where you provide all your HAProxy server IPs in order to get the table of each HAProxy synchronized. then you're done. Baptiste On 2/8/13, Alex Davies a...@davz.net wrote: Hi Willy, Thanks for your suggestion. I'm guessing you mean something like this backend: backend x balance roundrobin stick-table type string size 32k peers other_haproxy_server expire 24h stick store-response set-cookie(PHPSESSID) If I understand you correctly, you are saying that this will only mean that sessions become persistant once PHPSESSID is set. So, to translate into practicality, as long as the login page creates the relevant cooke (and it does not subsequently change once logged in), this should work nicely. Thanks, -Alex On Sun, Feb 3, 2013 at 7:59 AM, Baptiste bed...@gmail.com wrote: Hi, the only way you could do what you want for now is using stick tables (and haproxy 1.5-dev17). You can learn the Set-Cookie from the server and match the Cookie in the table from the client. That way, all the request from a user will be sent to the same server, from the first to the last one. Today, haproxy is able to hash a HTTP header for load-balancing, so a configuration like: balance hdr(Cookie) could do the trick, but it means that ALL clients cookie to load-balance. And worste, since there is no phpsessionid cookie on the first request, there are chances that the first and the second requests won't be routed to the same server. I guess it would be possible soon to have a: balance cook(PHPSessionID) but it won't fix the sticking issue between first and second request since the cookie is not present in the first request. So if you really want using the algorithm method, you must be able to share cookies between your backend servers, only lucky people will be able to get authenticated. Well, maybe there are some dirty tricks like managing a farm for cookie-less clients and configuring PHP to learn an unknown session on the fly. Baptiste On Sun, Feb 3, 2013 at 2:03 AM, Alex Davies a...@davz.net wrote: Hi All, What is the best way to configure haproxy to hash based on an application cookie (such as PHPSESSID), in a way that is consistent (meaning multiple haproxy servers will route to the same backend), ideally including the ability to weight backends (the configuration would clearly have to be the same on these different boxes). appsession obviously allows this for a single HAProxy server, but it seems from the documentation that it generates a server based on the hash at the start of each session, so if the same session hit a different but identically configured haproxy server it would end up with a Thanks, -Alex -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
Experience with HAProxy SSL intermediate certificates - Godaddy and others
Hi All, I saw some traffic on the list from Guillaume and others about this, but I thought i'd confirm a real world production use of a GoDaddy[1] SSL certificate (which requires an intermediate certificates for some use cases, specifically Java applications). I used the following line in haproxy.cfg: bind :443 ssl crt /path/to/domain.com.crt ca-file /path/to/ca.pem ciphers ECDHE-RSA-AES256-SHA:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM In /path/to/domain.com.crt, I have My private key (the one used to generate the CSR) The final certificate for my domain (downloaded from the provider) The intermediate certificate (from the .zip file with the CA bundle provided by godaddy) In /path/to/ca.pem I just took the gd_bundle file provided by GoDaddy. I took the ciphers restriction from an exceliance blog post[2]; it seems to effectively shut up the BEAST attack alerts on teh SSL checker websites. I found the utility at https://www.digicert.com/util/ and the online check at https://www.ssllabs.com/ssltest/ super useful. I wonder if it might be helpful to ammend the crt cert documentation to say that Intermediate certificates should be loaded with this (either with multiple crt lines, or concatenation as it already says). This was not obvious to me, and I spent some time failing to get it working using the intermediate certificate within the SSL. I have said it before, but i'd like to say it again - HAProxy is awesome, and the removal of one more chain in the link is fantastic. Thanks guys! Thanks, -Alex [1] Godaddy ask you to choose your type of SSL provider. I selected nginx as I have used that before, but for some reason it does not provide the intermediate certificate in this case. Select Apache Tomcat to get a zip file with both gd_bundle and the intermediate Cert. [2] http://blog.exceliance.fr/2013/01/21/mitigating-the-ssl-beast-attack-using-the-aloha-load-balancer-haproxy/
Re: Consistent hashing based on cookie - across multiple HAProxy boxes
Hi Willy, Thanks for your suggestion. I'm guessing you mean something like this backend: backend x balance roundrobin stick-table type string size 32k peers other_haproxy_server expire 24h stick store-response set-cookie(PHPSESSID) If I understand you correctly, you are saying that this will only mean that sessions become persistant once PHPSESSID is set. So, to translate into practicality, as long as the login page creates the relevant cooke (and it does not subsequently change once logged in), this should work nicely. Thanks, -Alex On Sun, Feb 3, 2013 at 7:59 AM, Baptiste bed...@gmail.com wrote: Hi, the only way you could do what you want for now is using stick tables (and haproxy 1.5-dev17). You can learn the Set-Cookie from the server and match the Cookie in the table from the client. That way, all the request from a user will be sent to the same server, from the first to the last one. Today, haproxy is able to hash a HTTP header for load-balancing, so a configuration like: balance hdr(Cookie) could do the trick, but it means that ALL clients cookie to load-balance. And worste, since there is no phpsessionid cookie on the first request, there are chances that the first and the second requests won't be routed to the same server. I guess it would be possible soon to have a: balance cook(PHPSessionID) but it won't fix the sticking issue between first and second request since the cookie is not present in the first request. So if you really want using the algorithm method, you must be able to share cookies between your backend servers, only lucky people will be able to get authenticated. Well, maybe there are some dirty tricks like managing a farm for cookie-less clients and configuring PHP to learn an unknown session on the fly. Baptiste On Sun, Feb 3, 2013 at 2:03 AM, Alex Davies a...@davz.net wrote: Hi All, What is the best way to configure haproxy to hash based on an application cookie (such as PHPSESSID), in a way that is consistent (meaning multiple haproxy servers will route to the same backend), ideally including the ability to weight backends (the configuration would clearly have to be the same on these different boxes). appsession obviously allows this for a single HAProxy server, but it seems from the documentation that it generates a server based on the hash at the start of each session, so if the same session hit a different but identically configured haproxy server it would end up with a Thanks, -Alex
Consistent hashing based on cookie - across multiple HAProxy boxes
Hi All, What is the best way to configure haproxy to hash based on an application cookie (such as PHPSESSID), in a way that is consistent (meaning multiple haproxy servers will route to the same backend), ideally including the ability to weight backends (the configuration would clearly have to be the same on these different boxes). appsession obviously allows this for a single HAProxy server, but it seems from the documentation that it generates a server based on the hash at the start of each session, so if the same session hit a different but identically configured haproxy server it would end up with a Thanks, -Alex
Re: Rate limiting- queueing requests
Hi Willy, I never replied to this mail, my apologies! Thank you for your suggestions. Sadly, in our case, neither approach works - but it was worth asking you first. I solved our problem with something that executes right at the start of our application, Thank you! Alex On Wed, Nov 28, 2012 at 7:20 AM, Willy Tarreau w...@1wt.eu wrote: Hi Alex, On Tue, Nov 27, 2012 at 11:41:08PM +, Alex Davies wrote: Hey All, I have an application that can only handle. to some URLs, one request every x seconds from each session (identified by a specific cookie). Rather than adding logic to handle this to the application itself (which I fear I will have to do), I would like to know if it is possible to use the rate limiting functionality in HAProxy to delay the sending of a request to the backend to the time the last request was sent + x fraction of a second? I see a bunch of example configs on the internet to reject connections over x per second but nothing that queues requests in a order. If you have just a few such URLs, one thing you could do which will approach your need is to have a backend per URL (or per group of URL), in which a tcp-request content rule causes artificially long pauses when the session rate is too high. This can work well as long as the number of concurrent connections on that backend remains low and known (so that you can adjust the timer). If you need only one connection at a time, you could chain a server with maxconn 1 to such an installation. A simple example would consist in this : frontend front use_backend limited if { path_beg /foo /bar } # limited to 2 requests per second backend limited tcp-request inspect-delay 500 tcp-request content accept if { be_sess_rate le 2 } || WAIT_END server ... This can work well for printing devices or PDF generators for example. It won't work well at all if you don't know the number of concurrent users, in which case it could be done like this (even uglier) : frontend front use_backend serialize if { path_beg /foo /bar } # serialize requests backend serialize server limited 127.0.0.1:1 maxconn 1 send-proxy # limited to 2 requests per second listen limited bind 127.0.0.1:1 accept-proxy tcp-request inspect-delay 500 tcp-request content accept if { be_sess_rate le 2 } || WAIT_END server ... This time it will do the job whatever the number of concurrent clients. But it's not very pretty... Willy -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
Rate limiting- queueing requests
Hey All, I have an application that can only handle. to some URLs, one request every x seconds from each session (identified by a specific cookie). Rather than adding logic to handle this to the application itself (which I fear I will have to do), I would like to know if it is possible to use the rate limiting functionality in HAProxy to delay the sending of a request to the backend to the time the last request was sent + x fraction of a second? I see a bunch of example configs on the internet to reject connections over x per second but nothing that queues requests in a order. Thanks! -Alex
Source IP rate limiting
Hi, I am interested in rate limiting connections from users to stop small DOS 'attacks' from individual users. I see the excellent post at http://blog.serverfault.com/post/1016491873/ and have followed this in a test enviroment. I have the following questions: * What is the best way to monitor the # of connections that are being rejected as a result of this from the log? The socat example in that post seems - to me - to show the number of IPs in the relevant tables as opposed to the number of connections that are being rejected. Is it possible also to know which 'reject' the request is blocked by (from the example post there are 2) * Is it possible to 'hash' on a specific cookie value (i'm thinking PHPSESSID) as well as IP, i.e. if connections for any given PHPSESSID value reaches x per minute block? Many thanks, Alex -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
Re: Source IP rate limiting
Hi, Thanks for your reply. What is the 'signature' that is unique in the logs for this kind of block? I have HTTP logs enabled; for the Session state at disconnection part of the log would I be looking for a first letter of P or R for clients blocked by these filters? (and it it possible to distinguish clients blocked because of these ACLs compared to other reasons for a P or R? I am using a command like this: [root@frontend2 ~]# tail -f /var/log/haproxy.log | awk -F' ' '{ if ($15 ~ /^P/) print $0 }' Nov 10 16:17:26 localhost haproxy[11102]: 64.41.0.39:4192[10/Nov/2011:16:17:26.788] main webservers/NOSRV -1/-1/-1/-1/15 -1 0 - - PRNN 7694/7694/119/0/30 0/0 GET /images/face_05.gif HTTP/1.1 But in this particular case the problem is (from my reading) that the client failed to send a complete request, not a ACL. As for a sticky table to store the PHPSESSID and block, am I along the right track with a config like this?: backend x stick-table type string size 500k stick store-request cookie(PHPSESSID) table cookie_sc2_conn_rate acl cookie_conn_rate_abuse cookie_sc2_conn_rate gt 300 acl mark_as_abuser sc1_inc_gpc0 gt 0 tcp-request content reject if cookie_conn_rate_abuse mark_as_abuser Many thanks, Alex On Thu, Nov 10, 2011 at 12:56 PM, Baptiste bed...@gmail.com wrote: On Thu, Nov 10, 2011 at 12:48 PM, Alex Davies a...@davz.net wrote: Hi, I am interested in rate limiting connections from users to stop small DOS 'attacks' from individual users. I see the excellent post at http://blog.serverfault.com/post/1016491873/ and have followed this in a test enviroment. I have the following questions: * What is the best way to monitor the # of connections that are being rejected as a result of this from the log? The socat example in that post seems - to me - to show the number of IPs in the relevant tables as opposed to the number of connections that are being rejected. Is it possible also to know which 'reject' the request is blocked by (from the example post there are 2) * Is it possible to 'hash' on a specific cookie value (i'm thinking PHPSESSID) as well as IP, i.e. if connections for any given PHPSESSID value reaches x per minute block? Many thanks, Alex -- Alex Davies Hin, You can know the numbre of rejected request through the logs. You can use a str stick table and store the PHPSESSID in it. And you can capture the cookie value in the logs as well to know how many request have been rejected. cheers -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
Re: haproxy - kernel socket and # files limits
Hi Willy, Thank you for your detailed explanation; you are entirely right and the limit that was screwing me was the limit of fds/process which I have now fixed. Can you explain which parameter should be set to 2 to prevent malloc() fails when there is no more memory left? Many thanks, Alex On Tue, Oct 4, 2011 at 6:49 AM, Willy Tarreau w...@1wt.eu wrote: Hi Alex, On Tue, Oct 04, 2011 at 01:38:40AM +0100, Alex Davies wrote: Hi, I am running haproxy 1.4.18 on RHEL6 (64 bit). I am trying to run a large number of connections (I have long pooling backends), ideally several hundred k. My servers have 24G RAM and are doing nothing else. I have two problems. Firstly, if I increase teh nofile hard limit in /etc/security/limits.conf to anything over 1048576 (1 Megabyte, although I think this is defined as a # of files) I can't SSH to the box or start haproxy - new SSH connections are immediately closed without entries in the logs. The kernel limit (/proc/sys/fs/file-max) is set to 200k without problem. Haproxy balks as follows: Starting haproxy: [WARNING] 276/012759 (2924) : [/usr/sbin/haproxy.main()] Cannot raise FD limit to 246. [WARNING] 276/012759 (2924) : [/usr/sbin/haproxy.main()] FD limit (1048576) too low for maxconn=100/maxsock=246. Please raise 'ulimit-n' to 246 or more to avoid any trouble. There is a default limit of 1048576 fds per process, which you can change with nr_open. But be careful when increasing all those values! Some programs might not like it at all and some scripts may become slow as hell when they close every possible fd before a fork(). So you don't want to have everything running unlimited. Ideally, keep the default ulimit at 1024 and let haproxy change it without impacting other processes. Note: the highest test that was done on haproxy was with 1M fds, nothing above (about 480k conns). Secondly, I notice that as my number of connections rises I get Out of socket memory errors in the kernel log. Google led me to believe that this would be a problem caused by excessive orphan sockets, but this seems not to be the case: I don't believe in orphans too for this case, because normally you see a message too many of orphans long before running out of memory, since orphans are often limited to a small number. [root@frontend2 log]# cat /proc/net/sockstat | grep orphan TCP: inuse 134376 orphan 0 tw 87 alloc 150249 mem 100217 (output taken during a time of problem, where haproxy was mostly inaccessible and most connections were refused) I also seem to have plenty of spare sockets: [root@frontend2 log]# cat /proc/sys/net/ipv4/tcp_mem 2303712 3071616 4607424 [root@frontend2 log]# cat /proc/net/sockstat sockets: used 150458 TCP: inuse 134376 orphan 1 tw 69 alloc 150250 mem 100217 UDP: inuse 12 mem 3 UDPLITE: inuse 0 RAW: inuse 0 FRAG: inuse 0 memory 0 (100217 4607424 by some margin). The usual thing is when some socket buffers are too large. For instance, the default 87k read and 64k write buffers imply that you consume 150k by default for each socket, until the kernel starts to reclaim socket memory. All the people I know who use very large amounts of sockets use small buffers, both in haproxy and in the kernel, because most often it's for chat/websocket or such things which transport few data. You could very well set your default kernel TCP buffers to 8k and let them grow larger if needed : tcp_rmem 4096 8192 65536 tcp_wmem 4096 8192 65536 You should never forget that a full connection through haproxy uses : - 2 TCP sockets, so 2 tcp_rmem and 2 tcp_wmem - 2 haproxy buffers (one per direction), each of global.bufsize. So if you set haproxy to 8kB and your kernel to 8kB, you will need 16kB for haproxy and 32kB for the system = 48kB per connection. That's already too much for 1M connections at 24 GB. The kernel will never go below 4kB, and at this point you'll have 32kB total = 32 GB of RAM per million connection. Ideally i'd like to set the number of open files and sockets to as close to infinite as possible - and allow them to use all the system RAM. You will use all the system's RAM if socket buffers are properly tuned. I'm used to say that you need 1/3 of the RAM for TCP buffers, another 1/3 for haproxy and the last 1/3 for the rest of the system (caches, ...). With 24 GB, you can even assume close to 12+12 and almost nothing for the system. Your TCP settings already allow you to use up to 18 GB RAM for sockets. Haproxy will allocate what it needs for its maxconn, so in practice you can max out memory. It is even a bit dangerous, you should ensure that the system will never overcommit memory (set the param to 2) so that it fails on malloc() when the limit is reached instead of pretending the memory exists and killing the process when it tries to use it. But that's for a second point. Regards, Willy -- Alex
haproxy - kernel socket and # files limits
Hi, I am running haproxy 1.4.18 on RHEL6 (64 bit). I am trying to run a large number of connections (I have long pooling backends), ideally several hundred k. My servers have 24G RAM and are doing nothing else. I have two problems. Firstly, if I increase teh nofile hard limit in /etc/security/limits.conf to anything over 1048576 (1 Megabyte, although I think this is defined as a # of files) I can't SSH to the box or start haproxy - new SSH connections are immediately closed without entries in the logs. The kernel limit (/proc/sys/fs/file-max) is set to 200k without problem. Haproxy balks as follows: Starting haproxy: [WARNING] 276/012759 (2924) : [/usr/sbin/haproxy.main()] Cannot raise FD limit to 246. [WARNING] 276/012759 (2924) : [/usr/sbin/haproxy.main()] FD limit (1048576) too low for maxconn=100/maxsock=246. Please raise 'ulimit-n' to 246 or more to avoid any trouble. Secondly, I notice that as my number of connections rises I get Out of socket memory errors in the kernel log. Google led me to believe that this would be a problem caused by excessive orphan sockets, but this seems not to be the case: [root@frontend2 log]# cat /proc/net/sockstat | grep orphan TCP: inuse 134376 orphan 0 tw 87 alloc 150249 mem 100217 (output taken during a time of problem, where haproxy was mostly inaccessible and most connections were refused) I also seem to have plenty of spare sockets: [root@frontend2 log]# cat /proc/sys/net/ipv4/tcp_mem 2303712 3071616 4607424 [root@frontend2 log]# cat /proc/net/sockstat sockets: used 150458 TCP: inuse 134376 orphan 1 tw 69 alloc 150250 mem 100217 UDP: inuse 12 mem 3 UDPLITE: inuse 0 RAW: inuse 0 FRAG: inuse 0 memory 0 (100217 4607424 by some margin). Ideally i'd like to set the number of open files and sockets to as close to infinite as possible - and allow them to use all the system RAM. Would anybody with more knowledge in this area be able to shed any light? - Alex
Re: haproxy / Python 'tornado' framework - digging into 502/504 errors
Hi Willy, Cyril, Thank you for your detailed analysis. I still notice 504 errors almost immediately on a HAproxy start, and the PID matches the new process: [root@frontend2 log]# ps aux | grep haproxy haproxy 21242 6.6 0.1 133176 47984 ?Rs 07:17 0:00 /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid [root@frontend2 log]# service haproxy stop; service rsyslog stop; rm -f /var/log/haproxy.log; service rsyslog start; service haproxy start; Stopping haproxy: [ OK ] Shutting down system logger: [ OK ] Starting system logger:[ OK ] Starting haproxy: [ OK ] [root@frontend2 log]# tail -f haproxy.log | grep 504 Sep 14 07:16:14 localhost haproxy[21178]: 94.197.40.185:3504[14/Sep/2011:07:16:08.216] main python_8001/python_8001_fe1 80/0/0/-1/6449 502 204 - - SH-- 3375/3375/950/950/0 0/0 POST /xxx/chat/status/updates HTTP/1.1 Sep 14 07:16:15 localhost haproxy[21178]: 118.101.95.88:49504[14/Sep/2011:07:16:10.298] main python_9003/python_9003_fe1 22/0/0/-1/5088 502 204 - - SH-- 3312/3312/386/386/0 0/0 POST /xxx/chat/message/3/updates HTTP/1.1 ^C [root@frontend2 log]# ps aux | grep haproxy haproxy 21178 5.4 0.2 137268 51480 ?Ss 07:16 0:01 /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid I don't understand how this is - can you shed any light? (the configuration is the same as in my email - i.e. server timeout 2hrs). I will investigate the 502 errors with more benchmarking directly against the backends. Thank you for confirming that this is the source of the problem. Many thanks, Alex On Tue, Sep 13, 2011 at 11:41 PM, Willy Tarreau w...@1wt.eu wrote: Hi Alex, On Tue, Sep 13, 2011 at 03:18:54PM +0100, Alex Davies wrote: Hi, Thank you for your observation - indeed I did notice some of those as I was writing my email - I have updated my globals to increase the server timeout (as we are doing long polling) and reduce the others, and remove the duplicates: defaults mode http optionhttplog #option tcplog optiondontlognull optiondontlog-normal log global retries 10 maxconn 5 option forwardfor except 127.0.0.1/32 # Apache on https://127.0.0.1 option httpclose # Required for REMOTE HEADER option redispatch timeout connect 1 timeout client 1 timeout server 720 I still notice the same errors in the logs! (slightly less 504, as I would expect through the increase in timeout server - but I still don't understand why I get any at all in the first minute of a new process). To complete Cyril's detailed analysis, I'd like to add that you'll only see 502s when you restart, and it will take some time before you see 504s again (eg: 2 hours with the config above). The 502s mean that the server has suddenly aborted the connection (flags SH), while the 504s indicate that haproxy was fed up with waiting and closed after timeout server was elapsed. So yes it's very possible that your server has its own timeout, but it should be in the 30s from what I saw in your logs. It sill does not explain why some requests never time out on the server, maybe they don't wake the same components up ? Regards, Willy -- Alex Davies This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender immediately by e-mail and delete this e-mail permanently.
haproxy / Python 'tornado' framework - digging into 502/504 errors
Hi, I am not a haproxy expert, but have been using it in production for some time with excellent results and I wonder if I can seek some expert advice on running the fairly fast application server http://www.tornadoweb.org/ behind HAproxy (haproxy-1.3.23 using the EPEL RPM (-1) on RHEL6 x86_64). Haproxy is working very well for me, but i'm looking for help understanding how I can diagnose problems with the Tornado application I have running behind it. I have ~8 tornado processes running on two servers. Its important that one is active and the other is failover (some state is stored in memory). The parts of my haproxy configuration relevant to my question are below. I notice a large number of entries in the logs like this: 502 errors: Sep 13 12:42:45 localhost haproxy[15128]: 188.222.50.208:61001[13/Sep/2011:12:42:43.881] main python_8001/python_8001_fe1 10/0/0/-1/1527 502 204 - - SH-- 6676/6676/2082/2082/0 0/0 POST /xxx/chat/status/updates HTTP/1.1 Sep 13 12:42:45 localhost haproxy[15128]: 81.246.46.162:29456[13/Sep/2011:12:42:14.289] main python_8001/python_8001_fe1 28/0/0/-1/31118 502 204 - - SH-- 6675/6675/2081/2081/0 0/0 POST /xxx/chat/status/updates HTTP/1.1 504 errors: Sep 13 12:43:08 localhost haproxy[15128]: 180.234.122.248:52888[13/Sep/2011:12:38:08.822] main python_9004/python_9004_fe1 45/0/0/-1/300045 504 194 - - sH-- 6607/6607/697/697/0 0/0 POST /xxx/chat/message/4/updates HTTP/1.1 Sep 13 12:43:09 localhost haproxy[15128]: 82.26.136.198:61758[13/Sep/2011:12:38:09.071] main python_8001/python_8001_fe1 19/0/0/-1/300020 504 194 - - sH-- 6569/6569/2085/2085/0 0/0 POST /xxx/chat/status/updates HTTP/1.1 It seems to me that all of these involve 0 seconds waiting in a queue, 0 seconds to make a connection to the final app server and then a aborted connection to the app server before a complete response could be received The total time in milliseconds between accept and last close seems to be ~300 seconds for most of the requests (although far from all of them, as the first entry shows). If I *restart* (not reload) haproxy, I still get lines with the fifth of these numbers (Tt in the docs) as ~300,000 (the timeout server value in the config at the moment I copied the logs above), a few seconds after the haproxy process starts. I also get lots that seem to end on almost exactly 300k even when I change both timeout client and timeout server to very different numbers. It is possible that the application (jQuery) has a 300s timeout hardcoded, but in any case I do not understand why the haproxy logs show connections with a connection of 300k failing when I stop haproxy, increase timeout server by a order of magnitude and start it again. Looking at the next part of the log entries it seems that bytes_read is always 204 for 504 errors and 194 for 504 errors. This does seem to be a fairly regular pattern: [root@frontend2 log]# cat /var/log/haproxy.log | grep 504 194 | wc -l 1975 [root@frontend2 log]# cat /var/log/haproxy.log | grep 502 204 | wc -l 12401 [root@frontend2 log]# cat /var/log/haproxy.log | wc -l 18721 My second question is how do I find out exactly what is being returned (easily), i.e. what are those 194/204 bytes? This might give me a hint as to what is going wrong or timing out on the application server. I guess I could try to tcpdump but I might struggle to actually filter down the correct data (there are large numbers of successful connections going on) The next part of the logs are most interesting; ignoring the two cookie fields we see that the the server-side timeout expired for the 504 errors and the TCP session was unexpectedly aborted by the server, or the server explicitly refused it in the case of the 502. Subject to my questions above I have a theory that the 504s are caused by the long-pooling application, but I do not understand why in the case of the 502 haproxy is not retrying the TCP connection before returning a 502 - I thought that the option redispatch and retries 10 would ensure another go. If anybody is able to shed some thoughts on my two questions I would be very grateful! Many thanks, Alex # haproxy.conf global log 127.0.0.1 local4 debug chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 5 userhaproxy group haproxy daemon defaults mode http optionhttplog #option tcplog optiondontlognull optiondontlog-normal log global retries 10 maxconn 5 timeout connect 20 contimeout20 clitimeout9 option forwardfor except 127.0.0.1/32 # Apache running https on localhost option httpclose # Required for REMOTE HEADER option redispatch timeout connect 1 timeout client 30 timeout server 30 frontend main *:80 acl url_py_8001 path_beg -i /url1 acl url_py_8002 path_beg -i
Re: haproxy / Python 'tornado' framework - digging into 502/504 errors
Hi, Thank you for your observation - indeed I did notice some of those as I was writing my email - I have updated my globals to increase the server timeout (as we are doing long polling) and reduce the others, and remove the duplicates: defaults mode http optionhttplog #option tcplog optiondontlognull optiondontlog-normal log global retries 10 maxconn 5 option forwardfor except 127.0.0.1/32 # Apache on https://127.0.0.1 option httpclose # Required for REMOTE HEADER option redispatch timeout connect 1 timeout client 1 timeout server 720 I still notice the same errors in the logs! (slightly less 504, as I would expect through the increase in timeout server - but I still don't understand why I get any at all in the first minute of a new process). Cheers, Alex On Tue, Sep 13, 2011 at 1:46 PM, Cyril Bonté cyril.bo...@free.fr wrote: clitimeout
haproxy / Python 'tornado' framework - digging into 502/504 errors
Hi, Thank you for your observation - indeed I did notice some of those as I was writing my email - I have updated my globals to increase the server timeout (as we are doing long polling) and reduce the others, and remove the duplicates: defaults mode http optionhttplog #option tcplog optiondontlognull optiondontlog-normal log global retries 10 maxconn 5 option forwardfor except 127.0.0.1/32 # Apache on https://127.0.0.1 option httpclose # Required for REMOTE HEADER option redispatch timeout connect 1 timeout client 1 timeout server 720 I still notice the same errors in the logs! (slightly less 504, as I would expect through the increase in timeout server - but I still don't understand why I get any at all in the first minute of a new process). Cheers, Alex On Tue, Sep 13, 2011 at 1:46 PM, Cyril Bonté cyril.bo...@free.fr wrote: clitimeout