{"id":18523108,"url":"https://github.com/taymindis/nginx-socketify","last_synced_at":"2025-04-09T11:31:28.440Z","repository":{"id":132372018,"uuid":"155646501","full_name":"Taymindis/nginx-socketify","owner":"Taymindis","description":"customize your upstream socket request and downstream response buffer in Nginx config just one time effort","archived":false,"fork":false,"pushed_at":"2018-11-01T02:47:58.000Z","size":89,"stargazers_count":9,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-24T05:13:17.318Z","etag":null,"topics":["http","netcat","nginx","tcp","telnet"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Taymindis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-01T01:46:33.000Z","updated_at":"2024-10-27T20:45:58.000Z","dependencies_parsed_at":"2023-05-31T13:16:28.938Z","dependency_job_id":null,"html_url":"https://github.com/Taymindis/nginx-socketify","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Taymindis%2Fnginx-socketify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Taymindis%2Fnginx-socketify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Taymindis%2Fnginx-socketify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Taymindis%2Fnginx-socketify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Taymindis","download_url":"https://codeload.github.com/Taymindis/nginx-socketify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248031412,"owners_count":21036393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","netcat","nginx","tcp","telnet"],"created_at":"2024-11-06T17:34:16.316Z","updated_at":"2025-04-09T11:31:28.434Z","avatar_url":"https://github.com/Taymindis.png","language":"C","readme":"\nnginx-socketify\n=========\n\nAccess various tcp protocol services over a nginx-socketify.\ncustomize your upstream socket request and downstream response buffer in Nginx config just `one time effort` .\n\nTable of Contents\n=================\n\n* [Introduction](#introduction)\n* [Synopsis](#synopsis)\n* [Config Commands](#config-commands)\n* [Installation](#installation)\n* [Test](#test)\n* [Support](#support)\n* [Copyright \u0026 License](#copyright--license)\n\nIntroduction\n============\n\nnginx-socketify is a nginx 3rd party upstream module which allow to massage(customize) request by sending your own data buffer and proxy to any of your server which accept different protocol request (for example, stomp, redis, memcached), and filter response from upstream servers.\n\nnginx-socketify module is vanilla c module, there is no any fancy dependencies needed.\n\n![Image of nginx-socketify](socketify-illustration.png)\n\nExample of nginx config for socketify will be provided.\n\nThe following is simple demonstration how it communicate to redis, memcache and rabbitmq.\n\nSynopsis\n========\n\n\n```nginx\n# nginx.conf\nupstream redis_server {\n    server 127.0.0.1:6379;\n   # server x.x.x.x:6379 backup;\n}\nupstream memcached_server {\n    server 127.0.0.1:11211;\n}\nupstream rabbitmqup {\n    keepalive 100;\n    server 127.0.0.1:61618;\n}\n\nserver {\n  # for stomp protocol needed\n  socketify_ascii_to_char 0 nullstring;\n  socketify_ascii_to_char 10 newline;\n\n  listen       8989;\n\n  # memcached\n  location  = /mmc {\n      set $lastdelimeter \"@:|:@\";\n      if ( $request_method !~ ^(GET|PUT|POST)$ ) {\n          return 405;\n      }\n      if ($arg_key = ''){\n          return 405 'key needed';\n      }\n      if ( $request_method ~ ^(GET)$ ) {\n          socketify_send \"get $arg_key\\r\\n\";\n          socketify_done_recv_if_eol_match \"@:|:@END\\r\\n\";\n          socketify_done_recv_if_start_match \"END\\r\\n\";\n          socketify_substr_resp \"\\r\\n\" \"@:|:@\\r\\nEND\" 2 0 200;\n      }\n\n      socketify_strlen $request_body$lastdelimeter totalbulklength;\n\n      if ( $request_method ~ ^(PUT|POST)$ ) {\n          socketify_send \"set $arg_key 0 60000 $totalbulklength\\r\\n$request_body$lastdelimeter\\r\\n\";\n          socketify_done_recv_if_eol_match \"STORED\\r\\n\";\n      }\n      socketify_pass memcached_server;\n  }\n\n  # ... Redis.conf \n  # ... \n  # ...\n}\n```\n\n[Back to TOC](#table-of-contents)\n\nConfig Commands\n===============\n\n* [socketify_pass](#socketify_pass)\n* [socketify_escape](#socketify_escape)\n* [socketify_ascii_to_char](#socketify_ascii_to_char)\n* [socketify_strlen](#socketify_strlen)\n* [socketify_send](#socketify_send)\n* [socketify_done_recv_by_scan_len](#socketify_done_recv_by_scan_len)\n* [socketify_done_recv_if_eol_match](#socketify_done_recv_if_eol_match)\n* [socketify_done_recv_if_start_match](#socketify_done_recv_if_start_match)\n* [socketify_npacket_should_recv](#socketify_npacket_should_recv)\n* [socketify_unescape_response](#socketify_unescape_response)\n* [socketify_regex_filter_to_var](#socketify_regex_filter_to_var)\n* [socketify_regex_resp](#socketify_regex_resp)\n* [socketify_regex_resp_to_hdr](#socketify_regex_resp_to_hdr)\n* [socketify_append_resp](#socketify_append_resp)\n* [socketify_substr_to_var](#socketify_substr_to_var)\n* [socketify_substr_resp](#socketify_substr_resp)\n* [socketify_substr_resp_to_hdr](#socketify_substr_resp_to_hdr)\n* [socketify_content_type](#socketify_content_type)\n* [socketify_socket_schema](#socketify_socket_schema)\n* [socketify_cache =\u003e _proxy_cache_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache)\n* [socketify_cache_key =\u003e _proxy_cache_key_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_key)\n* [socketify_cache_path =\u003e _proxy_cache_path_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_path)\n* [socketify_cache_bypass =\u003e _proxy_cache_bypass_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_bypass)\n* [socketify_no_cache =\u003e _proxy_no_cache_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_no_cache)\n* [socketify_cache_valid =\u003e _proxy_cache_valid_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid)\n* [socketify_cache_min_uses =\u003e _proxy_cache_min_uses_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_min_uses)\n* [socketify_cache_max_range_offset =\u003e _proxy_cache_max_range_offset_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_max_range_offset)\n* [socketify_cache_use_stale =\u003e _proxy_cache_use_stale_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_use_stale)\n* [socketify_cache_methods =\u003e _proxy_cache_methods_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_methods)\n* [socketify_cache_lock =\u003e _proxy_cache_lock_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_lock)\n* [socketify_cache_lock_timeout =\u003e _proxy_cache_lock_timeout_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_lock_timeout)\n* [socketify_cache_lock_age =\u003e _proxy_cache_lock_age_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_lock_age)\n* [socketify_cache_revalidate =\u003e _proxy_cache_revalidate_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_revalidate)\n* [socketify_cache_background_update =\u003e _proxy_cache_background_update_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_background_update)\n* [socketify_buffering =\u003e _proxy_buffering_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering)\n* [socketify_ignore_headers =\u003e _proxy_ignore_headers_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers)\n* [socketify_bind =\u003e _proxy_bind_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind)\n* [socketify_connect_timeout =\u003e _proxy_connect_timeout_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout)\n* [socketify_send_timeout =\u003e _proxy_send_timeout_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_send_timeout)\n* [socketify_buffer_size =\u003e _proxy_buffer_size_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size)\n* [socketify_buffers =\u003e _proxy_buffers_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers)\n* [socketify_busy_buffers_size =\u003e _proxy_busy_buffers_size_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_busy_buffers_size)\n* [socketify_read_timeout =\u003e _proxy_read_timeout_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout)\n* [socketify_next_upstream =\u003e _proxy_next_upstream_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream)\n* [socketify_next_upstream_tries =\u003e _proxy_next_upstream_tries_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries)\n* [socketify_next_upstream_timeout =\u003e _proxy_next_upstream_timeout_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_timeout)\n* [socketify_pass_request_headers =\u003e _proxy_pass_request_headers_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers)\n* [socketify_pass_request_body =\u003e _proxy_pass_request_body_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_body)\n* [socketify_intercept_errors =\u003e _proxy_intercept_errors_](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors)\n\n[Back to TOC](#table-of-contents)\n\nsocketify_pass                                                                                                                                                  \n==============           \n                                                                                                                                                           \nThe server which socketify passing the request to.\n\n\nsocketify_escape\n================\n\nThe data that need to be escaped - socketify_escape \u003ccontent_to_escape\u003e \u003cescape_type\u003e \u003cresponse_to_var\u003e\n```nginx \nsocketify_escape $request_body json escaped_body\n```\n\nsocketify_ascii_to_char\n=======================\n\nThe ascii(0-255) that convert to char variable and use it in the config. \n\n\nsocketify_strlen\n=================\n\ncount the variable string len\n\n\nsocketify_send\n===============\n\nThat command that are going to send, variable resolving.\nThis command allow more than one in same scope of config\n\n```nginx\n\nsocketify_send \"set $arg_key 0 60000 $totalbulklength\\r\\n\";\nsocketify_send \"$request_body$lastdelimeter\\r\\n\";\n\n# ...\n\n```\n\nsocketify_done_recv_by_scan_len\n================================\n\nScan the bytes by giving the position of buffer. Finished read if the bytes len is equal or more than the scanned len. For ex. \n\n```nginx\n\nsocketify_done_recv_by_scan_len scan_aft=content-length:;\n\n```\nThere are 4 optional attribute :\nscan_aft   : which buffer starting to scan\nscan_range : the range need to be scan for length\ncount_aft  : which buffer should be starting to count , for example count_aft=\\r\\n\ncount_extra: extra bytes len to count, less using, mostly for extra protocol buffer.\n\n\nsocketify_done_recv_if_start_match\n==============================\n\nDone read the bytes by starting matching.\n\n```nginx\n# memcached sample if starting is end\\r\\n means not key found, direct return done recv\n socketify_done_recv_if_start_match \"END\\r\\n\";\n```\n\nsocketify_done_recv_if_eol_match\n==============================\n\nDone read the bytes by end of line matching.\n\n```nginx\n# memcached sample\n socketify_done_recv_if_eol_match \"STORED\\r\\n\";\n```\n\nsocketify_npacket_should_recv\n==============================\n\nThis is under beta version.\n\n\nsocketify_unescape_response\n============================\n\nTo unescape the response, the process is just after done read the bytes\n\n```nginx\nsocketify_unescape_response json_string;\n```\n\nsocketify_regex_filter_to_var\n=============================\n\nsocketify_regex_filter_to_var \u003cdata\u003e \u003cregex\u003e output_var\n\nFilter the data by regular expression and pass to the variable, the process trigger when get the variable\n\n```nginx\nsocketify_regex_filter_to_var $http_token abs(.*) myoutput;\n```\n\nsocketify_regex_resp\n=====================\nFilter the response by regular expression, it is the step the data before response to client, it appendable and it accepts multiple commands in sequence  in one scope\n\nsocketify_regex_resp \u003cregex\u003e \u003c[append][status_code]\u003e;\n\nFor ex.\n\n```nginx\n\nsocketify_regex_resp \u003cregex\u003e append;\nsocketify_regex_resp \u003cregex\u003e append;\nsocketify_regex_resp \u003cregex\u003e 200; # return 200 status code, status code it's only accept one\n\n```\n\n\nsocketify_append_resp\n======================\n\ndirect append static content to response, it accepts multiple commands in sequences\n\n```nginx\n\nsocketify_append_resp startclause;\nsocketify_regex_resp \u003cregex\u003e append;\nsocketify_regex_resp \u003cregex\u003e 200;\n\n\n```\n\nsocketify_regex_resp_to_hdr\n===========================\nThis is the filtering response and pass the response to header variable for the next forwarded request, this is mostly use for @postaction nginx. \n\n\n\n\nsocketify_substr_to_var\n=======================\nsocketify_substr_to_var is similar phase to socketify_regex_filter_to_var, it just using substring\n\nsyntax: socketify_substr_to_var \u003cdatainput\u003e \u003c[ascii=]lf\u003e \u003c[ascii=]rt\u003e \u003coffsetlf\u003e \u003coffsetrt\u003e output_var\n\n\n\nsocketify_substr_resp\n=======================\nsocketify_substr_to_var is similar phase to socketify_regex_resp, it just using substring, it accepts multiple commands in sequence in one scope\n\nsyntax: socketify_substr_resp \u003c[ascii=]lf\u003e \u003c[ascii=]rt\u003e \u003coffsetlf\u003e \u003coffsetrt\u003e \u003c[append][status_code]\u003e;\n\n\n\n\nsocketify_substr_resp_to_hdr\n============================\nsocketify_substr_resp_to_hdr is similar phase to socketify_regex_resp_to_hdr, it just using substring, it accepts multiple commands in sequence in one scope\n\nsyntax: socketify_substr_resp_to_hdr \u003c[ascii=]lf\u003e \u003c[ascii=]rt\u003e \u003coffsetlf\u003e \u003coffsetrt\u003e \u003cheader_out=\u003e;\nsyntax: socketify_substr_resp_to_hdr \u003c[ascii=]lf\u003e \u003c[ascii=]rt\u003e \u003coffsetlf\u003e \u003coffsetrt\u003e \u003cheader_in=\u003e;\n\nFor ex.\n\n```nginx\n\nsocketify_substr_resp_to_hdr \"Personal Profile: {\" \"} end personal profile\" 19 0 header_out=personalprofile;\n\n19 means move the left substring to 19 forward.\n\n0 means move nothing to forward right string\n\nnext action can be use via call $http_personalprofile\n\n```\n\n\n\nsocketify_content_type\n=======================\n\nSet Response content type\n\n\n\nsocketify_socket_schema\n=======================\n\nset the socket schema, ex. memcache:// tcp:// redis://\n\n\n[Back to TOC](#table-of-contents)           \n\nInstallation\n============\n\n```bash\nwget 'http://nginx.org/download/nginx-1.13.7.tar.gz'\ntar -xzvf nginx-1.13.7.tar.gz\ncd nginx-1.13.7/\n\n./configure --add-module=/path/to/nginx-socketify\n\nmake -j2\nsudo make install\n```\n\n[Back to TOC](#table-of-contents)\n\n\nTest\n=====\n\nIt depends on nginx test suite libs, please refer [test-nginx](https://github.com/openresty/test-nginx) for installation.\n\n\n```bash\ncd /path/to/nginx-socketify\nexport PATH=/path/to/nginx-dirname:$PATH \nsudo prove t\n```\n\n[Back to TOC](#table-of-contents)\n\n\nSupport\n=======\n\nPlease do not hesitate to contact minikawoon2017@gmail.com for any queries or development improvement.\n\n\n[Back to TOC](#table-of-contents)\n\nCopyright \u0026 License\n===================\n\nThis module is licensed under BSD 2-Clause License\n\nCopyright (c) 2018, Taymindis Woon \u003ccloudleware2015@gmail.com\u003e\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n[Back to TOC](#table-of-contents)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaymindis%2Fnginx-socketify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaymindis%2Fnginx-socketify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaymindis%2Fnginx-socketify/lists"}