├── README.md ├── config └── ngx_http_tcp_keepalive_module.c /README.md: -------------------------------------------------------------------------------- 1 | # Nginx TCP keepalive module 2 | 3 | When using [Nginx](http://wiki.nginx.org/Main) as a reverse proxy where the 4 | connections stay open (for example, to implement a server push), 5 | a problem arise when the client times out: nginx doesn't detect it because it 6 | doesn't use the [TCP keepalive](http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) mechanism. 7 | The fact that nginx doesn't detect connection timeouts implies that the backend server 8 | (used for comet, server push, etc..) will see the client as connected forever which is 9 | bad for two reasons: 1) the client presence can matter in your application, 10 | and 2) resources will never get freed up. 11 | 12 | Note: this has nothing to do with HTTP keepalive. 13 | 14 | This module allows you to set the TCP keepalive values on http connections, namely 15 | `TCP_KEEPCNT`, `TCP_KEEPIDLE`, `TCP_KEEPINTVL`. 16 | 17 | ## Installation 18 | 19 | ### From source 20 | 21 | Configure the Nginx sources with: 22 | 23 | ./configure --add-module=path/to/nginx_tcp_keepalive 24 | 25 | And then compile/install with make/make install. 26 | 27 | ## Configuration Options 28 | 29 | ### tcp_keepalive 30 | 31 | * **syntax**: tcp\_keepalive *on|off* 32 | * **default**: off 33 | * **context**: http, server, location 34 | 35 | Enables the TCP keepalive mechanism. 36 | 37 | --- 38 | 39 | ### tcp_keepcnt 40 | 41 | * **syntax**: tcp\_keepcnt *num* 42 | * **default**: 2 43 | * **context**: http, server, location 44 | 45 | The maximum number of keepalive probes TCP should send before dropping the connection. 46 | 47 | --- 48 | 49 | ### tcp_keepidle 50 | 51 | * **syntax**: tcp\_keepidle *time* 52 | * **default**: 1m 53 | * **context**: http, server, location 54 | 55 | The time the connection needs to remain idle before TCP starts sending keepalive probes. 56 | 57 | --- 58 | 59 | ### tcp_keepintvl 60 | 61 | * **syntax**: tcp\_keepintvl *time* 62 | * **default**: 1m 63 | * **context**: http, server, location 64 | 65 | The time between individual keepalive probes. 66 | 67 | ## License 68 | 69 | nginx_tcp_keepalive is distributed under the MIT license. 70 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_tcp_keepalive_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_tcp_keepalive_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS ${ngx_addon_dir}/ngx_http_tcp_keepalive_module.c" 4 | -------------------------------------------------------------------------------- /ngx_http_tcp_keepalive_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Nicolas Viennot 3 | * 4 | * This file is subject to the terms and conditions of the MIT License. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern ngx_module_t ngx_http_tcp_keepalive_module; 13 | 14 | typedef struct { 15 | ngx_flag_t enable; 16 | ngx_uint_t tcp_keepcnt; 17 | time_t tcp_keepidle; 18 | time_t tcp_keepintvl; 19 | } ngx_http_tcp_keepalive_conf_t; 20 | 21 | static ngx_int_t 22 | ngx_http_tcp_keepalive_handler(ngx_http_request_t *r) 23 | { 24 | ngx_http_tcp_keepalive_conf_t *conf; 25 | int fd = r->connection->fd; 26 | 27 | conf = ngx_http_get_module_loc_conf(r, ngx_http_tcp_keepalive_module); 28 | if (!conf->enable) 29 | return NGX_DECLINED; 30 | 31 | #define SSO(level, optname, val) ({ \ 32 | if (setsockopt(fd, level, optname, &(val), sizeof(int)) < 0) { \ 33 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \ 34 | "setsockopt(" #level ", " #optname ", %d) failed", val); \ 35 | return NGX_HTTP_INTERNAL_SERVER_ERROR; \ 36 | } \ 37 | }) 38 | SSO(SOL_SOCKET, SO_KEEPALIVE, conf->enable); 39 | #ifdef NGX_DARWIN 40 | SSO(IPPROTO_TCP, TCP_KEEPALIVE, conf->tcp_keepidle); 41 | #else 42 | SSO(IPPROTO_TCP, TCP_KEEPCNT, conf->tcp_keepcnt); 43 | SSO(IPPROTO_TCP, TCP_KEEPIDLE, conf->tcp_keepidle); 44 | SSO(IPPROTO_TCP, TCP_KEEPINTVL, conf->tcp_keepintvl); 45 | #endif 46 | #undef SSO 47 | 48 | return NGX_DECLINED; 49 | } 50 | 51 | static ngx_int_t 52 | ngx_http_tcp_keepalive_init(ngx_conf_t *cf) 53 | { 54 | ngx_http_handler_pt *h; 55 | ngx_http_core_main_conf_t *cmcf; 56 | 57 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 58 | 59 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); 60 | if (h == NULL) 61 | return NGX_ERROR; 62 | 63 | *h = ngx_http_tcp_keepalive_handler; 64 | 65 | return NGX_OK; 66 | } 67 | 68 | static void * 69 | ngx_http_tcp_keepalive_create_loc_conf(ngx_conf_t *cf) 70 | { 71 | ngx_http_tcp_keepalive_conf_t *conf; 72 | 73 | conf = ngx_palloc(cf->pool, sizeof(*conf)); 74 | if (conf == NULL) 75 | return NULL; 76 | 77 | conf->enable = NGX_CONF_UNSET; 78 | conf->tcp_keepcnt = NGX_CONF_UNSET_UINT; 79 | conf->tcp_keepidle = NGX_CONF_UNSET; 80 | conf->tcp_keepintvl = NGX_CONF_UNSET; 81 | 82 | return conf; 83 | } 84 | 85 | static char * 86 | ngx_http_tcp_keepalive_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 87 | { 88 | ngx_http_tcp_keepalive_conf_t *prev = parent; 89 | ngx_http_tcp_keepalive_conf_t *conf = child; 90 | 91 | ngx_conf_merge_value(conf->enable, prev->enable, 0); 92 | ngx_conf_merge_uint_value(conf->tcp_keepcnt, prev->tcp_keepcnt, 2); 93 | ngx_conf_merge_value(conf->tcp_keepidle, prev->tcp_keepidle, 60); 94 | ngx_conf_merge_value(conf->tcp_keepintvl, prev->tcp_keepintvl, 60); 95 | 96 | return NGX_CONF_OK; 97 | } 98 | 99 | static ngx_command_t ngx_http_tcp_keepalive_commands[] = { 100 | { 101 | ngx_string("tcp_keepalive"), 102 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 103 | ngx_conf_set_flag_slot, 104 | NGX_HTTP_LOC_CONF_OFFSET, 105 | offsetof(ngx_http_tcp_keepalive_conf_t, enable), 106 | NULL 107 | }, 108 | { 109 | ngx_string("tcp_keepcnt"), 110 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 111 | ngx_conf_set_num_slot, 112 | NGX_HTTP_LOC_CONF_OFFSET, 113 | offsetof(ngx_http_tcp_keepalive_conf_t, tcp_keepcnt), 114 | NULL 115 | }, 116 | { 117 | ngx_string("tcp_keepidle"), 118 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 119 | ngx_conf_set_sec_slot, 120 | NGX_HTTP_LOC_CONF_OFFSET, 121 | offsetof(ngx_http_tcp_keepalive_conf_t, tcp_keepidle), 122 | NULL 123 | }, 124 | { 125 | ngx_string("tcp_keepintvl"), 126 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 127 | ngx_conf_set_sec_slot, 128 | NGX_HTTP_LOC_CONF_OFFSET, 129 | offsetof(ngx_http_tcp_keepalive_conf_t, tcp_keepintvl), 130 | NULL 131 | }, 132 | ngx_null_command 133 | }; 134 | 135 | static ngx_http_module_t ngx_http_tcp_keepalive_module_ctx = { 136 | NULL, /* preconfiguration */ 137 | ngx_http_tcp_keepalive_init, /* postconfiguration */ 138 | 139 | NULL, /* create main configuration */ 140 | NULL, /* init main configuration */ 141 | 142 | NULL, /* create server configuration */ 143 | NULL, /* merge server configuration */ 144 | 145 | ngx_http_tcp_keepalive_create_loc_conf, /* create location configuration */ 146 | ngx_http_tcp_keepalive_merge_loc_conf /* merge location configuration */ 147 | }; 148 | 149 | ngx_module_t ngx_http_tcp_keepalive_module = { 150 | NGX_MODULE_V1, 151 | &ngx_http_tcp_keepalive_module_ctx, /* module context */ 152 | ngx_http_tcp_keepalive_commands, /* module directives */ 153 | NGX_HTTP_MODULE, /* module type */ 154 | NULL, /* init master */ 155 | NULL, /* init module */ 156 | NULL, /* init process */ 157 | NULL, /* init thread */ 158 | NULL, /* exit thread */ 159 | NULL, /* exit process */ 160 | NULL, /* exit master */ 161 | NGX_MODULE_V1_PADDING 162 | }; 163 | --------------------------------------------------------------------------------