1. L4 LB

Nginx L4 LB process TCP/UPD by stream directive by 7 stages:

  1. 1. Post-accept
  2. The first phase after accepting a client connection. The ngx_stream_realip_module module is invoked at this phase.
  3. 2. Pre-access
  4. Preliminary check for access. The ngx_stream_limit_conn_module and ngx_stream_set_module modules are invoked at this phase.
  5. 3. Access
  6. Client access limitation before actual data processing. The ngx_stream_access_module module is invoked at this phase.
  7. 4. SSL
  8. TLS/SSL termination. The ngx_stream_ssl_module module is invoked at this phase.
  9. 5. Preread
  10. Reading initial bytes of data into the preread buffer to allow modules such as ngx_stream_ssl_preread_module analyze the data before its processing.
  11. 6. Content
  12. Mandatory phase where data is actually processed, usually proxied to upstream servers, or a specified value is returned to a client.
  13. 7. Log
  14. The final phase where the result of a client session processing is recorded. The ngx_stream_log_module module is invoked at this phase.

1.1. ngx_stream_core_module

1.1.1. stream

  • Directives

    1. Syntax: stream {...}
    2. Default: Close
    3. Context: main
  • Instroduction

Provides the configuration file context in which the stream server directives are specified.

1.1.2. server

  • Directives

    1. Syntax: server {...}
    2. Default: Close
    3. Context: stream
  • Instroduction

Configuration of server, some like L7 virtual host server .

1.1.3. listen

  • Directives

    1. Syntax: listen [address:]port [ssl] [udp] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
    2. Default: Close
    3. Context: stream
  • Instroduction

Listen address and port for socket on which the server will accept connections. The address and port support multiple formats, such as:

  1. listen 6443;
  2. listen 127.0.0.1:6443;
  3. listen 0.0.0.0:6443;
  4. listen 0.0.0.0:6443-6446;
  5. listen unix:/var/run/nginx.sock;

ssl parameter allows specifying that all connections accept on the port must be work in SSL mode.
udp parameter specifying use UDP protocol, default is tcp protocol.In upd mode, you shoude specify reuseportparameter to handle package from same port and address.
protocolparameter allow all connections use proxy protocol.If fronted server(L4 LB) use open proxy protocol, the current must be sepcified protocol parameter, usualy the parameter used for tranfer client to backend server.
backlogparameter limit maxinum length queue for connections. General linux platform is 511 default.
other parameters instruduction doc

1.1.4. preread_buffer_size

  • Directives

    1. Syntax: preread_buffer_size size
    2. Default: preread_buffer_size 16k;
    3. Context: stream, server
  • Instroduction

Specifies a size of the preread buffer

1.1.5. preread_timeout

  • Directives

    1. Syntax: preread_timeout timeout
    2. Default: preread_timeout 30;
    3. Context: stream, server
  • Instroduction

Specifies a timeout of the preread phase.

1.1.6. resolver

  • Directives

    1. Syntax: resolver address ... [valid=time] [ipv6=on|off] [status_zone=zone]
    2. Default: Close
    3. Context: stream, server
  • Instroduction

Specifies dns server to resolve upstream server form domian name to IP address.
valid parameter specified dns cache life.
status_zoneparameter (1.17.1) ,is not community feature.

1.1.7. preread_timeout

  • Directives

    1. Syntax: resolver_timeout timeout
    2. Default: resolver_timeout 30;
    3. Context: stream, server
  • Instroduction

Sets a timeout for name resolution.

1.2. ngx_stream_proxy_module

The ngx_stream_proxy_module module (1.9.0) allows proxying data streams over TCP, UDP (1.9.13), and UNIX-domain sockets.

1.2.1. proxy_pass

  • Directives

    1. Syntax: proxy_pass address;
    2. Default: Close
    3. Context: server
  • Instroduction

Sets proxied server address, the address can be specified by IP, domain name, socket path or upstream name.For example:

  1. proxy_pass 127.0.0.1:8080;
  2. proxy_pass unix:/var/run/test.sock;
  3. proxy_pass $upstream;

1.2.2. proxy_protocol

  • Directives

    1. Syntax: proxy_protocol on|off;
    2. Default: proxy_protocol off;
    3. Context: stream, server
  • Instroduction

Add client IP to network package which transport to proxied server, the proxied server need use protocol to resolv request.

1.2.3. proxy_buffer_size

  • Directives

    1. Syntax: proxy_buffer_size size;
    2. Default: proxy_buffer_size 16k;
    3. Context: stream, server
  • Instroduction

Sets the size of the buffer used for reading data from the proxied server. Also sets the size of the buffer used for reading data from the client.

1.2.4. proxy_connect_timeout

  • Directives

    1. Syntax: proxy_connect_timeout timeout;
    2. Default: proxy_connect_timeout 60s;
    3. Context: stream, server
  • Instroduction

Defines a timeout for establishing a connection with a proxied server.

