├── .DS_Store ├── .idea ├── .gitignore ├── DK8sDDosFirewall.iml ├── modules.xml └── vcs.xml ├── Dockerfile ├── DockerfileTest ├── LICENSE ├── Makefile ├── README.md ├── cert.key ├── cert.pem ├── env.conf ├── forward.sh ├── nginx.conf ├── protect.lua ├── record.lua ├── stats.lua ├── wechat.jpg └── wrk.lua /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yinyue123/DK8sDDosFirewall/e55de6074a1f2906d2826f93bd6ca7e3de2ab18c/.DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/DK8sDDosFirewall.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openresty/openresty:1.21.4.2-alpine as builder 2 | RUN mkdir /app 3 | WORKDIR /app 4 | 5 | ADD stats.lua /app 6 | ADD protect.lua /app 7 | ADD record.lua /app 8 | 9 | RUN /usr/local/openresty/luajit/bin/luajit -b /app/stats.lua /app/stats.ljbc 10 | RUN /usr/local/openresty/luajit/bin/luajit -b /app/protect.lua /app/protect.ljbc 11 | RUN /usr/local/openresty/luajit/bin/luajit -b /app/record.lua /app/record.ljbc 12 | 13 | FROM --platform=linux/amd64 openresty/openresty:1.21.4.2-alpine 14 | EXPOSE 80 443 3000 15 | 16 | RUN mkdir /app 17 | WORKDIR /app 18 | RUN apk add --no-cache tzdata 19 | ENV TZ Asia/Shanghai 20 | COPY --from=builder /app/stats.ljbc /app/ 21 | COPY --from=builder /app/protect.ljbc /app/ 22 | COPY --from=builder /app/record.ljbc /app/ 23 | ADD stats.lua /app/stats.lua 24 | ADD protect.lua /app/protect.lua 25 | ADD record.lua /app/record.lua 26 | ADD cert.key /app/cert.key 27 | ADD cert.pem /app/cert.pem 28 | ADD env.conf /app/env.conf 29 | ADD nginx.conf /app/nginx.conf 30 | 31 | CMD ["openresty", "-c", "/app/nginx.conf"] 32 | -------------------------------------------------------------------------------- /DockerfileTest: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 centos:7 2 | EXPOSE 80 443 3000 3 | RUN mkdir /app 4 | WORKDIR /app 5 | 6 | RUN yum install -y yum-utils 7 | RUN yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo && yum install -y openresty openresty-resty openresty-opm 8 | RUN yum install -y vim 9 | 10 | ADD stats.lua /app/stats.lua 11 | ADD protect.lua /app/protect.lua 12 | ADD ping.lua /app/ping.lua 13 | ADD record.lua /app/record.lua 14 | ADD cert.key /app/cert.key 15 | ADD cert.pem /app/cert.pem 16 | ADD env.conf /app/env.conf 17 | ADD nginx.conf /app/nginx.conf 18 | 19 | CMD ["openresty", "-c", "/app/nginx.conf"] 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROD_REG?=yinyue123/ddos-firewal 2 | IMG_TAG?=v2.4 3 | PROD_IMG?=${PROD_REG}:${IMG_TAG} 4 | export DOCKER_HOST?=tcp://192.168.10.1:2375 5 | 6 | all: push 7 | 8 | push: 9 | docker build -f Dockerfile . -t $(PROD_IMG) 10 | docker push ${PROD_IMG} 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DK8sDDosFirewall 2 | Protect your service from CC attacks, UDP attacks, and traffic flooding attacks. 3 | 4 | [DK8s DDos Firewall Code Repository](https://github.com/yinyue123/DK8sDDosFirewall) 5 | 6 | [DK8s DDos Firewall Docker Image](https://hub.docker.com/r/yinyue123/ddos-firewal) 7 | 8 | `For more information, please visit `[https://www.dk8s.com](https://www.dk8s.com) 9 | 10 | ![WeChat](https://raw.githubusercontent.com/yinyue123/DK8sDDosFirewall/main/wechat.jpg) 11 | -------------------------------------------------------------------------------- /cert.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQCnbQUB9zZBiouSxLrl0VorHIPZswMdN64Sc39wBWy9J5Ze00cb 3 | y+IuH9lPYu688DlaAYande7tG2wuGSoBO4WzGSDnTKbd4YfmUZrWCmYvqqQsaEG/ 4 | l+ml3Ap/m9KcrtCQUP3UMMfgcc20d3Zho07VfO86658he2u/qH3l3SU8DwIDAQAB 5 | AoGBAJ7U+QQ1X35sDh8tjVUK9+ygP6FehxzHvtb4RTSjoNYN4USSUQpYsHkrc8Ax 6 | TeVmTDJL8k+ZvRGpi0ZsTwIeUqXd41CbXqBtu59LuhsOQSYWhbTR4HU/cVueJbFD 7 | GKJ0x68mu9kQQcT2wpjLv4SeVFCIwQMudcL31U6CFtLbsR6JAkEA0SDAK9AxG/TM 8 | fW5jimmiaRte+ELqao8/rer/DGd6hEV2izb03HXRunQW4CuAIjiaILrmioRkgxya 9 | Mt8f5xaqNQJBAMzzgX5Al14H0h3BrzQSD3dmo0ims0guN7hIJQ+hhy4e9TLmZJwU 10 | 7oCjUTvdg2gbId9PEKkGmxFZ1pLtcXq6dbMCQEl044uAOX/EYP++AqDfsfiRcK5r 11 | csOzRX7liGjnABXuAFGuIBxAFkcT9+UN4pgioaDVhZ0qG9Qh+9fan+4f+/ECQFet 12 | 0Pc3IMqMY/pw8sg+9bjqAu7AyjAV/aZrztcaDl/PxKxK3j3bwpDrzYPj5ySxftMu 13 | 2vzEo7BPk7l1tTeA73sCQQCN05E0HTuDMhLbbNGfnKPoC6FChCI8QZgEMQ2MdkiT 14 | kGBaqi/AwtrCQBEDIV8yQrJpsHzXaCpBxCyZuj56m5Xh 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICcTCCAdoCCQCi/HJ9vuqbgDANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJj 3 | bjELMAkGA1UECAwCc3oxCzAJBgNVBAcMAnhsMQ0wCwYDVQQKDARkazhzMQ0wCwYD 4 | VQQLDARkazhzMRUwEwYDVQQDDAx3d3cuZGs4cy5jb20xHzAdBgkqhkiG9w0BCQEW 5 | EDc5ODUyMzU5M0BxcS5jb20wHhcNMjMwNzI4MDkxOTEyWhcNMzMwNzI1MDkxOTEy 6 | WjB9MQswCQYDVQQGEwJjbjELMAkGA1UECAwCc3oxCzAJBgNVBAcMAnhsMQ0wCwYD 7 | VQQKDARkazhzMQ0wCwYDVQQLDARkazhzMRUwEwYDVQQDDAx3d3cuZGs4cy5jb20x 8 | HzAdBgkqhkiG9w0BCQEWEDc5ODUyMzU5M0BxcS5jb20wgZ8wDQYJKoZIhvcNAQEB 9 | BQADgY0AMIGJAoGBAKdtBQH3NkGKi5LEuuXRWiscg9mzAx03rhJzf3AFbL0nll7T 10 | RxvL4i4f2U9i7rzwOVoBhqd17u0bbC4ZKgE7hbMZIOdMpt3hh+ZRmtYKZi+qpCxo 11 | Qb+X6aXcCn+b0pyu0JBQ/dQwx+BxzbR3dmGjTtV87zrrnyF7a7+ofeXdJTwPAgMB 12 | AAEwDQYJKoZIhvcNAQELBQADgYEAUESQ4W5BRa9u2i+HbgPhZ3Rgv6LXKP5w91eC 13 | PFy2bRTY4dZcnxHtEWRfP4ulGrWCVA+eH2z6jA1H1iZ01YdZwU89h1ejQkfE80HY 14 | FCTAKhEotgBa4pu6w27VZXkwBeLAlE/N98BMzzdWkrLrDKUG9MSMmhLUns+ijlOz 15 | neFoPdM= 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /env.conf: -------------------------------------------------------------------------------- 1 | set $limit_count_per_hour 3600; 2 | set $limit_bytes_per_hour 268435456; 3 | set $limit_costs_per_hour 3600; 4 | set $limit_count_per_day 10800; 5 | set $limit_bytes_per_day 1073741824; 6 | set $limit_costs_per_day 10800; 7 | -------------------------------------------------------------------------------- /forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | forward_ip=${1:-'127.0.0.1'} 4 | echo "New Request forward to $forward_ip" 5 | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to "$forward_ip:80" 6 | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to "$forward_ip:443" 7 | iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 8 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | user root; 2 | daemon off; 3 | # 绑定cpu亲核性,减少cache未命中,请根据实际情况修改 4 | worker_processes 1; 5 | worker_cpu_affinity 1; 6 | # 日志输出到标准输出 7 | error_log /dev/stdout; 8 | events { 9 | # 设置单个worker连接数 10 | worker_connections 10240; 11 | use epoll; 12 | } 13 | 14 | http { 15 | # 配置名为access的log输出格式 16 | log_format access '$remote_addr $server_port - $http_host [$time_local] ' 17 | '"$request" $status $body_bytes_sent ' 18 | '"$http_referer" "$http_user_agent" ' 19 | '$http_x_forwarded_for|$http_x_real_ip|$limit_key'; 20 | # log日志输出到标准输出 21 | access_log /dev/stdout access; 22 | # 关闭日志,提高性能。开启日志,排查问题 23 | # access_log off; 24 | 25 | # 白名单不限速 26 | geo $limit { 27 | default 1; 28 | 192.168.0.0/24 0; 29 | 10.0.0.0/8 0; 30 | 127.0.0.0/8 0; 31 | } 32 | 33 | # Header有X-Forwarded-IP就用xff,没有就用数据包的源IP 34 | map $http_x_forwarded_for $real_ip { 35 | default $remote_addr; 36 | "~^(?P[^,]+)" $ip; 37 | } 38 | 39 | # 匹配到白名单就为空不限速,没匹配到就限速 40 | map $limit $limit_key { 41 | 0 ""; 42 | 1 $real_ip; 43 | } 44 | 45 | geo $whitelist { 46 | default 0; 47 | 1.1.1.1/24 1; # cdn的ip访问白名单 48 | } 49 | 50 | # 请求超过阈值,断开连接 51 | limit_req_status 444; 52 | # 限制单个ip的请求数,避免单个ip打爆服务,请根据实际业务进行修改 53 | limit_req_zone $limit_key zone=req_ip:10m rate=5r/s; 54 | # 限制单个服务的请求数,避免请求过载打爆服务,请根据实际业务进行修改 55 | limit_req_zone $server_name zone=req_svr:1m rate=1000r/s; 56 | # 限制单个uri的请求数,避免带宽被打爆,请根据实际业务进行修改 57 | limit_req_zone $uri zone=req_res:10m rate=3r/s; 58 | # 连接数超过阈值,断开连接 59 | limit_conn_status 444; 60 | # 限制单个ip的连接数 61 | limit_conn_zone $limit_key zone=con_ip:10m; 62 | # 限速的共享内存,如果不够可以改大 63 | lua_shared_dict traffic_stats 50m; 64 | # 引入lua模块 65 | lua_package_path "/app/?.ljbc;/app/?.lua;;"; 66 | server { 67 | # 设置dns解析 68 | resolver 8.8.8.8 ipv6=off; 69 | # 监听80和443端口 70 | listen 80; 71 | listen 443 ssl; 72 | # 关闭文件索引,避免文件结构泄漏 73 | autoindex off; 74 | # 设置静态文件的目录 75 | root /www; 76 | # 开启OCSP装订,加速TLS握手效率 77 | ssl_stapling on; 78 | ssl_stapling_verify on; 79 | # 配置ssl证书和密钥 80 | ssl_certificate /app/cert.pem; 81 | ssl_certificate_key /app/cert.key; 82 | # SSL会话有效期 83 | ssl_session_timeout 5m; 84 | # 使用SSL版本,加密算法 85 | ssl_protocols TLSv1.2 TLSv1.3; 86 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 87 | ssl_prefer_server_ciphers on; 88 | # 开启HSTS,强制用户浏览器使用https协议 89 | add_header Strict-Transport-Security "max-age=2592000"; 90 | 91 | # 开启gzip压缩,配置压缩文件类型,压缩等级,最小压缩长度,关闭IE浏览器压缩 92 | gzip on; 93 | gzip_types *; 94 | gzip_comp_level 6; 95 | gzip_min_length 256; 96 | gzip_buffers 16 8k; 97 | gzip_proxied any; 98 | gzip_vary on; 99 | gzip_disable "MSIE [1-6]\.(?!.*SV1)"; 100 | 101 | # 配置匹配的域名 (重要,必须修改) 102 | server_name www.dk8s.com; 103 | 104 | # 限制下行带宽 105 | limit_rate 100k; 106 | limit_rate_after 1m; 107 | 108 | # 限制连接数 109 | limit_conn con_ip 40; 110 | 111 | # 检查客户浏览器端是否断开连接 112 | lua_check_client_abort on; 113 | 114 | # 引入限速配置文件 115 | include /app/env.conf; 116 | 117 | # 开启CDN源IP访问白名单 118 | # deny all; 119 | # allow $whitelist; 120 | 121 | # 如果后段服务为http服务,请保留这一段,并修改后段服务地址 122 | location / { 123 | # 对单个ip进行限速,请根据实际业务进行修改 124 | limit_req zone=req_ip burst=100 delay=200; 125 | # 对整个服务进行限速,请根据实际业务进行修改 126 | limit_req zone=req_svr burst=1000 delay=2000; 127 | # 向后端传递host名 128 | proxy_set_header Host $host; 129 | # 对请求IP进行限速处理 130 | access_by_lua_file /app/protect.ljbc; 131 | # 对请求IP流量进行统计 132 | log_by_lua_file /app/record.ljbc; 133 | # 调试使用 134 | # lua_code_cache off; 135 | # access_by_lua_file /app/protect.lua; 136 | # log_by_lua_file /app/record.lua; 137 | # 如果是纯静态网站,请保留index,并删除proxy_pass。 138 | # index index.php index.html index.htm; 139 | # 后段服务地址,请 根据实际情况修改 140 | proxy_pass http://127.0.0.1:3000; 141 | } 142 | 143 | # 后段服务为php-fpm。请保留这一段,否则删除 144 | # location / { 145 | # # 对单个ip进行限速,请根据实际业务进行修改 146 | # limit_req zone=req_ip burst=100 delay=200; 147 | # # 对整个服务进行限速,请根据实际业务进行修改 148 | # limit_req zone=req_svr burst=1000 delay=2000; 149 | # # 向后端传递host名 150 | # proxy_set_header Host $host; 151 | # # 对请求IP进行限速处理 152 | # access_by_lua_file /app/protect.ljbc; 153 | # # 对请求IP流量进行统计 154 | # log_by_lua_file /app/record.ljbc; 155 | # # 调试使用 156 | # # lua_code_cache off; 157 | # # access_by_lua_file /app/protect.lua; 158 | # # log_by_lua_file /app/record.lua; 159 | # # 逐个匹配php、html、htm 160 | # index index.php index.html index.htm; 161 | # } 162 | 163 | # 后段服务为php-fpm。请保留这一段,否则删除 164 | # location ~ \.php$ { 165 | # # 对单个ip进行限速,请根据实际业务进行修改 166 | # limit_req zone=req_ip burst=100 delay=200; 167 | # # 对整个服务进行限速,请根据实际业务进行修改 168 | # limit_req zone=req_svr burst=1000 delay=2000; 169 | # # 向后端传递host名 170 | # proxy_set_header Host $host; 171 | # # 对请求IP进行限速处理 172 | # access_by_lua_file /app/protect.ljbc; 173 | # # 对请求IP流量进行统计 174 | # log_by_lua_file /app/record.ljbc; 175 | # # 调试使用 176 | # # lua_code_cache off; 177 | # # access_by_lua_file /app/protect.lua; 178 | # # log_by_lua_file /app/record.lua; 179 | # # php-fpm的地址,请 根据实际情况修改 180 | # fastcgi_pass 127.0.0.1:9000; 181 | # fastcgi_index index.php; 182 | # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 183 | # include fastcgi_params; 184 | # } 185 | 186 | # 查看ip的统计信息 187 | location /dk8s.stats { 188 | # 对单个ip进行限速 189 | limit_req zone=req_ip burst=100 delay=200; 190 | # 对整个服务进行限速 191 | limit_req zone=req_svr burst=1000 delay=2000; 192 | # lua_code_cache off; 193 | # access_by_lua_file /app/protect.lua; 194 | # log_by_lua_file /app/record.lua; 195 | access_by_lua_file /app/protect.ljbc; 196 | content_by_lua_file /app/stats.ljbc; 197 | log_by_lua_file /app/record.ljbc; 198 | } 199 | 200 | # 图片资源等信息,用作配置浏览器缓存。请修改后段服务地址,或删除proxy_pass,并把图片存到/www/所在位置 201 | location ~* \.(jpg|png|jpeg)$ { 202 | # 对单个ip进行限速 203 | limit_req zone=req_ip burst=100 delay=200; 204 | # 对整个服务进行限速 205 | limit_req zone=req_svr burst=1000 delay=2000; 206 | # 对uri进行限速,防止刷单个资源,导致带宽被打爆 207 | limit_req zone=req_res burst=200 delay=1000; 208 | # lua_code_cache off; 209 | # access_by_lua_file /app/protect.lua; 210 | # log_by_lua_file /app/record.lua; 211 | # 设置浏览器资源过期时间 212 | expires 7d; 213 | proxy_set_header Host $host; 214 | access_by_lua_file /app/protect.ljbc; 215 | log_by_lua_file /app/record.ljbc; 216 | # 后段服务地址,请 根据实际情况修改。如果资源存在/www/所在的位置,请删除proxy_pass 217 | proxy_pass http://127.0.0.1:3000; 218 | } 219 | 220 | # 样式资源等信息,用作配置浏览器缓存。请修改后段服务地址,或删除proxy_pass,并把js,css存到/www/所在位置 221 | location ~* \.(js|css|svg|woff|woff2)$ { 222 | # 对单个ip进行限速 223 | limit_req zone=req_ip burst=100 delay=200; 224 | # 对整个服务进行限速 225 | limit_req zone=req_svr burst=1000 delay=2000; 226 | # 对uri进行限速,防止刷单个资源,导致带宽被打爆 227 | limit_req zone=req_res burst=200 delay=1000; 228 | # lua_code_cache off; 229 | # access_by_lua_file /app/protect.lua; 230 | # log_by_lua_file /app/record.lua; 231 | # 设置浏览器资源过期时间 232 | expires 1d; 233 | # 向后端传递host名 234 | proxy_set_header Host $host; 235 | # 让浏览器每次请求检查资源是否过期 236 | add_header Cache-Control no-cache; 237 | access_by_lua_file /app/protect.ljbc; 238 | log_by_lua_file /app/record.ljbc; 239 | # 后段服务地址,请 根据实际情况修改。如果资源存在/www/所在的位置,请删除proxy_pass 240 | proxy_pass http://127.0.0.1:3000; 241 | } 242 | 243 | error_page 429 @429; 244 | location @429 { 245 | return 429 "error"; 246 | } 247 | 248 | # location /control_group { 249 | # # 测速的对照组,生产环境请删除 250 | # proxy_set_header Host $host; 251 | # proxy_pass http://127.0.0.1:3000; 252 | # access_by_lua_block { 253 | # ngx.exit(429) 254 | # } 255 | # log_by_lua_block { 256 | # local a=0; 257 | # } 258 | # } 259 | } 260 | 261 | server { 262 | # 未匹配的域名,断开连接,防止源站被扫描 263 | listen 80 default_server; 264 | listen 443 ssl default_server; 265 | ssl_reject_handshake on; 266 | return 444; 267 | } 268 | 269 | server { 270 | # 测试用 271 | listen 3000; 272 | location / { 273 | return 200 'Ok'; 274 | } 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /protect.lua: -------------------------------------------------------------------------------- 1 | function set_key(dict, key, value) 2 | local ok, err = dict:set(key, value) 3 | if not ok then 4 | ngx.log(ngx.ERR, "Set key", key, "err", err) 5 | ngx.exit(444) 6 | end 7 | end 8 | 9 | function str_concat(...) 10 | local str = {...} 11 | return table.concat(str, ':') 12 | end 13 | 14 | function protect(during, ttl, count_limit, bytes_limit, costs_limit) 15 | local dict = ngx.shared.traffic_stats 16 | local timestamp = ngx.now() 17 | local ip = ngx.var.limit_key 18 | local count_key = str_concat("count", during, ip) 19 | local bytes_key = str_concat("bytes", during, ip) 20 | local costs_key = str_concat("costs", during, ip) 21 | local last_time_key = str_concat("last", during, ip) 22 | local forbidden_key = str_concat("forbidden", during, ip) 23 | 24 | local last_time = dict:get(last_time_key) 25 | if last_time == nil or last_time + ttl < timestamp then 26 | set_key(dict, last_time_key, timestamp) 27 | set_key(dict, count_key, 0) 28 | set_key(dict, bytes_key, 0) 29 | set_key(dict, costs_key, 0) 30 | set_key(dict, forbidden_key, false) 31 | end 32 | 33 | local count = dict:get(count_key) 34 | if count ~= nil and count > tonumber(count_limit) then 35 | set_key(dict, forbidden_key, true) 36 | ngx.exit(444) 37 | end 38 | 39 | local bytes = dict:get(bytes_key) 40 | if bytes ~= nil and bytes > tonumber(bytes_limit) then 41 | set_key(dict, forbidden_key, true) 42 | ngx.exit(444) 43 | end 44 | 45 | local cost = dict:get(costs_key) 46 | if cost ~= nil and cost > tonumber(costs_limit) then 47 | set_key(dict, forbidden_key, true) 48 | ngx.exit(444) 49 | end 50 | end 51 | 52 | protect("hour", 3600, ngx.var.limit_count_per_hour, ngx.var.limit_bytes_per_hour, ngx.var.limit_costs_per_hour) 53 | protect("day", 3600 * 24, ngx.var.limit_count_per_day, ngx.var.limit_bytes_per_day, ngx.var.limit_costs_per_day) 54 | -------------------------------------------------------------------------------- /record.lua: -------------------------------------------------------------------------------- 1 | 2 | function str_concat(...) 3 | local str = {...} 4 | return table.concat(str, ':') 5 | end 6 | 7 | function stats(during) 8 | local request_length = ngx.var.request_length 9 | local bytes_sent = ngx.var.bytes_sent 10 | local ip = ngx.var.limit_key 11 | local dict = ngx.shared.traffic_stats 12 | local count_key = str_concat("count", during, ip) 13 | local bytes_key = str_concat("bytes", during, ip) 14 | local costs_key = str_concat("costs", during, ip) 15 | dict:incr(count_key, 1) 16 | dict:incr(bytes_key, request_length + bytes_sent) 17 | dict:incr(costs_key, math.floor(ngx.var.request_time * 1000)) 18 | --ngx.log(ngx.INFO, string.format('Usage %20s %5d %5d %5d', 19 | -- ip, 1, request_length + bytes_sent, math.floor(ngx.var.request_time * 1000))) 20 | end 21 | 22 | stats("hour") 23 | stats("day") 24 | -------------------------------------------------------------------------------- /stats.lua: -------------------------------------------------------------------------------- 1 | 2 | function stats(during) 3 | local timestamp = ngx.now() 4 | local dict = ngx.shared.traffic_stats 5 | for _, val in pairs(dict:get_keys(0)) do 6 | local match = "last:"..during 7 | if string.sub(val, 1, #match) == match then 8 | local ip = string.sub(val, #match + 2, -1) 9 | local last_time = dict:get(val) 10 | local age = math.floor(timestamp - last_time) 11 | local count = dict:get("count:"..during..":"..ip) 12 | local bytes = dict:get("bytes:"..during..":"..ip) 13 | local costs = dict:get("costs:"..during..":"..ip) 14 | local forbidden = dict:get("forbidden:"..during..":"..ip) 15 | local output = string.format("%20s, %15s, %15d, %15d, %15d, %15d, %15s", 16 | ip, during, age, count, bytes, costs, forbidden) 17 | ngx.say(output) 18 | end 19 | end 20 | end 21 | 22 | ngx.say(string.format("%20s, %15s, %15s, %15s, %15s, %15s, %15s", 23 | 'ip', 'during', 'age', 'count', 'bytes', 'costs', 'forbidden')) 24 | stats("hour") 25 | stats("day") 26 | -------------------------------------------------------------------------------- /wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yinyue123/DK8sDDosFirewall/e55de6074a1f2906d2826f93bd6ca7e3de2ab18c/wechat.jpg -------------------------------------------------------------------------------- /wrk.lua: -------------------------------------------------------------------------------- 1 | local random = math.random 2 | 3 | function request() 4 | local ip = string.format("%d.%d.%d.%d", random(0, 255), random(0, 255), random(0, 255), random(0, 255)) 5 | wrk.headers["X-Forwarded-For"] = ip 6 | return wrk.format("GET", path) 7 | end 8 | 9 | -- wrk -s ./wrk.lua -c 500 -t 8 -d 600s -c 10 http://[target] 10 | -- wrk -s ./wrk.lua -c 500 -t 8 -d 600s -c 150 http://[target] 11 | -- wrk -s ./wrk.lua -c 500 -t 8 -d 600s -c 100000 http://[target] 12 | --------------------------------------------------------------------------------