- Limit max connections per IP address and new connections per second with iptables
- Как ограничить количество подключений (запросов) в NGINX
- Ограничение количества соединений в NGINX
- Проверка лимита подключений Nginx
- Ограничение количества подключений Nginx к приложению
- Increasing the maximum number of TCP/IP connections in Linux
- 5 Answers 5
Limit max connections per IP address and new connections per second with iptables
This will reject connections above 15 from one source IP.
iptables -A INPUT -m state --state RELATED,ESTABLISHED -m limit --limit 150/second --limit-burst 160 -j ACCEPT
In this 160 new connections (packets really) are allowed before the limit of 150 NEW connections (packets) per second is applied.
The second rule does NOT work on «new connections». It explicitly affects existing («ESTABLISHED») connections. To do new connections, you would want —state NEW. You might also consider using -m conntrack —ctstate in place of -m state —state . conntrack is new and improved vs. state.
the comment above for adding the 2nd rule to NEW connections — do not do that — it effectively turns your INPUT chain into a default accept .
You want the following rules in your iptables to answer both requirements in your question:
iptables -t filter -I INPUT -p tcp --dport 80 -j ACCEPT iptables -t filter -I INPUT -p tcp --dport 80 -m state \ --state RELATED,ESTABLISHED -j ACCEPT # Adjust "--connlimit-above NN" to limit the maximum connections per IP # that you need. iptables -t filter -I INPUT -p tcp --syn --dport 80 -m connlimit \ --connlimit-above 10 --connlimit-mask 32 -j DROP # Adjust "--connlimit-above NNN" to the maximum total connections you # want your web server to support iptables -t filter -I INPUT -p tcp --syn --dport 80 -m connlimit \ --connlimit-above 150 -j DROP
Because we are using -I (as per the OP request) we have to do them in reverse order so ‘read’ them from the bottom up.
I also suggest considering —connlimit-mask NN change from 32 to 24. This will limit a full Class-C network (max 256 IP addresses in the same range) to 10 connections. You could also use any other classless number like 22 or 30 depending on how you think your service might be used.
Also depending on how you want the client to behave, you might want to use «-j REJECT —reject-with tcp-reset» instead of «-j DROP» in the two rules above, or even only in the 150 connections max rule.
If you REJECT the connection the browser or software using port 80 will show a «not available» status immediately, but the DROP option will cause the client to wait and retry a few times before reporting the site as not available. I tend to lean to the DROP myself as it behaves more like a bad connection than an offline server.
Also, if the connection limit drops back down below 150 (or 10) while it is still retrying, then it will finally get through to your server.
The REJECT option will cause a fraction less traffic to your site however, as DROP will cause it to send additional packets while it retries. Probably not all that relevant.
If on the other hand your port 80 traffic is part of a cluster then REJECT will tell the cluster controller that it’s down and to stop sending traffic to it for the duration of it’s retry timeout.
The RELATED,ESTABLISHED rule is there under the assumption your default rule is to block all traffic (iptables -t filter -P INPUT DROP). This just accepts futher packets belonging to accepted connections.
Also —syn tells it to pay attention to (or count) the packets that set up a TCP connection.
Как ограничить количество подключений (запросов) в NGINX
NGINX поставляется с различными модулями, позволяющими пользователям контролировать трафик своих веб-сайтов, веб-приложений и других веб-ресурсов. Одной из основных причин ограничения трафика или доступа является предотвращение злоупотреблений или атак определенных видов, таких как DoS (отказ в обслуживании).
Существует три основных способа ограничения использования или трафика в NGINX:
- Ограничение количества подключений (запросов).
- Ограничение количества запросов.
- Ограничение пропускной способности.
Вышеупомянутые подходы к управлению трафиком NGINX, в зависимости от варианта использования, могут быть настроены для ограничения на основе определенного ключа, наиболее распространенным из которых является IP-адрес клиента. NGINX также поддерживает другие переменные, такие как файл cookie сеанса и многие другие.
В этой первой части нашей серии из трех частей мы обсудим, как ограничить количество подключений в NGINX для защиты ваших веб-сайтов/приложений.
- Как ограничить количество подключений (запросов) в NGINX — часть 1
- Как ограничить скорость соединений (запросов) в NGINX — часть 2
- Как ограничить использование пропускной способности в NGINX — часть 3
Имейте в виду, что NGINX будет рассматривать соединение для ограничения, только если у него есть запрос, обрабатываемый сервером, и весь заголовок запроса уже прочитан. Поэтому учитываются не все клиентские подключения.
Ограничение количества соединений в NGINX
Во-первых, вам нужно определить зону общей памяти, в которой хранятся метрики подключения для различных ключей, используя директиву limit_conn_zone. Как упоминалось ранее, ключ может быть текстом, переменной, такой как удаленный IP-адрес клиента, или их комбинацией.
Эта директива, действующая в контексте HTTP, принимает два параметра: ключ и зону (в формате имя_зоны:размер).
limit_conn_zone $binary_remote_addr zone=limitconnbyaddr:20m;
Чтобы задать код состояния ответа, возвращаемый на отклоненные запросы, используйте директиву limit_conn_status, которая принимает в качестве параметра код состояния HTTP. Он действителен в контексте HTTP, сервера и местоположения.
Чтобы ограничить количество подключений, используйте директиву limint_conn, чтобы задать используемую зону памяти и максимальное количество разрешенных подключений, как показано в следующем фрагменте конфигурации. Эта директива действительна в контексте HTTP, сервера и местоположения.
limit_conn limitconnbyaddr 50;
upstream api_service < server 127.0.0.1:9051; server 10.1.1.77:9052; >limit_conn_zone $binary_remote_addr zone=limitconnbyaddr:20m; limit_conn_status 429; server < listen 80; server_name testapp.linux-console.net; root /var/www/html/testapp.linux-console.net/build; index index.html; limit_conn limitconnbyaddr 50; #include snippets/error_pages.conf; proxy_read_timeout 600; proxy_connect_timeout 600; proxy_send_timeout 600; location / < try_files $uri $uri/ /index.html =404 =403 =500; >location /api < proxy_pass http://api_service; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; >>
Сохраните файл и закройте его.
Затем проверьте правильность конфигурации NGINX, выполнив следующую команду:
Затем перезагрузите службу NGINX, чтобы применить последние изменения:
$ sudo systemctl reload nginx
Проверка лимита подключений Nginx
Когда клиент превышает максимально допустимое количество подключений, NGINX возвращает клиенту ошибку «429 Слишком много запросов» и регистрирует запись, подобную приведенной ниже в файл журнала ошибок:
2022/03/15 00:14:00 [error] 597443#0: *127 limiting connections by zone "limitconnbyaddr", client: x.x.x.x, server: testapp.tecmimt.com, request: "GET /static/css/main.63fdefff.chunk.css.map HTTP/1.1", host: "testapp.tecmimt.com"
Ограничение количества подключений Nginx к приложению
Вы также можете ограничить количество соединений для данного сервера, используя переменную $server_name:
upstream api_service < server 127.0.0.1:9051; server 10.1.1.77:9052; >limit_conn_zone $server_name zone=limitbyservers:10m; limit_conn_status 429; server < listen 80; server_name testapp.linux-console.net; root /var/www/html/testapp.linux-console.net/build; index index.html; limit_conn limitbyservers 2000; #include snippets/error_pages.conf; proxy_read_timeout 600; proxy_connect_timeout 600; proxy_send_timeout 600; location / < try_files $uri $uri/ /index.html =404 =403 =500; >location /api < proxy_pass http://api_service; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; >>
Эта конфигурация позволяет NGINX ограничить общее количество подключений к виртуальному серверу, на котором работает приложение testapp.linux-console.net, до 2000 подключений.
Примечание. Ограничение подключений на основе IP-адреса клиента имеет и обратную сторону. В конечном итоге вы можете ограничить подключения для нескольких пользователей, особенно если многие пользователи, получающие доступ к вашему приложению, находятся в одной сети и работают за NAT — все их подключения будут исходить с одного и того же IP-адреса.
В таком сценарии вы можете использовать одну или несколько переменных, доступных в NGINX, которые могут идентифицировать клиента на уровне приложения, например, файл cookie сеанса.
Вам также могут понравиться следующие статьи, связанные с Nginx:
- Как создать пользовательскую страницу ошибки 404 в NGINX
- Как управлять доступом на основе IP-адреса клиента в NGINX
- Как кэшировать контент в NGINX
- Как включить HTTP/2.0 в Nginx
- Как использовать Nginx в качестве балансировщика нагрузки HTTP в Linux
Это все на данный момент! В следующей части этой серии мы обсудим еще один полезный метод управления трафиком в NGINX — ограничение скорости запросов. А пока оставайтесь с нами.
Increasing the maximum number of TCP/IP connections in Linux
I am programming a server and it seems like my number of connections is being limited since my bandwidth isn’t being saturated even when I’ve set the number of connections to «unlimited». How can I increase or eliminate a maximum number of connections that my Ubuntu Linux box can open at a time? Does the OS limit this, or is it the router or the ISP? Or is it something else?
@Software Monkey: I answered this anyway because I hope this might be useful to someone who actually is writing a server in the future.
@derobert: I saw that +1. Actually, I had the same thought after my previous comment, but thought I would let the comment stand.
5 Answers 5
Maximum number of connections are impacted by certain limits on both client & server sides, albeit a little differently.
On the client side: Increase the ephermal port range, and decrease the tcp_fin_timeout
To find out the default values:
sysctl net.ipv4.ip_local_port_range sysctl net.ipv4.tcp_fin_timeout
The ephermal port range defines the maximum number of outbound sockets a host can create from a particular I.P. address. The fin_timeout defines the minimum time these sockets will stay in TIME_WAIT state (unusable after being used once). Usual system defaults are:
This basically means your system cannot consistently guarantee more than (61000 — 32768) / 60 = 470 sockets per second. If you are not happy with that, you could begin with increasing the port_range . Setting the range to 15000 61000 is pretty common these days. You could further increase the availability by decreasing the fin_timeout . Suppose you do both, you should see over 1500 outbound connections per second, more readily.
To change the values:
sysctl net.ipv4.ip_local_port_range="15000 61000" sysctl net.ipv4.tcp_fin_timeout=30
The above should not be interpreted as the factors impacting system capability for making outbound connections per second. But rather these factors affect system’s ability to handle concurrent connections in a sustainable manner for large periods of «activity.»
Default Sysctl values on a typical Linux box for tcp_tw_recycle & tcp_tw_reuse would be
net.ipv4.tcp_tw_recycle=0 net.ipv4.tcp_tw_reuse=0
These do not allow a connection from a «used» socket (in wait state) and force the sockets to last the complete time_wait cycle. I recommend setting:
sysctl net.ipv4.tcp_tw_recycle=1 sysctl net.ipv4.tcp_tw_reuse=1
This allows fast cycling of sockets in time_wait state and re-using them. But before you do this change make sure that this does not conflict with the protocols that you would use for the application that needs these sockets. Make sure to read post «Coping with the TCP TIME-WAIT» from Vincent Bernat to understand the implications. The net.ipv4.tcp_tw_recycle option is quite problematic for public-facing servers as it won’t handle connections from two different computers behind the same NAT device, which is a problem hard to detect and waiting to bite you. Note that net.ipv4.tcp_tw_recycle has been removed from Linux 4.12.
On the Server Side: The net.core.somaxconn value has an important role. It limits the maximum number of requests queued to a listen socket. If you are sure of your server application’s capability, bump it up from default 128 to something like 128 to 1024. Now you can take advantage of this increase by modifying the listen backlog variable in your application’s listen call, to an equal or higher integer.
sysctl net.core.somaxconn=1024
txqueuelen parameter of your ethernet cards also have a role to play. Default values are 1000, so bump them up to 5000 or even more if your system can handle it.
ifconfig eth0 txqueuelen 5000 echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local
Similarly bump up the values for net.core.netdev_max_backlog and net.ipv4.tcp_max_syn_backlog . Their default values are 1000 and 1024 respectively.
sysctl net.core.netdev_max_backlog=2000 sysctl net.ipv4.tcp_max_syn_backlog=2048
Now remember to start both your client and server side applications by increasing the FD ulimts, in the shell.
Besides the above one more popular technique used by programmers is to reduce the number of tcp write calls. My own preference is to use a buffer wherein I push the data I wish to send to the client, and then at appropriate points I write out the buffered data into the actual socket. This technique allows me to use large data packets, reduce fragmentation, reduces my CPU utilization both in the user land and at kernel-level.