1.2.5. proxy_download_rate

  • Directives

    1. Syntax: proxy_download_rate rate;
    2. Default: proxy_download_rate 0;
    3. Context: stream, server
  • Instroduction

Limit reading bytes per second from proxied server on one connection. Default 0 is no limit.

1.2.6. proxy_next_upstream

  • Directives

    1. Syntax: proxy_next_upstream on | off;
    2. Default: proxy_next_upstream on;
    3. Context: stream, server
  • Instroduction

When a connection to the proxied server cannot be established, determines whether a client connection will be passed to the next server.

1.2.6. proxy_next_upstream

  • Directives

    1. Syntax: proxy_next_upstream_timeout;
    2. Default: proxy_next_upstream_timeout 0;
    3. Context: stream, server
  • Instroduction

Limits the time allowed to pass a connection to the next server. The 0 value turns off this limitation.

1.2.6. proxy_next_upstream_tries

  • Directives

    1. Syntax: proxy_next_upstream_tries rate;
    2. Default: proxy_next_upstream_tries 0;
    3. Context: stream, server
  • Instroduction

Limits the number of possible tries for passing a connection to the next server. The 0 value turns off this limitation.

1.3. ngx_stream_realip_module

1.3.1. set_real_ip_from

  • Directives

    1. Syntax: set_real_ip_from address|CIDR|unix;
    2. Default: Close
    3. Context: stream, server
  • Instroduction

Defines trusted address that are know to send corrent replacement addresses.
If specified, the tow variables can use for next process:

  • $realip_remote_addr: real client IP
  • $realip_remote_port: keeps the original client port

    1.4. ngx_stream_log_module

    1.4.1. log_format

  • Directives

    1. Syntax: log_format name [escape=default|json|none] string ...;
    2. Default: Close
    3. Context: stream
  • Instroduction

Sets log format, some variables refer: core_module, all variables

1.4.2. access_log

  • Directives

    1. Syntax: access_log path format [buffer=size] [gzip[=level]] [flush=time] [if=condition];
    2. access_log off;
    3. Default: Close
    4. Context: stream, server
  • Instroduction

Sets log access log configure:
buffer paramter specified for cache access log on memory, it useful when requests is too many.
gzip parameter specified compress access log, used zactorzgrepto view logs.When use gzipcompress, the cache will be cache on memory, defautl buffer is 64k, default compress is 1.

1.5. ngx_stream_upstream_module

1.5.1. upstream

  • Directives

    1. Syntax: upstream name { ... }
    2. Default: Close
    3. Context: stream
  • Instroduction

Defines a group of servers. Servers can listen on different ports. In addition, servers listening on TCP and UNIX-domain sockets can be mixed.

1.5.2. server

  • Directives

    1. Syntax: server address [parameters];
    2. Default: Close
    3. Context: upstream
  • Instroduction

Sets proxied server configration.
weigth=num sets the weight of the server, by default, 1.
max_conns=num limits the maximum number of simultaneous connections to the proxied server.Default 0.
max_fails=numsets the number of unsuccessful attempts to communicate with the server that should happen in the duration set by the fail_timeout parameter to consider the server unavailable.Default 1.
fail_timeout=timethe period of time the server will be considered unavailable.Default 10.
backupmarks the server as a backup server. Connections to the backup server will be passed when the primary servers are unavailable.
down marks the server as permanently unavailable.

1.5.3. hash

  • Directives

    1. Syntax: hash key [consistent];
    2. Default: Close
    3. Context: upstream
  • Instroduction

Specifies a load balancing method for a server group where the client-server mapping is based on the hashed key value. The key can contain text, variables. such as: hash $remote_addr

1.5.4. least_conn

  • Directives

    1. Syntax: least_conn
    2. Default: Close
    3. Context: upstream
  • Instroduction

Specifies that a group should use a load balancing method where a connection is passed to the server with the least number of active connections, taking into account weights of servers.


2. Example

2.1. LB for Kubernets Master

In my kubernetes cluster, there has three master: 10.4.7.51:6443-10.4.7.53:6443. Nginx LB deploy on 10.4.7.59.The configruation:

