mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: 增加网站防火墙相关
This commit is contained in:
parent
5b63dc42a2
commit
1bd5a180b3
@ -1,4 +1,4 @@
|
||||
user nginx;
|
||||
#user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
@ -36,5 +36,11 @@ http {
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
|
||||
lua_code_cache on;
|
||||
lua_shared_dict limit 10m;
|
||||
lua_package_path "/www/common/waf/?.lua;/usr/local/openresty/lualib/?.lua;";
|
||||
init_by_lua_file /www/common/waf/init.lua;
|
||||
|
||||
include /usr/local/openresty/nginx/conf/conf.d/*.conf;
|
||||
}
|
@ -1,16 +1,12 @@
|
||||
version: '3'
|
||||
services:
|
||||
nginx1.23.1:
|
||||
container_name: nginx1.23.1
|
||||
image: nginx:1.23.1
|
||||
openresty1.21.4:
|
||||
image: openresty/openresty:1.21.4.1-3-alpine
|
||||
restart: always
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
|
||||
- ./log:/var/log/nginx
|
||||
- ./conf/conf.d:/etc/nginx/conf.d/
|
||||
- ./ssl:/etc/nginx/ssl
|
||||
- ./www:/www/root/
|
||||
- ./conf/conf.d:/usr/local/openresty/nginx/conf/conf.d/
|
||||
- ./www:/www
|
||||
- ./root:/usr/share/nginx/html
|
||||
|
||||
|
||||
|
374
apps/nginx/versions/1.23.1/www/common/waf/access.lua
Normal file
374
apps/nginx/versions/1.23.1/www/common/waf/access.lua
Normal file
@ -0,0 +1,374 @@
|
||||
local match = string.match
|
||||
local ngxmatch=ngx.re.match
|
||||
local unescape=ngx.unescape_uri
|
||||
local get_headers = ngx.req.get_headers
|
||||
local cjson = require "cjson"
|
||||
local content_length=tonumber(ngx.req.get_headers()['content-length'])
|
||||
local method=ngx.req.get_method()
|
||||
|
||||
|
||||
local function optionIsOn(options)
|
||||
return options == "on" or options == "On" or options == "ON"
|
||||
end
|
||||
|
||||
local logpath = ngx.var.logdir
|
||||
local rulepath = ngx.var.RulePath
|
||||
local UrlDeny = optionIsOn(ngx.var.UrlDeny)
|
||||
local PostCheck = optionIsOn(ngx.var.postMatch)
|
||||
local CookieCheck = optionIsOn(ngx.var.cookieMatch)
|
||||
local WhiteCheck = optionIsOn(ngx.var.whiteModule)
|
||||
local attacklog = optionIsOn(ngx.var.attacklog)
|
||||
local CCDeny = optionIsOn(ngx.var.CCDeny)
|
||||
local Redirect=optionIsOn(ngx.var.Redirect)
|
||||
|
||||
|
||||
|
||||
local function getClientIp()
|
||||
IP = ngx.var.remote_addr
|
||||
if IP == nil then
|
||||
IP = "unknown"
|
||||
end
|
||||
return IP
|
||||
end
|
||||
local function write(logfile,msg)
|
||||
local fd = io.open(logfile,"ab")
|
||||
if fd == nil then return end
|
||||
fd:write(msg)
|
||||
fd:flush()
|
||||
fd:close()
|
||||
end
|
||||
local function log(method,url,data,ruletag)
|
||||
if attacklog then
|
||||
local realIp = getClientIp()
|
||||
local ua = ngx.var.http_user_agent
|
||||
local servername=ngx.var.server_name
|
||||
local time=ngx.localtime()
|
||||
local line = nil
|
||||
if ua then
|
||||
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n"
|
||||
else
|
||||
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n"
|
||||
end
|
||||
local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
|
||||
write(filename,line)
|
||||
end
|
||||
end
|
||||
------------------------------------规则读取函数-------------------------------------------------------------------
|
||||
local function read_rule(var)
|
||||
file = io.open(rulepath..'/'..var,"r")
|
||||
if file==nil then
|
||||
return
|
||||
end
|
||||
t = {}
|
||||
for line in file:lines() do
|
||||
table.insert(t,line)
|
||||
end
|
||||
file:close()
|
||||
return(t)
|
||||
end
|
||||
|
||||
local function read_json(var)
|
||||
file = io.open(rulepath..'/'..var,"r")
|
||||
if file==nil then
|
||||
return
|
||||
end
|
||||
str = file:read("*a")
|
||||
file:close()
|
||||
list = cjson.decode(str)
|
||||
return list
|
||||
end
|
||||
|
||||
local function read_str(var)
|
||||
file = io.open(rulepath..'/'..var,"r")
|
||||
if file==nil then
|
||||
return
|
||||
end
|
||||
local str = file:read("*a")
|
||||
file:close()
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
|
||||
local urlrules=read_rule('url')
|
||||
local argsrules=read_rule('args')
|
||||
local uarules=read_rule('user-agent')
|
||||
local wturlrules=read_rule('whiteurl')
|
||||
local postrules=read_rule('post')
|
||||
local ckrules=read_rule('cookie')
|
||||
local ccrate=read_str('ccrate')
|
||||
local ipWhitelist=read_json('ipWhitelist')
|
||||
local ipBlocklist=read_json('ipBlocklist')
|
||||
local black_fileExt = read_json('blackfileExt')
|
||||
local html=read_str('html')
|
||||
|
||||
|
||||
local function say_html()
|
||||
if Redirect then
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.status = ngx.HTTP_FORBIDDEN
|
||||
ngx.say(html)
|
||||
ngx.exit(ngx.status)
|
||||
end
|
||||
end
|
||||
|
||||
local function whiteurl()
|
||||
if WhiteCheck then
|
||||
if wturlrules ~=nil then
|
||||
for _,rule in pairs(wturlrules) do
|
||||
if ngxmatch(ngx.var.uri,rule,"isjo") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function fileExtCheck(ext)
|
||||
local items = Set(black_fileExt)
|
||||
ext=string.lower(ext)
|
||||
if ext then
|
||||
for rule in pairs(items) do
|
||||
if ngx.re.match(ext,rule,"isjo") then
|
||||
log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
|
||||
say_html()
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
local function args()
|
||||
if argsrules then
|
||||
for _,rule in pairs(argsrules) do
|
||||
local uriArgs = ngx.req.get_uri_args()
|
||||
for key, val in pairs(uriArgs) do
|
||||
if type(val)=='table' then
|
||||
local t={}
|
||||
for k,v in pairs(val) do
|
||||
if v == true then
|
||||
v=""
|
||||
end
|
||||
table.insert(t,v)
|
||||
end
|
||||
data=table.concat(t, " ")
|
||||
else
|
||||
data=val
|
||||
end
|
||||
if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"isjo") then
|
||||
log('GET',ngx.var.request_uri,"-",rule)
|
||||
say_html()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
local function url()
|
||||
if UrlDeny then
|
||||
for _,rule in pairs(urlrules) do
|
||||
if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"isjo") then
|
||||
log('GET',ngx.var.request_uri,"-",rule)
|
||||
say_html()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ua()
|
||||
local ua = ngx.var.http_user_agent
|
||||
if ua ~= nil then
|
||||
for _,rule in pairs(uarules) do
|
||||
if rule ~="" and ngxmatch(ua,rule,"isjo") then
|
||||
log('UA',ngx.var.request_uri,"-",rule)
|
||||
say_html()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function body(data)
|
||||
for _,rule in pairs(postrules) do
|
||||
if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"isjo") then
|
||||
log('POST',ngx.var.request_uri,data,rule)
|
||||
say_html()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function cookie()
|
||||
local ck = ngx.var.http_cookie
|
||||
if CookieCheck and ck then
|
||||
for _,rule in pairs(ckrules) do
|
||||
if rule ~="" and ngxmatch(ck,rule,"isjo") then
|
||||
log('Cookie',ngx.var.request_uri,"-",rule)
|
||||
say_html()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function denycc()
|
||||
if CCDeny and ccrate then
|
||||
local uri=ngx.var.uri
|
||||
CCcount=tonumber(string.match(ccrate,'(.*)/'))
|
||||
CCseconds=tonumber(string.match(ccrate,'/(.*)'))
|
||||
local uri = getClientIp()..uri
|
||||
local limit = ngx.shared.limit
|
||||
local req,_=limit:get(uri)
|
||||
if req then
|
||||
if req > CCcount then
|
||||
ngx.exit(503)
|
||||
return true
|
||||
else
|
||||
limit:incr(token,1)
|
||||
end
|
||||
else
|
||||
limit:set(uri,1,CCseconds)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function get_boundary()
|
||||
local header = get_headers()["content-type"]
|
||||
if not header then
|
||||
return nil
|
||||
end
|
||||
|
||||
if type(header) == "table" then
|
||||
header = header[1]
|
||||
end
|
||||
|
||||
local m = match(header, ";%s*boundary=\"([^\"]+)\"")
|
||||
if m then
|
||||
return m
|
||||
end
|
||||
|
||||
return match(header, ";%s*boundary=([^\",;]+)")
|
||||
end
|
||||
|
||||
local function whiteip()
|
||||
if next(ipWhitelist) ~= nil then
|
||||
for _,ip in pairs(ipWhitelist) do
|
||||
if getClientIp()==ip then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function blockip()
|
||||
if next(ipBlocklist) ~= nil then
|
||||
for _,ip in pairs(ipBlocklist) do
|
||||
if getClientIp()==ip then
|
||||
ngx.exit(403)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
if whiteip() then
|
||||
elseif blockip() then
|
||||
elseif denycc() then
|
||||
elseif ngx.var.http_Acunetix_Aspect then
|
||||
ngx.exit(444)
|
||||
elseif ngx.var.http_X_Scan_Memo then
|
||||
ngx.exit(444)
|
||||
elseif whiteurl() then
|
||||
elseif ua() then
|
||||
elseif url() then
|
||||
elseif args() then
|
||||
elseif cookie() then
|
||||
elseif PostCheck then
|
||||
if method=="POST" then
|
||||
local boundary = get_boundary()
|
||||
if boundary then
|
||||
local len = string.len
|
||||
local sock, err = ngx.req.socket()
|
||||
if not sock then
|
||||
return
|
||||
end
|
||||
ngx.req.init_body(128 * 1024)
|
||||
sock:settimeout(0)
|
||||
local content_length = nil
|
||||
content_length=tonumber(ngx.req.get_headers()['content-length'])
|
||||
local chunk_size = 4096
|
||||
if content_length < chunk_size then
|
||||
chunk_size = content_length
|
||||
end
|
||||
local size = 0
|
||||
while size < content_length do
|
||||
local data, err, partial = sock:receive(chunk_size)
|
||||
data = data or partial
|
||||
if not data then
|
||||
return
|
||||
end
|
||||
ngx.req.append_body(data)
|
||||
if body(data) then
|
||||
return true
|
||||
end
|
||||
size = size + len(data)
|
||||
local m = ngxmatch(data,[[Content-Disposition: form-data;(.+)filename="(.+)\\.(.*)"]],'ijo')
|
||||
if m then
|
||||
fileExtCheck(m[3])
|
||||
filetranslate = true
|
||||
else
|
||||
if ngxmatch(data,"Content-Disposition:",'isjo') then
|
||||
filetranslate = false
|
||||
end
|
||||
if filetranslate==false then
|
||||
if body(data) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
local less = content_length - size
|
||||
if less < chunk_size then
|
||||
chunk_size = less
|
||||
end
|
||||
end
|
||||
ngx.req.finish_body()
|
||||
else
|
||||
ngx.req.read_body()
|
||||
local args = ngx.req.get_post_args()
|
||||
if not args then
|
||||
return
|
||||
end
|
||||
for key, val in pairs(args) do
|
||||
if type(val) == "table" then
|
||||
if type(val[1]) == "boolean" then
|
||||
return
|
||||
end
|
||||
data=table.concat(val, ", ")
|
||||
else
|
||||
data=val
|
||||
end
|
||||
if data and type(data) ~= "boolean" and body(data) then
|
||||
body(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
1
apps/nginx/versions/1.23.1/www/common/waf/init.lua
Normal file
1
apps/nginx/versions/1.23.1/www/common/waf/init.lua
Normal file
@ -0,0 +1 @@
|
||||
ngx.log(ngx.INFO,"init success")
|
22
apps/nginx/versions/1.23.1/www/common/waf/rules/args
Normal file
22
apps/nginx/versions/1.23.1/www/common/waf/rules/args
Normal file
@ -0,0 +1,22 @@
|
||||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
@ -0,0 +1 @@
|
||||
["php","jsp"]
|
1
apps/nginx/versions/1.23.1/www/common/waf/rules/ccrate
Normal file
1
apps/nginx/versions/1.23.1/www/common/waf/rules/ccrate
Normal file
@ -0,0 +1 @@
|
||||
100/60
|
20
apps/nginx/versions/1.23.1/www/common/waf/rules/cookie
Normal file
20
apps/nginx/versions/1.23.1/www/common/waf/rules/cookie
Normal file
@ -0,0 +1,20 @@
|
||||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
30
apps/nginx/versions/1.23.1/www/common/waf/rules/html
Normal file
30
apps/nginx/versions/1.23.1/www/common/waf/rules/html
Normal file
@ -0,0 +1,30 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>网站防火墙</title>
|
||||
<style>
|
||||
p {
|
||||
line-height:20px;
|
||||
}
|
||||
ul{ list-style-type:none;}
|
||||
li{ list-style-type:none;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style=" padding:0; margin:0; font:14px/1.5 Microsoft Yahei, 宋体,sans-serif; color:#555;">
|
||||
|
||||
<div style="margin: 0 auto; width:1000px; padding-top:70px; overflow:hidden;">
|
||||
|
||||
|
||||
<div style="width:600px; float:left;">
|
||||
<div style=" height:40px; line-height:40px; color:#fff; font-size:16px; overflow:hidden; background:#6bb3f6; padding-left:20px;">网站防火墙 </div>
|
||||
<div style="border:1px dashed #cdcece; border-top:none; font-size:14px; background:#fff; color:#555; line-height:24px; height:220px; padding:20px 20px 0 20px; overflow-y:auto;background:#f3f7f9;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#fc4f03;">您的请求带有不合法参数,已被网站管理员设置拦截!</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">可能原因:您提交的内容包含危险的攻击请求</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;">如何解决:</p>
|
||||
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1)检查提交内容;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2)如网站托管,请联系空间提供商;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3)普通网站访客,请联系网站管理员;</li></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
@ -0,0 +1 @@
|
||||
[]
|
@ -0,0 +1 @@
|
||||
[]
|
19
apps/nginx/versions/1.23.1/www/common/waf/rules/post
Normal file
19
apps/nginx/versions/1.23.1/www/common/waf/rules/post
Normal file
@ -0,0 +1,19 @@
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
6
apps/nginx/versions/1.23.1/www/common/waf/rules/url
Normal file
6
apps/nginx/versions/1.23.1/www/common/waf/rules/url
Normal file
@ -0,0 +1,6 @@
|
||||
\.(svn|htaccess|bash_history)
|
||||
\.(bak|inc|old|mdb|sql|backup|java|class)$
|
||||
(vhost|bbs|host|wwwroot|www|site|root|hytop|flashfxp).*\.rar
|
||||
(phpmyadmin|jmx-console|jmxinvokerservlet)
|
||||
java\.lang
|
||||
/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp)
|
@ -0,0 +1 @@
|
||||
(HTTrack|harvest|audit|dirbuster|pangolin|nmap|sqln|-scan|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|PycURL|zmeu|BabyKrokodil|netsparker|httperf|bench| SF/)
|
1
apps/nginx/versions/1.23.1/www/common/waf/rules/whiteurl
Normal file
1
apps/nginx/versions/1.23.1/www/common/waf/rules/whiteurl
Normal file
@ -0,0 +1 @@
|
||||
^/123/$
|
@ -4,7 +4,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||
"os"
|
||||
"path"
|
||||
@ -49,9 +48,6 @@ func getHttpConfigByKeys(keys []string) ([]dto.NginxParam, error) {
|
||||
Name: dir.GetName(),
|
||||
Params: dir.GetParameters(),
|
||||
}
|
||||
if isRepeatKey(key) {
|
||||
nginxParam.SecondKey = dir.GetParameters()[0]
|
||||
}
|
||||
res = append(res, nginxParam)
|
||||
}
|
||||
if len(dirs) == 0 {
|
||||
@ -73,15 +69,7 @@ func updateHttpNginxConfig(params []dto.NginxParam) error {
|
||||
config := nginxConfig.Config
|
||||
http := config.FindHttp()
|
||||
for _, p := range params {
|
||||
newDir := components.Directive{
|
||||
Name: p.Name,
|
||||
Parameters: p.Params,
|
||||
}
|
||||
if isRepeatKey(p.Name) {
|
||||
http.UpdateDirectiveBySecondKey(p.Name, p.SecondKey, newDir)
|
||||
} else {
|
||||
http.UpdateDirectives(p.Name, newDir)
|
||||
}
|
||||
http.UpdateDirective(p.Name, p.Params)
|
||||
}
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
|
@ -347,7 +347,7 @@ func (w WebsiteService) UpdateNginxConfigByScope(req dto.NginxConfigReq) error {
|
||||
return err
|
||||
}
|
||||
if req.Operate == dto.ConfigDel {
|
||||
return deleteNginxConfig(website, keys)
|
||||
return deleteNginxConfig(website, constant.NginxScopeServer, keys)
|
||||
}
|
||||
|
||||
return updateNginxConfig(website, getNginxParams(req.Params, keys), req.Scope)
|
||||
@ -468,7 +468,7 @@ func (w WebsiteService) OpWebsiteHTTPS(req dto.WebsiteHTTPSOp) (dto.WebsiteHTTPS
|
||||
return dto.WebsiteHTTPS{}, err
|
||||
}
|
||||
|
||||
if err := deleteNginxConfig(website, getKeysFromStaticFile(dto.SSL)); err != nil {
|
||||
if err := deleteNginxConfig(website, constant.NginxScopeServer, getKeysFromStaticFile(dto.SSL)); err != nil {
|
||||
return dto.WebsiteHTTPS{}, err
|
||||
}
|
||||
}
|
||||
|
@ -44,15 +44,12 @@ func getDomain(domainStr string, websiteID uint) (model.WebSiteDomain, error) {
|
||||
}
|
||||
|
||||
func createStaticHtml(website *model.WebSite) error {
|
||||
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
|
||||
nginxInstall, err := getAppInstallByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(nginxApp.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "www", website.Alias)
|
||||
|
||||
indexFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "www", "sites", website.Alias)
|
||||
indexPath := path.Join(indexFolder, "index.html")
|
||||
indexContent := string(nginx_conf.Index)
|
||||
fileOp := files.NewFileOp()
|
||||
@ -72,14 +69,38 @@ func createStaticHtml(website *model.WebSite) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite) error {
|
||||
|
||||
nginxFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name)
|
||||
siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(siteFolder) {
|
||||
if err := fileOp.CreateDir(siteFolder, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CreateDir(path.Join(siteFolder, "log"), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CreateFile(path.Join(siteFolder, "log", "access.log")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CreateDir(path.Join(siteFolder, "waf", "rules"), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CreateDir(path.Join(siteFolder, "data"), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf", "rules"))
|
||||
}
|
||||
|
||||
func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) error {
|
||||
|
||||
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
|
||||
nginxInstall, err := getAppInstallByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(nginxApp.ID))
|
||||
if err != nil {
|
||||
if err := createWebsiteFolder(nginxInstall, website); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -98,6 +119,14 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e
|
||||
server.UpdateListen(strconv.Itoa(domain.Port), false)
|
||||
}
|
||||
server.UpdateServerName(serverNames)
|
||||
|
||||
siteFolder := path.Join("/www", "sites", website.Alias)
|
||||
commonFolder := path.Join("/www", "common")
|
||||
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log")})
|
||||
server.UpdateDirective("access_by_lua_file", []string{path.Join(commonFolder, "waf", "access.lua")})
|
||||
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
|
||||
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "waf", "log")})
|
||||
|
||||
if website.Type == "deployment" {
|
||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
@ -106,7 +135,7 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e
|
||||
proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort)
|
||||
server.UpdateRootProxy([]string{proxy})
|
||||
} else {
|
||||
server.UpdateRoot(path.Join("/www/root", website.Alias))
|
||||
server.UpdateRoot(path.Join("/www/sites", website.Alias))
|
||||
server.UpdateRootLocation()
|
||||
}
|
||||
|
||||
@ -114,15 +143,16 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := opNginx(nginxInstall.ContainerName, "check"); err != nil {
|
||||
|
||||
if err := opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
return opNginx(nginxInstall.ContainerName, "reload")
|
||||
return opNginx(nginxInstall.ContainerName, constant.NginxReload)
|
||||
}
|
||||
|
||||
func opNginx(containerName, operate string) error {
|
||||
nginxCmd := fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -s reload")
|
||||
if operate == "check" {
|
||||
if operate == constant.NginxCheck {
|
||||
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
||||
}
|
||||
if out, err := cmd.Exec(nginxCmd); err != nil {
|
||||
@ -160,12 +190,12 @@ func delNginxConfig(website model.WebSite) error {
|
||||
|
||||
func nginxCheckAndReload(oldContent string, filePath string, containerName string) error {
|
||||
|
||||
if err := opNginx(containerName, "check"); err != nil {
|
||||
if err := opNginx(containerName, constant.NginxCheck); err != nil {
|
||||
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := opNginx(containerName, "reload"); err != nil {
|
||||
if err := opNginx(containerName, constant.NginxReload); err != nil {
|
||||
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
||||
return err
|
||||
}
|
||||
@ -253,9 +283,6 @@ func getNginxConfigByKeys(website model.WebSite, keys []string) ([]dto.NginxPara
|
||||
Name: dir.GetName(),
|
||||
Params: dir.GetParameters(),
|
||||
}
|
||||
if isRepeatKey(key) {
|
||||
nginxParam.SecondKey = dir.GetParameters()[0]
|
||||
}
|
||||
res = append(res, nginxParam)
|
||||
}
|
||||
}
|
||||
@ -271,15 +298,7 @@ func updateNginxConfig(website model.WebSite, params []dto.NginxParam, scope dto
|
||||
updateConfig(config, scope)
|
||||
server := config.FindServers()[0]
|
||||
for _, p := range params {
|
||||
newDir := components.Directive{
|
||||
Name: p.Name,
|
||||
Parameters: p.Params,
|
||||
}
|
||||
if isRepeatKey(p.Name) {
|
||||
server.UpdateDirectiveBySecondKey(p.Name, p.SecondKey, newDir)
|
||||
} else {
|
||||
server.UpdateDirectives(p.Name, newDir)
|
||||
}
|
||||
server.UpdateDirective(p.Name, p.Params)
|
||||
}
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
@ -298,15 +317,7 @@ func updateConfig(config *components.Config, scope dto.NginxKey) {
|
||||
}
|
||||
|
||||
for _, dir := range newConfig.GetDirectives() {
|
||||
newDir := components.Directive{
|
||||
Name: dir.GetName(),
|
||||
Parameters: dir.GetParameters(),
|
||||
}
|
||||
if isRepeatKey(dir.GetName()) {
|
||||
config.UpdateDirectiveBySecondKey(dir.GetName(), dir.GetParameters()[0], newDir)
|
||||
} else {
|
||||
config.UpdateDirectives(dir.GetName(), newDir)
|
||||
}
|
||||
config.UpdateDirective(dir.GetName(), dir.GetParameters())
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,15 +350,24 @@ func getKeysFromStaticFile(scope dto.NginxKey) []string {
|
||||
return res
|
||||
}
|
||||
|
||||
func deleteNginxConfig(website model.WebSite, keys []string) error {
|
||||
func deleteNginxConfig(website model.WebSite, scope string, keys []string) error {
|
||||
nginxConfig, err := getNginxConfig(website.Alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := nginxConfig.Config
|
||||
config.RemoveDirectives(keys)
|
||||
server := config.FindServers()[0]
|
||||
server.RemoveDirectives(keys)
|
||||
if scope == constant.NginxScopeHttp {
|
||||
http := config.FindHttp()
|
||||
for _, key := range keys {
|
||||
http.RemoveDirective(key, []string{})
|
||||
}
|
||||
}
|
||||
if scope == constant.NginxScopeServer {
|
||||
server := config.FindServers()[0]
|
||||
for _, key := range keys {
|
||||
server.RemoveDirective(key, []string{})
|
||||
}
|
||||
}
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -452,9 +472,6 @@ func handleParamMap(paramMap map[string]string, keys []string) []dto.NginxParam
|
||||
Name: k,
|
||||
Params: getParamArray(k, v),
|
||||
}
|
||||
if isRepeatKey(k) {
|
||||
param.SecondKey = param.Params[0]
|
||||
}
|
||||
nginxParams = append(nginxParams, param)
|
||||
}
|
||||
}
|
||||
@ -478,14 +495,6 @@ func getNginxParams(params interface{}, keys []string) []dto.NginxParam {
|
||||
return nginxParams
|
||||
}
|
||||
|
||||
func isRepeatKey(key string) bool {
|
||||
|
||||
if _, ok := dto.RepeatKeys[key]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func toMapStr(m map[string]interface{}) map[string]string {
|
||||
ret := make(map[string]string, len(m))
|
||||
for k, v := range m {
|
||||
|
11
backend/constant/nginx.go
Normal file
11
backend/constant/nginx.go
Normal file
@ -0,0 +1,11 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
NginxScopeServer = "server"
|
||||
NginxScopeHttp = "http"
|
||||
)
|
||||
|
||||
const (
|
||||
NginxReload = "reload"
|
||||
NginxCheck = "check"
|
||||
)
|
@ -119,9 +119,9 @@ func (b *Block) RemoveDirective(key string, params []string) {
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
if IsRepeatKey(key) && len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if len(oldParams) > 0 && oldParams[0] == params[0] {
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
|
@ -102,9 +102,9 @@ func (h *Http) RemoveDirective(key string, params []string) {
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
if IsRepeatKey(key) && len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if len(oldParams) > 0 && oldParams[0] == params[0] {
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
|
@ -73,7 +73,7 @@ func (s *Server) UpdateDirective(key string, params []string) {
|
||||
if key == "" || len(params) == 0 {
|
||||
return
|
||||
}
|
||||
directives := s.GetDirectives()
|
||||
directives := s.Directives
|
||||
index := -1
|
||||
for i, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
@ -100,13 +100,13 @@ func (s *Server) UpdateDirective(key string, params []string) {
|
||||
}
|
||||
|
||||
func (s *Server) RemoveDirective(key string, params []string) {
|
||||
directives := s.GetDirectives()
|
||||
directives := s.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
if IsRepeatKey(key) && len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if len(oldParams) > 0 && oldParams[0] == params[0] {
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
|
@ -112,9 +112,9 @@ func (us *Upstream) RemoveDirective(key string, params []string) {
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
if IsRepeatKey(key) && len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if len(oldParams) > 0 && oldParams[0] == params[0] {
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
|
@ -12,5 +12,17 @@ server {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
access_log /var/log/nginx/nginx-log.log;
|
||||
|
||||
access_log /www/sites/domain/log/access.log;
|
||||
|
||||
access_by_lua_file /www/common/waf/access.lua;
|
||||
set $RulePath /www/sites/domain/waf/rules;
|
||||
set $logdir /www/sites/domain/waf/log;
|
||||
set $CCDeny on;
|
||||
set $attacklog on;
|
||||
set $whiteModule on;
|
||||
set $getMatch on;
|
||||
set $cookieMatch on;
|
||||
set $postMatch on;
|
||||
set $Redirect on;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ export namespace Nginx {
|
||||
}
|
||||
export interface NginxParam {
|
||||
name: string;
|
||||
secondKey: string;
|
||||
params: string[];
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,6 @@ export namespace WebSite {
|
||||
|
||||
export interface NginxParam {
|
||||
name: string;
|
||||
secondKey: string;
|
||||
params: string[];
|
||||
}
|
||||
|
||||
|
@ -68,10 +68,10 @@ const search = (req: WebSite.NginxConfigReq) => {
|
||||
enable.value = true;
|
||||
for (const param of res.data) {
|
||||
if (param.name === 'limit_conn') {
|
||||
if (param.secondKey === 'perserver') {
|
||||
if (param.params[0] === 'perserver') {
|
||||
form.perserver = Number(param.params[1]);
|
||||
}
|
||||
if (param.secondKey === 'perip') {
|
||||
if (param.params[0] === 'perip') {
|
||||
form.perip = Number(param.params[1]);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user