2.1.1. Nginx Config

  1. user nginx;
  2. worker_processes auto;
  3. error_log /var/log/nginx/error.log;
  4. pid /run/nginx.pid;
  5. include /usr/share/nginx/modules/*.conf;
  6. events {
  7. worker_connections 65535;
  8. }
  9. stream {
  10. log_format proxy '$time_local|$remote_addr|$upstream_addr|$protocol|$status|'
  11. '$session_time|$upstream_connect_time|$bytes_sent|$bytes_received|'
  12. '$upstream_bytes_sent|$upstream_bytes_received' ;
  13. access_log /var/log/nginx/access_stream.log proxy;
  14. error_log /var/log/nginx/error_stream.log warn;
  15. include /etc/nginx/conf.d/stream/*.conf;
  16. }
  1. upstream kube-apiserver {
  2. server 10.4.7.51:6443 ;
  3. server 10.4.7.52:6443 ;
  4. server 10.4.7.53:6443 ;
  5. }
  6. server {
  7. listen 10.4.7.59:6443 backlog=65535 so_keepalive=on;
  8. allow 10.4.7.0/24;
  9. allow 192.168.0.0/16;
  10. allow 172.19.0.0/16;
  11. allow 172.24.0.0/16;
  12. deny all;
  13. proxy_connect_timeout 3s;
  14. proxy_next_upstream on;
  15. proxy_next_upstream_timeout 5;
  16. proxy_next_upstream_tries 1;
  17. proxy_pass kube-apiserver;
  18. access_log /var/log/nginx/kube-apiserver.log proxy;
  19. }

2.1.2. Test

  1. [root@centos-7-59 nginx]# cat /var/log/nginx/kube-apiserver.log
  2. 09/May/2021:14:57:16 +0800|10.4.7.1|10.4.7.51:6443|TCP|200|0.282|0.000|46393|4323|4323|46393
  3. 09/May/2021:14:57:17 +0800|10.4.7.1|10.4.7.51:6443|TCP|200|0.014|0.002|13935|1776|1776|13935
  4. 09/May/2021:14:57:30 +0800|10.4.7.1|10.4.7.52:6443|TCP|502|3.004|-|0|0|0|0
  5. 09/May/2021:14:57:34 +0800|10.4.7.1|10.4.7.52:6443|TCP|502|3.003|-|0|0|0|0
  6. 09/May/2021:14:57:35 +0800|10.4.7.1|10.4.7.53:6443|TCP|200|0.012|0.000|13936|1776|1776|13936
  7. 09/May/2021:14:57:37 +0800|10.4.7.1|10.4.7.53:6443|TCP|200|0.014|0.000|13936|1776|1776|13936
  8. 09/May/2021:14:58:27 +0800|10.4.7.51|10.4.7.53:6443|TCP|200|0.013|0.000|1546|1408|1408|1546

2.2. Proxy To HTTP Server

When Nginx proxy TCP requset to backend server, the request $remote_ip will be change to nginx IP.So we need add client to TCP request.
image.png

2.2.1. Nginx Config

2.2.1.1. L4 Proxy Server

  1. stream {
  2. log_format proxy '$time_local|$remote_addr|$upstream_addr|$protocol|$status|'
  3. '$session_time|$upstream_connect_time|$bytes_sent|$bytes_received|'
  4. '$upstream_bytes_sent|$upstream_bytes_received' ;
  5. access_log /var/log/nginx/stream_access.log proxy ;
  6. error_log /var/log/nginx/stream_error.log info;
  7. include /etc/nginx/stream/*.conf;
  8. }
  1. server {
  2. listen 80;
  3. proxy_protocol on;
  4. proxy_pass 10.4.7.82:8080;
  5. }

2.2.1.2. Web Server

  1. http {
  2. log_format access '$time_local|$http_x_real_ip|$remote_addr|$http_x_forwarded_for|$upstream_addr|'
  3. '$request_method|$server_protocol|$host|$request_uri|$http_referer|$http_user_agent|'
  4. '$proxy_host|$status' ;
  5. access_log /var/log/nginx/access.log access;
  6. sendfile on;
  7. tcp_nopush on;
  8. tcp_nodelay on;
  9. keepalive_timeout 65;
  10. types_hash_max_size 2048;
  11. include /etc/nginx/mime.types;
  12. default_type application/octet-stream;
  13. include /etc/nginx/conf.d/*.conf;
  14. server {
  15. # the 80 port to accept HTTP request direct requset
  16. # the 8080 port to accept proxy protcol request
  17. listen 80 default_server;
  18. listen 8080 proxy_protocol;
  19. set_real_ip_from 10.4.7.81;
  20. real_ip_header proxy_protocol;
  21. location / {
  22. return 200 "hello world\r\n";
  23. }
  24. }
  25. }

2.2.2. Test

  1. # the first log: client direct access webserver by http://10.4.7.82
  2. # the second log: client access proxy server by http://10.4.7.81
  3. [root@centos-82 ~]# tail /var/log/nginx/access.log
  4. 09/May/2021:15:41:53 +0800|-|10.4.7.1|-|-|GET|HTTP/1.1|10.4.7.82|/|-|curl/7.68.0|-|200
  5. 09/May/2021:15:41:55 +0800|-|10.4.7.1|-|-|GET|HTTP/1.1|10.4.7.81|/|-|curl/7.68.0|-|200
  1. # when you direct access 10.4.7.82:8080, nginx will raise error:
  2. [root@centos-82 ~]# cat /var/log/nginx/error.log
  3. 2021/05/09 15:42:51 [error] 1672#0: *8 broken header: "GET / HTTP/1.1
  4. Host: 10.4.7.82:8080
  5. User-Agent: curl/7.68.0
  6. Accept: */*
  7. " while reading PROXY protocol, client: 10.4.7.1, server: 0.0.0.0:8080