# coding: utf-8 # ------------------------------------------------------------------- # YakPanel # ------------------------------------------------------------------- # Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved. # ------------------------------------------------------------------- # Author: wzz # ------------------------------------------------------------------- import json import os # ------------------------------ # docker - 反向代理模型 # ------------------------------ import sys if "/www/server/panel/class" not in sys.path: sys.path.insert(0, "/www/server/panel/class") os.chdir("/www/server/panel") import public class main(): def __init__(self): self._proxy_path = '/www/server/proxy_project' self._proxy_config_path = self._proxy_path + '/sites' self._site_proxy_conf_path = "" if not os.path.exists(self._proxy_config_path): public.ExecShell('mkdir -p {}'.format(self._proxy_config_path)) public.ExecShell('chown -R www:www {}'.format(self._proxy_config_path)) public.ExecShell('chmod -R 755 {}'.format(self._proxy_config_path)) self._init_proxy_conf = { "site_name": "", "domain_list": [], "site_port": [], "https_port": "443", "ipv4_port_conf": "listen {listen_port};", "ipv6_port_conf": "listen [::]:{listen_port};", "port_conf": "listen {listen_port};{listen_ipv6}", "ipv4_ssl_port_conf": "{ipv4_port_conf}\n listen {https_port} ssl http2 ;", "ipv6_ssl_port_conf": "{ipv6_port_conf}\n listen [::]:{https_port} ssl http2 ;", "ipv4_http3_ssl_port_conf": "{ipv4_port_conf}\n listen {https_port} quic;\n listen {https_port} ssl;", "ipv6_http3_ssl_port_conf": "{ipv6_port_conf}\n listen [::]:{https_port} quic;\n listen [::]:{https_port} ssl ;", "site_path": "", "ssl_info": { "ssl_status": False, "ssl_default_conf": "#error_page 404/404.html;", "ssl_conf": '#error_page 404/404.html;\n ssl_certificate /www/server/panel/vhost/cert/{site_name}/fullchain.pem;\n ssl_certificate_key /www/server/panel/vhost/cert/{site_name}/privkey.pem;\n ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;\n ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;\n ssl_prefer_server_ciphers on;\n ssl_session_cache shared:SSL:10m;\n ssl_session_timeout 10m;\n add_header Strict-Transport-Security "max-age=31536000";\n error_page 497 https://$host$request_uri;', "force_ssl_conf": '#error_page 404/404.html;{force_conf}\n ssl_certificate /www/server/panel/vhost/cert/{site_name}/fullchain.pem;\n ssl_certificate_key /www/server/panel/vhost/cert/{site_name}/privkey.pem;\n ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;\n ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;\n ssl_prefer_server_ciphers on;\n ssl_session_cache shared:SSL:10m;\n ssl_session_timeout 10m;\n add_header Strict-Transport-Security "max-age=31536000";\n error_page 497 https://$host$request_uri;', "force_https": False, "force_conf": " #HTTP_TO_HTTPS_START\n if ($server_port !~ 443){\n rewrite ^(/.*)$ https://$host$1 permanent;\n }\n #HTTP_TO_HTTPS_END", }, "err_age_404": "", "err_age_502": "", "ip_limit": { "ip_black": [], "ip_white": [], }, "basic_auth": [], "proxy_cache": { "cache_status": False, "cache_zone": "", "static_cache": "", "expires": "1d", "cache_conf": "", }, "gzip": { "gzip_status": False, "gzip_min_length": "1k", "gzip_comp_level": "6", "gzip_types": "text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js", "gzip_conf": "gzip on;\n gzip_min_length 10k;\n gzip_buffers 4 16k;\n gzip_http_version 1.1;\n gzip_comp_level 2;\n gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;\n gzip_vary on;\n gzip_proxied expired no-cache no-store private auth;\n gzip_disable \"MSIE [1-6]\.\";", }, "subs_filter": False, "sub_filter": { "sub_filter_str": [], }, "websocket": { "websocket_status": True, "websocket_conf": "proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection $connection_upgrade;", }, "security": { "security_status": False, "static_resource": "jpg|jpeg|gif|png|js|css", "return_resource": "404", "http_status": False, "domains": "", "security_conf": " #SECURITY-START Hotlink protection configuration" "\n location ~ .*\.({static_resource})$" "\n {{\n expires {expires};" "\n access_log /dev/null;" "\n valid_referers {domains};" "\n if ($invalid_referer){{" "\n return {return_resource};" "\n }}" "\n }}\n #SECURITY-END", }, "redirect": { "redirect_status": False, "redirect_conf": " #引用重定向规则,注释后配置的重定向代理将无效\n include /www/server/panel/vhost/nginx/redirect/{site_name}/*.conf;", }, "proxy_log": { "log_type": "default", "server_port": "", "log_path": "", "log_conf": "\naccess_log {log_path}/{site_name}.log;\n error_log {log_path}/{site_name}.error.log;", }, "default_cache": "proxy_cache_path /www/wwwroot/{site_name}/proxy_cache_dir levels=1:2 keys_zone={cache_name}_cache:20m inactive=1d max_size=5g;", "default_describe": "# 如果反代网站访问异常且这里已经配置了内容,请优先排查此处的配置是否正确\n", "http_block": "", "server_block": "", "remark": "", "proxy_info": [], } self._template_conf = '''{http_block} server {{ {port_conf} server_name {domains}; index index.php index.html index.htm default.php default.htm default.html; root {site_path}; #CERT-APPLY-CHECK--START # 用于SSL证书申请时的文件验证相关配置 -- 请勿删除 include /www/server/panel/vhost/nginx/well-known/{site_name}.conf; #CERT-APPLY-CHECK--END #SSL-START {ssl_start_msg} {ssl_info} #SSL-END #REDIRECT START {redirect_conf} #REDIRECT END #ERROR-PAGE-START {err_page_msg} {err_age_404} {err_age_502} #ERROR-PAGE-END #PHP-INFO-START PHP引用配置,可以注释或修改 {security_conf} include enable-php-00.conf; #PHP-INFO-END #IP-RESTRICT-START 限制访问ip的配置,IP黑白名单 {ip_limit_conf} #IP-RESTRICT-END #BASICAUTH START {auth_conf} #BASICAUTH END #SUB_FILTER START {sub_filter} #SUB_FILTER END #GZIP START {gzip_conf} #GZIP END #GLOBAL-CACHE START {proxy_cache} #GLOBAL-CACHE END #WEBSOCKET-SUPPORT START {websocket_support} #WEBSOCKET-SUPPORT END #PROXY-CONF-START {proxy_conf} #PROXY-CONF-END #SERVER-BLOCK START {server_block} #SERVER-BLOCK END #禁止访问的文件或目录 location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {{ return 404; }} #一键申请SSL证书验证目录相关设置 location /.well-known{{ allow all; }} #禁止在证书验证目录放入敏感文件 if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {{ return 403; }} #LOG START {server_log} {monitor_conf} #LOG END }}''' self._template_proxy_conf = '''location ^~ {proxy_path} {{ {ip_limit} {basic_auth} proxy_pass {proxy_pass}; proxy_set_header Host {proxy_host}; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header REMOTE-HOST $remote_addr; {SNI} {timeout_conf} {websocket_support} {custom_conf} {proxy_cache} {gzip} {sub_filter} {server_log} }}''' def structure_proxy_conf(self, get): ''' @name @author wzz <2024/4/19 下午4:29> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' sni_conf = "" if get.proxy_pass.startswith("https://"): sni_conf = "proxy_ssl_server_name on;" get.proxy_conf = self._template_proxy_conf.format( ip_limit="", gzip="", proxy_cache="", sub_filter="", server_log="", basic_auth="", proxy_pass=get.proxy_pass, proxy_host=get.proxy_host, proxy_path=get.proxy_path, SNI=sni_conf, custom_conf="", timeout_conf=get.proxy_timeout, websocket_support=self._init_proxy_conf["websocket"]["websocket_conf"], ) get.proxy_info = { "proxy_type": get.proxy_type, "proxy_path": get.proxy_path, "proxy_pass": get.proxy_pass, "proxy_host": get.proxy_host, "ip_limit": { "ip_black": [], "ip_white": [], }, "basic_auth": {}, "proxy_cache": { "cache_status": False, "cache_zone": get.site_name.replace(".", "_") + "_cache", "static_cache": "", "expires": "1d", "cache_conf": "", }, "gzip": { "gzip_status": False, "gzip_min_length": "1k", "gzip_comp_level": "6", "gzip_types": "text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js", "gzip_conf": "gzip on;\n gzip_min_length 10k;\n gzip_buffers 4 16k;\n gzip_http_version 1.1;\n gzip_comp_level 2;\n gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;\n gzip_vary on;\n gzip_proxied expired no-cache no-store private auth;\n gzip_disable \"MSIE [1-6]\.\";", }, "sub_filter": { "sub_filter_str": [], }, "websocket": { "websocket_status": True, "websocket_conf": "proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection $connection_upgrade;", }, "proxy_log": { "log_type": "off", "log_conf": get.server_log, }, "timeout": { "proxy_connect_timeout": "60", "proxy_send_timeout": "600", "proxy_read_timeout": "600", "timeout_conf": "proxy_connect_timeout 60s;\n proxy_send_timeout 600s;\n proxy_read_timeout 600s;", }, "custom_conf": "", "proxy_conf": get.proxy_conf, "remark": "", "template_proxy_conf": self._template_proxy_conf, } # 2024/4/18 上午10:53 构造反向代理的配置文件 def structure_nginx(self, get): ''' @name 构造反向代理的配置文件 @author wzz <2024/4/18 上午10:54> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.err_age_404 = get.get("err_age_404", "#error_page 404 /404.html;") get.err_age_502 = get.get("err_age_502", "#error_page 502 /502.html;") get.proxy_info = get.get("proxy_info", "") get.server_log = get.get( "server_log", self._init_proxy_conf["proxy_log"]["log_conf"].format( log_path=public.get_logs_path(), site_name=get.site_name ) ) get.remark = get.get("remark", "") get.server_block = get.get("server_block", "") get.websocket_status = get.get("websocket_status", True) get.proxy_timeout = "proxy_connect_timeout 60s;\n proxy_send_timeout 600s;\n proxy_read_timeout 600s;" self.structure_proxy_conf(get) is_subs = public.ExecShell("nginx -V 2>&1|grep 'ngx_http_substitutions_filter' -o")[0] self._init_proxy_conf["subs_filter"] = True if is_subs != "" else False self._init_proxy_conf["site_name"] = get.site_name self._init_proxy_conf["domain_list"] = get.domain_list self._init_proxy_conf["site_port"] = get.port_list self._init_proxy_conf["site_path"] = get.site_path self._init_proxy_conf["err_age_404"] = get.err_age_404 self._init_proxy_conf["err_age_502"] = get.err_age_502 self._init_proxy_conf["proxy_log"]["log_conf"] = get.server_log self._init_proxy_conf["remark"] = get.remark self._init_proxy_conf["http_block"] = "" self._init_proxy_conf["proxy_info"].append(get.proxy_info) self._init_proxy_conf["proxy_cache"]["cache_zone"] = get.site_name.replace(".", "_") + "_cache" # 2024/4/18 上午10:35 写入Nginx配置文件 def write_nginx_conf(self, get): ''' @name 写入Nginx配置文件 @author wzz <2024/4/18 上午10:36> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' # 这里可能会报错 self.structure_nginx(get) if len(get.port_list) > 1: ipv4_port_conf = "" ipv6_port_conf = "" for p in get.port_list: ipv4_port_conf += self._init_proxy_conf["ipv4_port_conf"].format(listen_port=p) + "\n " ipv6_port_conf += self._init_proxy_conf["ipv6_port_conf"].format(listen_port=p) + "\n " else: ipv4_port_conf = self._init_proxy_conf["ipv4_port_conf"].format(listen_port=get.port_list[0]) ipv6_port_conf = self._init_proxy_conf["ipv6_port_conf"].format(listen_port=get.port_list[0]) port_conf = ipv4_port_conf + "\n" + ipv6_port_conf # 2024/6/4 下午4:20 兼容新版监控报表的配置 monitor_conf = "" if os.path.exists("/www/server/panel/plugin/monitor/monitor_main.py"): monitor_conf = '''#Monitor-Config-Start 网站监控报表日志发送配置 access_log syslog:server=unix:/tmp/bt-monitor.sock,nohostname,tag={pid}__access monitor; error_log syslog:server=unix:/tmp/bt-monitor.sock,nohostname,tag={pid}__error; #Monitor-Config-End'''.format(pid=get.pid) conf = self._template_conf.format( http_block=get.http_block, server_block="", port_conf=port_conf, ssl_start_msg=public.getMsg('NGINX_CONF_MSG1'), err_page_msg=public.getMsg('NGINX_CONF_MSG2'), php_info_start=public.getMsg('NGINX_CONF_MSG3'), rewrite_start_msg=public.getMsg('NGINX_CONF_MSG4'), log_path=public.get_logs_path(), domains=' '.join(get.domain_list) if len(get.domain_list) > 1 else get.site_name, site_name=get.site_name, ssl_info="#error_page 404/404.html;", err_age_404=get.err_age_404, err_age_502=get.err_age_502, ip_limit_conf="", auth_conf="", sub_filter="", gzip_conf="", redirect_conf="", security_conf="", proxy_conf=get.proxy_conf, server_log=get.server_log, site_path=get.site_path, proxy_cache="", websocket_support=self._init_proxy_conf["websocket"]["websocket_conf"], monitor_conf=monitor_conf, ) # 写配置文件 well_known_path = "{}/vhost/nginx/well-known".format(public.get_panel_path()) if not os.path.exists(well_known_path): os.makedirs(well_known_path, 0o600) public.writeFile("{}/{}.conf".format(well_known_path, get.site_name), "") get.filename = public.get_setup_path() + '/panel/vhost/nginx/' + get.site_name + '.conf' return public.writeFile(get.filename, conf) # 2024/4/25 上午11:11 检查nginx是否支持http3 def check_http3_support(self): ''' @name 检查nginx是否支持http3 @author wzz <2024/4/25 上午11:13> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' return public.ExecShell("nginx -V 2>&1| grep 'http_v3_module' -o")[0] # 2024/7/29 下午3:00 添加反代前置配置检测 def check_before_create(self, get): ''' @name 添加反代前置配置检测 @author wzz <2024/7/29 下午3:01> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' from mod.base.web_conf import util webserver = util.webserver() if webserver != "nginx" or webserver is None: return public.returnResult(status=False, msg="Only Nginx is supported. Please install Nginx before using it!") from panelSite import panelSite site_obj = panelSite() site_obj.check_default() wc_err = public.checkWebConfig() if not wc_err: return public.returnResult( status=False, msg='ERROR: There is an error in the configuration file, please exclude it before operation

' + wc_err.replace("\n", '
') + '
' ) get.site_name = util.to_puny_code(get.domain_list[0].strip().split(":")[0]).strip().lower() public.check_domain_cloud(get.site_name) if get.site_name.find('*') != -1: return public.return_message(-1, 0, public.lang("The primary domain name cannot be a generic DNS")) main_domain = get.site_name opid = public.M('domain').where("name=? and port=?", (main_domain, int(get.site_port))).getField('pid') if opid: if public.M('sites').where('id=?', (opid,)).count(): return public.returnResult(status=False, msg='Website [{}] already exists, please do not add again!'.format(main_domain)) public.M('domain').where('pid=?', (opid,)).delete() if public.M('binding').where('domain=?', (main_domain,)).count(): return public.returnResult(status=False, msg='Website [{}] already exists, please do not add again!'.format(main_domain)) sql = public.M('sites') if sql.where("name=?", (get.site_name,)).count(): if public.is_ipv4(get.site_name): get.site_name = get.site_name + "_" + str(get.site_port) else: return public.returnResult(status=False, msg='Website [{}] already exists, please do not add again!'.format(main_domain)) return public.returnResult(True) # 2024/7/29 下午2:39 创建必须目录 def create_must_dir(self, get): ''' @name @author wzz <2024/7/29 下午2:40> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' if not os.path.exists(self._site_path): public.ExecShell('mkdir -p {}'.format(self._site_path)) public.ExecShell('chown -R www:www {}'.format(self._site_path)) public.ExecShell('chmod -R 755 {}'.format(self._site_path)) if not os.path.exists(get.site_path): public.ExecShell('mkdir -p {}'.format(get.site_path)) public.ExecShell('chown -R www:www {}'.format(get.site_path)) public.ExecShell('chmod -R 755 {}'.format(get.site_path)) if not os.path.exists(get.site_path + "/proxy_cache_dir"): public.ExecShell('mkdir -p {}'.format(get.site_path + "/proxy_cache_dir")) public.ExecShell('chown -R www:www {}'.format(get.site_path + "/proxy_cache_dir")) public.ExecShell('chmod -R 755 {}'.format(get.site_path + "/proxy_cache_dir")) # 2024/7/29 上午11:46 创建完成后置检测 def check_after_create(self, get): ''' @name 创建完成后置检测 @author wzz <2024/7/29 上午11:47> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' wc_err = public.checkWebConfig() if not wc_err: public.ExecShell("rm -f {}".format(self._site_proxy_conf_path)) public.ExecShell("rm -rf {}".format(get.filename)) public.M('sites').where('id=?', (get.pid,)).delete() public.M('domain').where('pid=?', (get.pid,)).delete() public.M('dk_sites').where('id=?', (get.dk_pid,)).delete() public.M('dk_domain').where('pid=?', (get.dk_pid,)).delete() return public.returnResult( status=False, msg='ERROR: There is an error in the configuration file, please exclude it before operation

' + wc_err.replace("\n", '
') + '
' ) if type(wc_err) != bool and "test failed" in wc_err: public.ExecShell("rm -f {}".format(self._site_proxy_conf_path)) public.ExecShell("rm -rf {}".format(get.filename)) public.M('sites').where('id=?', (get.pid,)).delete() public.M('domain').where('pid=?', (get.pid,)).delete() public.M('dk_sites').where('id=?', (get.dk_pid,)).delete() public.M('dk_domain').where('pid=?', (get.dk_pid,)).delete() return public.returnResult( status=False, msg='ERROR: There is an error in the configuration file, please exclude it before operation

' + wc_err.replace("\n", '
') + '
' ) return public.returnResult(True) # 2024/7/29 上午11:31 插入sites表 def insert_sites(self, get): ''' @name 插入sites或dk_sites表 @author wzz <2024/7/29 上午11:32> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' # 2024/4/18 上午10:22 写入数据库 if get.add_type == "all" or get.add_type == "sites": addtime = public.getDate() pdata = { 'name': get.site_name, 'rname': get.site_name, 'path': "/www/wwwroot/" + get.site_name, 'ps': get.remark, 'status': 1, 'type_id': 0, 'project_type': 'proxy', 'project_config': json.dumps(self._init_proxy_conf), 'addtime': addtime, } try: get.pid = public.M('sites').insert(pdata) if get.pid.find("error: table sites has no column named rname") != -1: create_table_str = public.M('sqlite_master').where('type=? AND name=?', ('table', 'sites')).getField('sql') if create_table_str and 'rname' not in create_table_str: public.M('sites').execute('ALTER TABLE `sites` ADD COLUMN `rname` VARCHAR default "";') # 重新添加 get.pid = public.M('sites').insert(pdata) # public.print_log("添加反向代理---{}".format(get.pid)) except: public.print_log(public.get_error_info()) if not get.pid: return public.return_message(-1, 0, public.lang("The addition failed and the data could not be inserted into the site database")) for domain in get.domain_list: public.M('domain').insert({ 'name': domain, 'pid': str(get.pid), 'port': '80' if ":" not in domain else domain.split(":")[1], 'addtime': addtime, }) return public.return_message(0, 0, '') # 2024/7/29 上午11:46 插入dk_sites表 def insert_dk_sites(self, get): ''' @name 插入sites或dk_sites表 @author wzz <2024/7/29 上午11:32> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' # 2024/4/18 上午10:22 写入数据库 if get.add_type == "all" or get.add_type == "dk_sites": opid = public.M('dk_domain').where("name=? and port=?", (get.site_name, int(get.site_port))).getField('pid') if opid: public.M('dk_sites').where('id=?', (opid,)).delete() public.M('dk_domain').where('pid=?', (opid,)).delete() addtime = public.getDate() pdata = { 'name': get.site_name, 'rname': get.site_name, 'path': "/www/wwwroot/" + get.site_name, 'ps': get.remark, 'status': 1, 'type_id': 111, 'project_type': 'dk_proxy', 'project_config': json.dumps(self._init_proxy_conf), 'addtime': addtime, 'container_id': get.container_id, 'container_name': get.container_name, 'container_port': get.container_port, } get.dk_pid = public.M('dk_sites').insert(pdata) if not get.dk_pid: return public.return_message(-1, 0, public.lang("The add failed and the data could not be inserted into the docker website database")) for domain in get.domain_list: public.M('dk_domain').insert({ 'name': domain, 'pid': str(get.dk_pid), 'port': '80' if ":" not in domain else domain.split(":")[1], 'addtime': addtime, }) return public.returnResult(True) # 2024/4/18 上午9:26 创建反向代理 def create(self, get): ''' @name 创建反向代理 @author wzz <2024/4/18 上午9:27> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' # 2024/4/18 上午9:45 参数处理 get.domains = get.get("domains", "") get.proxy_path = get.get("proxy_path", "/") get.proxy_pass = get.get("proxy_pass", "") get.proxy_host = get.get("proxy_host", "$http_host") get.remark = get.get("remark", "") get.proxy_type = get.get("proxy_type", "http") get.add_type = get.get("add_type", "all") get.pid = get.get("pid", None) get.dk_pid = get.get("dk_pid", None) # 2024/4/18 上午9:45 参数校验 if not get.domains: return public.returnResult(status=False, msg="Domain name cannot be empty. At least one domain must be entered!") if not get.proxy_pass: return public.returnResult(status=False, msg="Proxy target cannot be empty!") if get.remark != "": get.remark = public.xssencode2(get.remark) if get.proxy_type == "unix": if not get.proxy_pass.startswith("/"): return public.returnResult(status=False, msg="The Unix file path must start with '/', such as /tmp/flask_app.sock!") if not get.proxy_pass.endswith(".sock"): return public.returnResult(status=False, msg="The Unix file must end with '.sock', such as /tmp/flask_app.sock!") if not os.path.exists(get.proxy_pass): return public.returnResult(status=False, msg="The proxy target does not exist!") get.proxy_pass = "http://unix:{}".format(get.proxy_pass) elif get.proxy_type == "http": if not get.proxy_pass.startswith("http://") and not get.proxy_pass.startswith("https://"): return public.returnResult(status=False, msg="The proxy target must start with 'http://' or 'https://'.") get.domain_list = get.domains.split("\n") get.site_port = get.domain_list[0].strip().split(":")[1] if ":" in get.domain_list[0] else "80" get.port_list = [get.site_port] cbres = self.check_before_create(get) if not cbres["status"]: return cbres get.site_path = "/www/wwwroot/" + get.site_name if not public.checkPort(get.site_port): return public.returnResult(status=False, msg='Port 【{}】 is invalid!'.format(get.site_port)) if len(get.domain_list) > 1: for domain in get.domain_list[1:]: if not ":" in domain.strip(): continue d_port = domain.strip().split(":")[1] if not public.checkPort(d_port): return public.returnResult(status=False, msg='Port 【{}】 is invalid!'.format(d_port)) if not d_port in get.port_list: get.port_list.append(d_port) # 2024/4/18 上午10:21 添加端口到系统防火墙 from firewallModelV2.comModel import main as comModel firewall_com = comModel() get.port = get.site_port firewall_com.set_port_rule(get) # 2024/4/18 上午10:46 写入网站配置文件 get.http_block = "proxy_cache_path /www/wwwroot/{site_name}/proxy_cache_dir levels=1:2 keys_zone={cache_name}_cache:20m inactive=1d max_size=5g;".format( site_name=get.site_name, cache_name=get.site_name.replace(".", "_") ) # 2024/6/4 下午4:30 写nginx配置文件 self.write_nginx_conf(get) # 2024/4/18 上午10:22 写入数据库 ires = self.insert_sites(get) # self.insert_dk_sites(get) if ires["status"] == -1: return ires self._site_path = self._proxy_config_path + '/' + get.site_name self.create_must_dir(get) self._site_proxy_conf_path = '{}/{}.json'.format(self._site_path, get.site_name) public.writeFile(self._site_proxy_conf_path, json.dumps(self._init_proxy_conf)) cres = self.check_after_create(get) if not cres["status"]: return cres public.WriteLog('TYPE_SITE', 'SITE_ADD_SUCCESS', (get.site_name,)) public.set_module_logs('dk_site_proxy', 'create', 1) public.serviceReload() return public.returnResult(msg="Docker reverse proxy added successfully") def read_json_conf(self, get): ''' @name @author wzz <2024/4/18 下午9:53> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) try: proxy_json_conf = json.loads(public.readFile(conf_path)) except Exception as e: import traceback print(traceback.format_exc()) proxy_json_conf = {} return proxy_json_conf # 2024/4/18 下午9:58 设置全局日志 def set_global_log(self, get): ''' @name @author wzz <2024/4/18 下午9:58> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name cannot be empty") get.log_type = get.get("log_type", "default") if not get.log_type in ["default", "file", "rsyslog", "off"]: return public.returnResult(status=False, msg="Invalid log type! Please specify one of: default/file/rsyslog/off.") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="Failed to read the configuration file! Please delete the site and re-add it.") get.proxy_json_conf["proxy_log"]["log_type"] = get.log_type if get.log_type == "file": get.log_path = get.get("log_path", "") if get.log_path == "": return public.returnResult(status=False, msg="Log path cannot be empty!") if not get.log_path.startswith("/"): return public.returnResult(status=False, msg="Log path must start with '/'") get.proxy_json_conf["proxy_log"]["log_path"] = get.log_path get.proxy_json_conf["proxy_log"]["log_conf"] = self._init_proxy_conf["proxy_log"]["log_conf"].format( log_path=get.log_path, site_name=get.site_name ) elif get.log_type == "rsyslog": get.log_path = get.get("log_path", "") if get.log_path == "": return public.returnResult(status=False, msg="Log path cannot be empty!") site_name = get.site_name.replace(".", "_") get.proxy_json_conf["proxy_log"]["log_conf"] = ( "\n access_log syslog:server={server_host},nohostname,tag=nginx_{site_name}_access;" "\n error_log syslog:server={server_host},nohostname,tag=nginx_{site_name}_error;" .format( server_host=get.log_path, site_name=site_name )) get.proxy_json_conf["proxy_log"]["rsyslog_host"] = get.log_path elif get.log_type == "off": get.proxy_json_conf["proxy_log"]["log_conf"] = "\n access_log off;\n error_log off;" else: get.proxy_json_conf["proxy_log"]["log_conf"] = " " + self._init_proxy_conf["proxy_log"][ "log_conf"].format( log_path=public.get_logs_path(), site_name=get.site_name ) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) public.serviceReload() return public.returnResult(msg="Settings successfully!") # 2024/4/18 下午10:21 设置basic_auth def set_dir_auth(self, get): ''' @name 设置basic_auth @param auth_type: add/edit auth_path: /api username: admin password: admin @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.name = get.get("name", "") if get.name == "": return public.returnResult(status=False, msg="name不能为空!") get.auth_path = get.get("auth_path", "") if get.auth_path == "": return public.returnResult(status=False, msg="auth_path不能为空!") if not get.auth_path.startswith("/"): return public.returnResult(status=False, msg="auth_path必须以/开头!") get.username = get.get("username", "") get.password = get.get("password", "") if get.username == "" or get.password == "": return public.returnResult(status=False, msg="用户名和密码不能为空!") get.password = public.hasPwd(get.password) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if len(get.proxy_json_conf["basic_auth"]) == 0: return public.returnResult(status=False, msg="【{}】不存在http认证中,请先添加!".format(get.auth_path)) for i in range(len(get.proxy_json_conf["basic_auth"])): if get.proxy_json_conf["basic_auth"][i]["auth_path"] == get.auth_path: if get.proxy_json_conf["basic_auth"][i]["auth_name"] == get.name: get.proxy_json_conf["basic_auth"][i]["username"] = get.username get.proxy_json_conf["basic_auth"][i]["password"] = get.password break auth_file = "/www/server/pass/{site_name}/{name}.htpasswd".format(site_name=get.site_name, name=get.name) public.writeFile(auth_file, "{}:{}".format(get.username, get.password)) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) public.serviceReload() return public.returnResult(msg="设置成功!") # 2024/4/22 下午4:17 添加指定网站的basic_auth def add_dir_auth(self, get): ''' @name 添加指定网站的basic_auth @author wzz <2024/4/22 下午4:17> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.auth_path = get.get("auth_path", "") if get.auth_path == "": return public.returnResult(status=False, msg="auth_path不能为空!") if not get.auth_path.startswith("/"): return public.returnResult(status=False, msg="auth_path必须以/开头!") get.name = get.get("name", "") if get.name == "": return public.returnResult(status=False, msg="name不能为空!") get.username = get.get("username", "") if get.username == "": return public.returnResult(status=False, msg="username不能为空!") get.password = get.get("password", "") if get.password == "": return public.returnResult(status=False, msg="password不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") auth_file = "/www/server/pass/{site_name}/{name}.htpasswd".format(site_name=get.site_name, name=get.name) auth_conf = { "auth_status": True, "auth_path": get.auth_path, "auth_name": get.name, "username": get.username, "password": public.hasPwd(get.password), "auth_file": auth_file, } if len(get.proxy_json_conf["basic_auth"]) != 0: for i in range(len(get.proxy_json_conf["basic_auth"])): if get.proxy_json_conf["basic_auth"][i]["auth_path"] == get.auth_path: return public.returnResult(status=False, msg="【{}】已存在http认证中,无法重复添加!".format(get.auth_path)) if not os.path.exists("/www/server/pass"): public.ExecShell("mkdir -p /www/server/pass") if not os.path.exists("/www/server/pass/{}".format(get.site_name)): public.ExecShell("mkdir -p /www/server/pass/{}".format(get.site_name)) public.writeFile(auth_file, "{}:{}".format(get.username, public.hasPwd(get.password))) get.proxy_json_conf["basic_auth"].append(auth_conf) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="Successfully added!") # 2024/4/23 上午9:34 删除指定网站的basic_auth def del_dir_auth(self, get): ''' @name 删除指定网站的basic_auth @author wzz <2024/4/23 上午9:35> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.auth_path = get.get("auth_path", "") if get.auth_path == "": return public.returnResult(status=False, msg="auth_path不能为空!") get.name = get.get("name", "") if get.name == "": return public.returnResult(status=False, msg="name不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") auth_file = "/www/server/pass/{site_name}/{name}.htpasswd".format(site_name=get.site_name, name=get.name) panel_port = public.readFile('/www/server/panel/data/port.pl') proxy_list = self.get_proxy_list(get) if proxy_list["data"][0]["proxy_pass"] == "https://127.0.0.1:{}".format(panel_port.strip()) and get.auth_path.strip() == "/": return public.return_message(-1, 0, public.lang("[{}] is the reverse generation of the panel, and the http authentication of [/] cannot be deleted!",get.site_name)) if len(get.proxy_json_conf["basic_auth"]) != 0: for i in range(len(get.proxy_json_conf["basic_auth"])): if get.proxy_json_conf["basic_auth"][i]["auth_path"] == get.auth_path: if get.proxy_json_conf["basic_auth"][i]["auth_name"] == get.name: get.proxy_json_conf["basic_auth"].pop(i) break public.ExecShell("rm -f {}".format(auth_file)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/18 下午10:26 设置全局gzip def set_global_gzip(self, get): ''' @name 设置全局gzip @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.gzip_status = get.get("gzip_status/d", 999) if get.gzip_status == 999: return public.returnResult(status=False, msg="gzip_status不能为空,请传number 1或0!") get.gzip_min_length = get.get("gzip_min_length", "10k") get.gzip_comp_level = get.get("gzip_comp_level", "6") if get.gzip_min_length[0] == "0" or get.gzip_min_length.startswith("-"): return public.returnResult(status=False, msg="gzip_min_length参数不合法,请输入大于0的数字!") if get.gzip_comp_level == "0" or get.gzip_comp_level.startswith("-"): return public.returnResult(status=False, msg="gzip_comp_level参数不合法,请输入大于0的数字!") get.gzip_types = get.get( "gzip_types", "text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js" ) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["gzip"]["gzip_status"] = True if get.gzip_status == 1 else False if get.proxy_json_conf["gzip"]["gzip_status"]: get.proxy_json_conf["gzip"]["gzip_status"] = True get.proxy_json_conf["gzip"]["gzip_min_length"] = get.gzip_min_length get.proxy_json_conf["gzip"]["gzip_comp_level"] = get.gzip_comp_level get.proxy_json_conf["gzip"]["gzip_types"] = get.gzip_types get.gzip_conf = ("gzip on;" "\n gzip_min_length {gzip_min_length};" "\n gzip_buffers 4 16k;" "\n gzip_http_version 1.1;" "\n gzip_comp_level {gzip_comp_level};" "\n gzip_types {gzip_types};" "\n gzip_vary on;" "\n gzip_proxied expired no-cache no-store private auth;" "\n gzip_disable \"MSIE [1-6]\.\";").format( gzip_min_length=get.gzip_min_length, gzip_comp_level=get.gzip_comp_level, gzip_types=get.gzip_types ) get.proxy_json_conf["gzip"]["gzip_conf"] = get.gzip_conf else: get.proxy_json_conf["gzip"]["gzip_conf"] = "" update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/18 下午10:27 设置全局缓存 def set_global_cache(self, get): ''' @name 设置全局缓存 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.cache_status = get.get("cache_status/d", 999) if get.cache_status == 999: return public.returnResult(status=False, msg="cache_status不能为空,请传number 1或0!") get.expires = get.get("expires", "1d") if get.expires[0] == "0" or get.expires.startswith("-"): return public.returnResult(status=False, msg="expires参数不合法,请输入大于0的数字!") expires = "expires {}".format(get.expires) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") static_cache = ("\n location ~ .*\\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$" "\n {{" "\n {expires};" "\n error_log /dev/null;" "\n access_log /dev/null;" "\n }}").format( expires=expires, ) cache_conf = ("\n proxy_cache {cache_zone};" "\n proxy_cache_key $host$uri$is_args$args;" "\n proxy_ignore_headers Set-Cookie Cache-Control expires X-Accel-Expires;" "\n proxy_cache_valid 200 304 301 302 {expires};" "\n proxy_cache_valid 404 1m;" "{static_cache}").format( cache_zone=get.proxy_json_conf["proxy_cache"]["cache_zone"], expires=get.expires, static_cache=get.proxy_json_conf["proxy_cache"]["static_cache"] if get.proxy_json_conf["proxy_cache"][ "static_cache"] != "" else static_cache ) get.proxy_json_conf["proxy_cache"]["cache_status"] = True if get.cache_status == 1 else False if get.proxy_json_conf["proxy_cache"]["cache_status"]: get.proxy_json_conf["proxy_cache"]["cache_status"] = True get.proxy_json_conf["proxy_cache"]["expires"] = get.expires get.proxy_json_conf["proxy_cache"]["cache_conf"] = cache_conf else: get.proxy_json_conf["proxy_cache"]["cache_status"] = False get.proxy_json_conf["proxy_cache"]["cache_conf"] = static_cache update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/18 下午10:43 设置全局websocket支持 def set_global_websocket(self, get): ''' @name @author wzz <2024/4/19 下午2:37> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.websocket_status = get.get("websocket_status/d", 999) if get.websocket_status == 999: return public.returnResult(status=False, msg="websocket_status不能为空,请传number 1或0!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if get.websocket_status == 1: get.proxy_json_conf["websocket"]["websocket_status"] = True else: get.proxy_json_conf["websocket"]["websocket_status"] = False update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/19 下午2:54 设置备注 def set_remak(self, get): ''' @name 设置备注 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.remark = get.get("remark", "") get.table = "sites" get.ps = get.remark get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from data import data data_obj = data() result = data_obj.setPs(get) if not result["status"]: public.returnResult(status=False, msg=result["msg"]) get.proxy_json_conf["remark"] = get.remark self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return public.returnResult(msg=result["msg"]) # 2024/4/19 下午2:59 添加反向代理 def add_proxy(self, get): ''' @name @author wzz <2024/4/19 下午3:00> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.proxy_pass = get.get("proxy_pass", "") if get.proxy_pass == "": return public.returnResult(status=False, msg="proxy_pass不能为空!") get.proxy_host = get.get("proxy_host", "$http_host") get.proxy_type = get.get("proxy_type", "http") get.remark = get.get("remark", "") get.proxy_timeout = "proxy_connect_timeout 60s;\n proxy_send_timeout 600s;\n proxy_read_timeout 600s;" if get.remark != "": get.remark = public.xssencode2(get.remark) if get.proxy_type == "unix": if not get.proxy_pass.startswith("/"): return public.returnResult(status=False, msg="unix文件路径必须以/开头,如/tmp/flask_app.sock!") if not get.proxy_pass.endswith(".sock"): return public.returnResult(status=False, msg="unix文件必须以.sock结尾,如/tmp/flask_app.sock!") if not os.path.exists(get.proxy_pass): return public.returnResult(status=False, msg="代理目标不存在!") get.proxy_pass = "http://unix:{}".format(get.proxy_pass) elif get.proxy_type == "http": if not get.proxy_pass.startswith("http://") and not get.proxy_pass.startswith("https://"): return public.returnResult(status=False, msg="代理目标必须以http://或https://开头!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") # 2024/4/19 下午3:45 检测是否已经存在proxy_path,有的话就返回错误 for proxy_info in get.proxy_json_conf["proxy_info"]: if proxy_info["proxy_path"] == get.proxy_path: return public.returnResult(status=False, msg="【{}】已存在反向代理中,无法重复添加!".format(get.proxy_path)) if len(get.proxy_json_conf["basic_auth"]) != 0: for i in range(len(get.proxy_json_conf["basic_auth"])): if get.proxy_json_conf["basic_auth"][i]["auth_path"] == get.proxy_path: return public.returnResult(status=False, msg="【{}】已存在basicauth中,请先删除再添加反向代理!".format( get.proxy_path)) sni_conf = "" if get.proxy_pass.startswith("https://"): sni_conf = "proxy_ssl_server_name on;" get.proxy_conf = self._template_proxy_conf.format( ip_limit="", gzip="", proxy_cache="", sub_filter="", server_log="", basic_auth="", proxy_pass=get.proxy_pass, proxy_host=get.proxy_host, proxy_path=get.proxy_path, SNI=sni_conf, custom_conf="", timeout_conf=get.proxy_timeout, websocket_support=get.proxy_json_conf["websocket"]["websocket_conf"], ) get.proxy_json_conf["proxy_info"].append({ "proxy_type": get.proxy_type, "proxy_path": get.proxy_path, "proxy_pass": get.proxy_pass, "proxy_host": get.proxy_host, "ip_limit": { "ip_black": [], "ip_white": [], }, "basic_auth": {}, "proxy_cache": { "cache_status": False, "cache_zone": "", "static_cache": "", "expires": "1d", "cache_conf": "", }, "gzip": { "gzip_status": False, "gzip_min_length": "10k", "gzip_comp_level": "6", "gzip_types": "text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js", "gzip_conf": "gzip on;\n gzip_min_length 10k;\n gzip_buffers 4 16k;\n gzip_http_version 1.1;\n gzip_comp_level 2;\n gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;\n gzip_vary on;\n gzip_proxied expired no-cache no-store private auth;\n gzip_disable \"MSIE [1-6]\.\";", }, "sub_filter": { "sub_filter_str": [], }, "websocket": { "websocket_status": True, "websocket_conf": "proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection $connection_upgrade;", }, "proxy_log": { "log_type": "off", "log_conf": "", }, "timeout": { "proxy_connect_timeout": "60", "proxy_send_timeout": "600", "proxy_read_timeout": "600", "timeout_conf": "proxy_connect_timeout 60s;\n proxy_send_timeout 600s;\n proxy_read_timeout 600s;", }, "custom_conf": "", "proxy_conf": get.proxy_conf, "remark": get.remark, "template_proxy_conf": self._template_proxy_conf, }) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) public.set_module_logs('dk_site_proxy', 'add_proxy', 1) return public.returnResult(msg="Successfully added!") # 2024/4/19 下午9:45 删除指定站点 def delete(self, get): ''' @name @author wzz <2024/4/19 下午9:45> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") get.id = get.get("id", "") get.remove_path = get.get("remove_path/d", 0) if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.reload = get.get("reload/d", 1) if public.M('sites').where('id=?', (get.id,)).count() < 1: return public.returnResult(status=False, msg='指定站点不存在!') site_file = public.get_setup_path() + '/panel/vhost/nginx/' + get.site_name + '.conf' if os.path.exists(site_file): public.ExecShell('rm -f {}'.format(site_file)) redirect_dir = public.get_setup_path() + '/panel/vhost/nginx/redirect/' + get.site_name if os.path.exists(redirect_dir): public.ExecShell('rm -rf {}'.format(redirect_dir)) logs_file = public.get_logs_path() + '/{}*'.format(get.site_name) public.ExecShell('rm -f {}'.format(logs_file)) self._site_proxy_conf_path = "{path}/{site_name}".format( path=self._proxy_config_path, site_name=get.site_name ) public.ExecShell('rm -f {}'.format(self._site_proxy_conf_path)) if get.remove_path == 1: public.ExecShell('rm -rf /www/wwwroot/{}'.format(get.site_name)) if get.reload == 1: public.serviceReload() # 从数据库删除 public.M('sites').where("id=?", (get.id,)).delete() public.M('domain').where("pid=?", (get.id,)).delete() public.WriteLog('TYPE_SITE', "SITE_DEL_SUCCESS", (get.site_name,)) return public.returnResult(msg="反向代理项目删除成功!") # 2024/5/28 上午9:50 批量删除站点 def batch_delete(self, get): ''' @name 批量删除站点 @author wzz <2024/5/28 上午9:51> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_list = get.get("site_list", []) get.remove_path = get.get("remove_path/d", 0) get.reload = get.get("reload/d", 0) try: site_list = json.loads(get.site_list) except: return public.return_message(-1, 0, public.lang("Please pass in a list of websites that need to be deleted!")) acc_list = [] for site in site_list: args = public.dict_obj() args.site_name = site["site_name"] args.remove_path = get.remove_path args.reload = get.reload args.id = site["id"] de_result = self.delete(args) if not de_result["status"]: acc_list.append({"site_name": site["site_name"], "status": False}) continue acc_list.append({"site_name": site["site_name"], "status": True}) public.serviceReload() return public.return_message(0, 0, acc_list) # return public.returnResult(True, msg="Batch deletion of sites successful!", data=acc_list) # 2024/4/26 下午4:57 获取证书的部署状态 def get_site_ssl_info(self, siteName): ''' @name 获取证书的部署状态 @author wzz <2024/4/26 下午4:58> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' try: import time import re s_file = 'vhost/nginx/{}.conf'.format(siteName) is_apache = False if not os.path.exists(s_file): s_file = 'vhost/apache/{}.conf'.format(siteName) is_apache = True if not os.path.exists(s_file): return -1 s_conf = public.readFile(s_file) if not s_conf: return -1 ssl_file = None if is_apache: if s_conf.find('SSLCertificateFile') == -1: return -1 s_tmp = re.findall(r"SSLCertificateFile\s+(.+\.pem)", s_conf) if not s_tmp: return -1 ssl_file = s_tmp[0] else: if s_conf.find('ssl_certificate') == -1: return -1 s_tmp = re.findall(r"ssl_certificate\s+(.+\.pem);", s_conf) if not s_tmp: return -1 ssl_file = s_tmp[0] ssl_info = public.get_cert_data(ssl_file) if not ssl_info: return -1 ssl_info['endtime'] = int( int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")) - time.time()) / 86400) return ssl_info except: return -1 # 2024/4/19 下午10:05 获取所有project_type为proxy的站点,需要做分页配置,按照添加时间排序 def get_list(self, get): ''' @name 获取所有project_type为proxy的站点,需要做分页配置,按照添加时间排序 @param get: @return: ''' get.p = get.get("p/d", 1) get.limit = get.get("limit/d", 10) get.search = get.get("search", "") where = "project_type=?" if get.search != "": where += " and name like ?" param = ("proxy", "%{}%".format(get.search)) else: param = ("proxy",) import db sql = db.Sql() count = sql.table('sites').where(where, param).count() import page page = page.Page() data = {} info = {} info['count'] = count info['row'] = get.limit info['p'] = 1 if hasattr(get, 'p'): info['p'] = int(get['p']) if info['p'] < 1: info['p'] = 1 try: from flask import request info['uri'] = public.url_encode(request.full_path) except: info['uri'] = '' info['return_js'] = '' data['where'] = where data['page'] = page.GetPage(info) sql.table('sites').where(where, param) sql.field('id,name,path,status,ps,addtime,edate,rname').order('id desc') sql.limit(str(page.SHIFT) + ',' + str(page.ROW)) data['data'] = sql.select() try: path = '/www/server/btwaf/site.json' waf_res = json.loads(public.readFile(path)) except: waf_res = {} for site in data['data']: get.site_name = site["name"] project_config = self.read_json_conf(get) site["healthy"] = 1 site["waf"] = {} if not project_config: site["healthy"] = 0 site["conf_path"] = "" site["ssl"] = -1 site["proxy_pass"] = "" continue site["conf_path"] = public.get_setup_path() + '/panel/vhost/nginx/' + get.site_name + '.conf' site["ssl"] = self.get_site_ssl_info(get.site_name) site["proxy_pass"] = project_config["proxy_info"][0]["proxy_pass"] if waf_res: for waf in waf_res: if "open" in waf_res[waf]: site["waf"] = {"status": True} return public.returnResult(data=data) # 2024/4/19 下午11:46 给指定网站添加域名 def add_domain(self, get): ''' @name @author wzz <2024/4/19 下午11:46> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.domains = get.get("domains", "") if get.domains == "": return public.returnResult(status=False, msg="domains不能为空!") if "," in get.domains: return public.returnResult(status=False, msg="域名不能包含逗号!") get.domain_list = get.domains.strip().replace(' ', '').split("\n") public.check_domain_cloud(get.domain_list[0]) get.domain = ",".join(get.domain_list) get.webname = get.site_name port_list = [] for domain in get.domain_list: if not ":" in domain.strip(): continue d_port = domain.strip().split(":")[1] if not public.checkPort(d_port): return public.returnResult(status=False, msg='域名【{}】的端口号不合法!'.format(domain)) port_list.append(d_port) # 2024/4/20 上午12:02 更新json文件 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["domain_list"].extend(get.domain_list) get.proxy_json_conf["site_port"].extend(port_list) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) from panelSite import panelSite result = panelSite().AddDomain(get) if "status" in result and not result["status"]: return public.returnResult(status=False, msg=result["msg"]) return public.returnResult(status=True, data=result["domains"]) # 2024/4/20 上午12:07 删除指定网站的某个域名 def del_domain(self, get): ''' @name @author wzz <2024/4/20 上午12:07> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.port = get.get("port", "") if get.port == "": return public.returnResult(status=False, msg="port不能为空!") get.domain = get.get("domain", "") if get.domain == "": return public.returnResult(status=False, msg="domain不能为空!") get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.webname = get.site_name # 2024/4/20 上午12:02 更新json文件 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if len(get.proxy_json_conf["domain_list"]) == 1: return public.returnResult(status=False, msg="至少保留一个域名!") while get.domain in get.proxy_json_conf["domain_list"]: get.proxy_json_conf["domain_list"].remove(get.domain) if get.port in get.proxy_json_conf["site_port"] and len(get.proxy_json_conf["site_port"]) != 1: while get.port in get.proxy_json_conf["site_port"]: get.proxy_json_conf["site_port"].remove(get.port) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) from panelSite import panelSite result = panelSite().DelDomain(get) return public.returnResult(status=result["status"], msg=result["msg"]) # 2024/4/20 上午12:20 批量删除指定网站域名 def batch_del_domain(self, get): ''' @name 批量删除指定网站域名 @param get: @return: ''' get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.domains = get.get("domains", "") if get.domains == "": return public.returnResult(status=False, msg="domains不能为空!") get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.webname = get.site_name # 2024/4/20 上午12:02 更新json文件 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") # if len(get.proxy_json_conf["domain_list"]) == 1: # return public.returnResult(status=False, msg="至少保留一个域名!") get.domain_list = get.domains.strip().replace(' ', '').split("\n") # if len(get.domain_list) == len(get.proxy_json_conf["domain_list"]): # return public.returnResult(status=False, msg="至少保留一个域名!") for domain in get.domain_list: while domain in get.proxy_json_conf["domain_list"]: get.proxy_json_conf["domain_list"].remove(domain) if ":" in domain: port = domain.split(":")[1] if len(get.proxy_json_conf["site_port"]) == 1: continue while port in get.proxy_json_conf["site_port"]: get.proxy_json_conf["site_port"].remove(port) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) from panelSite import panelSite res_domains = [] for domain in get.domain_list: get.domain = domain get.port = "80" if ":" in domain: get.port = domain.split(":")[1] result = panelSite().DelDomain(get) res_domains.append({"name": domain, "status": result["status"], "msg": result["msg"]}) public.serviceReload() return public.returnResult(status=True, data=res_domains) # 2024/4/20 上午9:17 获取域名列表和https端口 def get_domain_list(self, get): ''' @name 获取域名列表和https端口 @param get: @return: ''' get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.siteName = get.webname = get.site_name get.table = "domain" get.list = True get.search = get.id # 2024/4/20 上午12:02 更新json文件 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") result_data = {} import data dataObject = data.data() result_data["domain_list"] = dataObject.getData(get) if get.proxy_json_conf["ssl_info"]["ssl_status"]: if not "https_port" in get.proxy_json_conf or get.proxy_json_conf["https_port"] == "": get.proxy_json_conf["https_port"] = "443" result_data["https_port"] = get.proxy_json_conf["https_port"] else: result_data["https_port"] = "未开启HTTPS" # 2024/4/20 上午9:21 domain_list里面没有的域名健康状态显示为0 for domain in result_data["domain_list"]: domain["healthy"] = 1 if domain["name"] not in get.proxy_json_conf["domain_list"]: domain["healthy"] = 0 public.set_module_logs('dk_site_proxy', 'get_domain_list', 1) return public.returnResult(data=result_data) # 2024/4/20 下午2:22 获取配置文件 def get_config(self, get): ''' @name @author wzz <2024/4/20 下午2:22> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") site_conf = public.readFile(public.get_setup_path() + '/panel/vhost/nginx/' + get.site_name + '.conf') ssl_conf = get.proxy_json_conf["ssl_info"]["ssl_conf"].format( site_name=get.site_name, ) if get.proxy_json_conf["ssl_info"]["force_https"]: ssl_conf = get.proxy_json_conf["ssl_info"]["force_ssl_conf"].format( site_name=get.site_name, force_conf=get.proxy_json_conf["ssl_info"]["force_ssl_conf"], ) if "如果反代网站访问异常且这里已经配置了内容,请优先排查此处的配置是否正确" in get.proxy_json_conf["http_block"]: http_block = get.proxy_json_conf["http_block"] else: http_block = '''# 可设置server|upstream|map等所有http字段,如: # server {{ # listen 10086; # server_name ... # }} # upstream stream_ser {{ # server back_test.com; # server ... # }} {default_describe} {http_block}'''.format( default_describe=self._init_proxy_conf["default_describe"], http_block=get.proxy_json_conf["http_block"], ) if "如果反代网站访问异常且这里已经配置了内容,请优先排查此处的配置是否正确" in get.proxy_json_conf["server_block"]: server_block = get.proxy_json_conf["server_block"] else: server_block = '''# 可设置server|location等所有server字段,如: # location /web {{ # try_files $uri $uri/ /index.php$is_args$args; # }} # error_page 404 /diy_404.html; {default_describe} {server_block}'''.format( default_describe=self._init_proxy_conf["default_describe"], server_block=get.proxy_json_conf["server_block"], ) data = { "site_conf": site_conf if not site_conf is False else "", "http_block": http_block, "server_block": server_block, "ssl_conf": ssl_conf, } return public.returnResult(data=data) # 2024/4/20 下午2:38 保存配置文件 def save_config(self, get): ''' @name 保存配置文件 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.conf_type = get.get("conf_type", "") if get.conf_type == "": return public.returnResult(status=False, msg="conf_type不能为空!") get.body = get.get("body", "") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if get.conf_type == "http_block": get.proxy_json_conf["http_block"] = get.body else: get.proxy_json_conf["server_block"] = get.body update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) public.serviceReload() return public.returnResult(msg="保存成功!") # 2024/4/20 下午3:11 根据proxy_json_conf,填入self._template_conf,然后生成nginx配置,保存到指定网站的conf文件中 def generate_config(self, get): """ @name 根据proxy_json_conf,填入self._template_conf,然后生成nginx配置,保存到指定网站的conf文件中 @param get: @return: """ # 2024/4/20 下午3:36 构造ip黑白名单 ip_black = "" ip_white = "" for ip in get.proxy_json_conf["ip_limit"]["ip_black"]: ip_black += ("deny {};\n ").format(ip) for ip in get.proxy_json_conf["ip_limit"]["ip_white"]: ip_white += ("allow {};\n ").format(ip) if ip_white != "": ip_white += "deny all;" ip_limit_conf = ip_black + "\n " + ip_white proxy_conf = "" ignore_path = [] if len(get.proxy_json_conf["proxy_info"]) != 0: for info in get.proxy_json_conf["proxy_info"]: proxy_auth_conf = "" if info["basic_auth"]: proxy_auth_conf = ("auth_basic \"Authorization\";" "\n auth_basic_user_file {auth_file};").format( auth_path=info["basic_auth"]["auth_path"], auth_file=info["basic_auth"]["auth_file"], ) if len(get.proxy_json_conf["basic_auth"]) != 0: for auth in get.proxy_json_conf["basic_auth"]: if info["proxy_path"] == auth["auth_path"]: ignore_path.append(auth["auth_path"]) proxy_auth_conf = ("auth_basic \"Authorization\";" "\n auth_basic_user_file {auth_file};").format( auth_path=auth["auth_path"], auth_file=auth["auth_file"], ) break p_ip_black = "" p_ip_white = "" for ip in info["ip_limit"]["ip_black"]: p_ip_black += ("deny {};\n ").format(ip) for ip in info["ip_limit"]["ip_white"]: p_ip_white += ("allow {};\n ").format(ip) if p_ip_white != "": p_ip_white += "deny all;" p_ip_limit_conf = p_ip_black + "\n " + p_ip_white if p_ip_black == "" and p_ip_white == "": p_ip_limit_conf = "" p_gzip_conf = "" if info["gzip"]["gzip_status"]: p_gzip_conf = info["gzip"]["gzip_conf"] p_sub_filter = "" if len(info["sub_filter"]["sub_filter_str"]) != 0: p_sub_filter = 'proxy_set_header Accept-Encoding \"\";' if not "subs_filter" in get.proxy_json_conf: get.proxy_json_conf["subs_filter"] = public.ExecShell("nginx -V 2>&1|grep 'ngx_http_substitutions_filter' -o")[0] != "" if not get.proxy_json_conf["subs_filter"]: for filter in info["sub_filter"]["sub_filter_str"]: p_sub_filter += "\n sub_filter {oldstr} {newstr};".format( oldstr=filter["oldstr"] if filter["oldstr"] != "" else "\"\"", newstr=filter["newstr"] if filter["newstr"] != "" else "\"\"", ) p_sub_filter += "\n sub_filter_once off;" else: for filter in info["sub_filter"]["sub_filter_str"]: p_sub_filter += "\n subs_filter {oldstr} {newstr} {sub_type};".format( oldstr=filter["oldstr"] if filter["oldstr"] != "" else "\"\"", newstr=filter["newstr"] if filter["newstr"] != "" else "\"\"", sub_type=filter["sub_type"] if "sub_type" in filter and filter["sub_type"] != "" else "\"\"", ) p_websocket_support = "" if info["websocket"]["websocket_status"]: p_websocket_support = info["websocket"]["websocket_conf"] timeout_conf = ("proxy_connect_timeout {proxy_connect_timeout};" "\n proxy_send_timeout {proxy_send_timeout};" "\n proxy_read_timeout {proxy_read_timeout};").format( proxy_connect_timeout=info["timeout"]["proxy_connect_timeout"].replace("s", "") + "s", proxy_send_timeout=info["timeout"]["proxy_send_timeout"].replace("s", "") + "s", proxy_read_timeout=info["timeout"]["proxy_read_timeout"].replace("s", "") + "s", ) sni_conf = "" if info["proxy_pass"].startswith("https://"): sni_conf = "proxy_ssl_server_name on;" tmp_conf = info["template_proxy_conf"].format( basic_auth=proxy_auth_conf, ip_limit=p_ip_limit_conf, gzip=p_gzip_conf, sub_filter=p_sub_filter, proxy_cache=info["proxy_cache"]["cache_conf"], server_log="", proxy_pass=info["proxy_pass"], proxy_host=info["proxy_host"], proxy_path=info["proxy_path"], custom_conf=info["custom_conf"], timeout_conf=timeout_conf, websocket_support=p_websocket_support, SNI=sni_conf, ) info["proxy_conf"] = tmp_conf proxy_conf += tmp_conf + "\n " # 2024/4/20 下午3:37 构造basicauth auth_conf = "" if len(get.proxy_json_conf["basic_auth"]) != 0: for auth in get.proxy_json_conf["basic_auth"]: if auth["auth_path"] not in ignore_path: tmp_conf = ("location ^~ {auth_path} {{" "\n auth_basic \"Authorization\";" "\n auth_basic_user_file {auth_file};" "\n }}").format(auth_path=auth["auth_path"], auth_file=auth["auth_file"]) auth_conf += tmp_conf + "\n " websocket_support = "" if get.proxy_json_conf["websocket"]["websocket_status"]: websocket_support = get.proxy_json_conf["websocket"]["websocket_conf"] gzip_conf = "" if get.proxy_json_conf["gzip"]["gzip_status"]: gzip_conf = get.proxy_json_conf["gzip"]["gzip_conf"] ssl_conf = "#error_page 404/404.html;" # listen_port = " ".join(get.proxy_json_conf["site_port"]) # listen_ipv6 = "\n listen [::]:{};".format(" ".join(get.proxy_json_conf["site_port"])) # port_conf = get.proxy_json_conf["port_conf"].format( # listen_port=listen_port, # listen_ipv6=listen_ipv6, # ) if not "https_port" in get.proxy_json_conf or get.proxy_json_conf["https_port"] == "": get.proxy_json_conf["https_port"] = "443" if not "ipv4_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv4_port_conf"] = "listen {listen_port};" if not "ipv6_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv6_port_conf"] = "listen [::]:{listen_port};" if not "ipv4_http3_ssl_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv4_http3_ssl_port_conf"] = "{ipv4_port_conf}\n listen {https_port} quic;\n listen {https_port} ssl;" if not "ipv6_http3_ssl_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv6_http3_ssl_port_conf"] = "{ipv6_port_conf}\n listen [::]:{https_port} quic;\n listen [::]:{https_port} ssl ;" if not "ipv4_ssl_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv4_ssl_port_conf"] = "{ipv4_port_conf}\n listen {https_port} ssl http2 ;" if not "ipv6_ssl_port_conf" in get.proxy_json_conf: get.proxy_json_conf["ipv6_ssl_port_conf"] = "{ipv6_port_conf}\n listen [::]:{https_port} ssl http2 ;" ipv4_port_conf = "" ipv6_port_conf = "" for p in get.proxy_json_conf["site_port"]: ipv4_port_conf += get.proxy_json_conf["ipv4_port_conf"].format( listen_port=p, ) + "\n " ipv6_port_conf += get.proxy_json_conf["ipv6_port_conf"].format( listen_port=p, ) + "\n " if get.proxy_json_conf["ssl_info"]["ssl_status"]: if public.ExecShell("nginx -V 2>&1| grep 'http_v3_module' -o")[0] != "": ipv4_http3_ssl_port_conf = get.proxy_json_conf["ipv4_http3_ssl_port_conf"].format( ipv4_port_conf=ipv4_port_conf, https_port=get.proxy_json_conf["https_port"], ) + "\n " ipv6_http3_ssl_port_conf = get.proxy_json_conf["ipv6_http3_ssl_port_conf"].format( ipv6_port_conf=ipv6_port_conf, https_port=get.proxy_json_conf["https_port"], ) + "\n " port_conf = ipv4_http3_ssl_port_conf + ipv6_http3_ssl_port_conf + "\n http2 on;" else: ipv4_ssl_port_conf = get.proxy_json_conf["ipv4_ssl_port_conf"].format( ipv4_port_conf=ipv4_port_conf, https_port=get.proxy_json_conf["https_port"], ) + "\n " ipv6_ssl_port_conf = get.proxy_json_conf["ipv6_ssl_port_conf"].format( ipv6_port_conf=ipv6_port_conf, https_port=get.proxy_json_conf["https_port"], ) + "\n " port_conf = ipv4_ssl_port_conf + ipv6_ssl_port_conf ssl_conf = get.proxy_json_conf["ssl_info"]["ssl_conf"].format(site_name=get.site_name) if get.proxy_json_conf["ssl_info"]["force_https"]: ssl_conf = get.proxy_json_conf["ssl_info"]["force_ssl_conf"].format( site_name=get.site_name, force_conf=get.proxy_json_conf["ssl_info"]["force_conf"] ) else: port_conf = ipv4_port_conf + "\n" + ipv6_port_conf redirect_conf = "" if get.proxy_json_conf["redirect"]["redirect_status"]: redirect_conf = get.proxy_json_conf["redirect"]["redirect_conf"].format(site_name=get.site_name) security_conf = "" if get.proxy_json_conf["security"]["security_status"]: domains = get.proxy_json_conf["security"]["domains"] if not get.proxy_json_conf["security"][ "http_status"] else "none blocked " + get.proxy_json_conf["security"]["domains"] security_conf = get.proxy_json_conf["security"]["security_conf"].format( static_resource=get.proxy_json_conf["security"]["static_resource"], expires="30d", domains=domains.replace(",", " "), return_resource=get.proxy_json_conf["security"]["return_resource"], ) default_cache = get.proxy_json_conf["default_cache"].format( site_name=get.site_name, cache_name=get.site_name.replace(".", "_") ) get.http_block = default_cache + "\n" + get.proxy_json_conf["http_block"] # 2024/6/4 下午4:20 兼容新版监控报表的配置 monitor_conf = "" if (os.path.exists("/www/server/panel/plugin/monitor/monitor_main.py") and os.path.exists("/www/server/monitor/config/sites.json")): try: sites_data = json.loads(public.readFile("/www/server/monitor/config/sites.json")) if sites_data[get.site_name]["open"]: id = public.M('domain').where("name=?", (get.site_name,)).getField('id') monitor_conf = '''#Monitor-Config-Start 网站监控报表日志发送配置 access_log syslog:server=unix:/tmp/bt-monitor.sock,nohostname,tag={sid}__access monitor; error_log syslog:server=unix:/tmp/bt-monitor.sock,nohostname,tag={sid}__error; #Monitor-Config-End'''.format(sid=id) except: pass get.site_conf = self._template_conf.format( http_block=get.http_block, server_block=get.proxy_json_conf["server_block"], port_conf=port_conf, ssl_start_msg=public.getMsg('NGINX_CONF_MSG1'), err_page_msg=public.getMsg('NGINX_CONF_MSG2'), php_info_start=public.getMsg('NGINX_CONF_MSG3'), rewrite_start_msg=public.getMsg('NGINX_CONF_MSG4'), domains=' '.join(get.proxy_json_conf["domain_list"]) if len( get.proxy_json_conf["domain_list"]) > 1 else get.site_name, site_name=get.site_name, ssl_info=ssl_conf, err_age_404=get.proxy_json_conf["err_age_404"], err_age_502=get.proxy_json_conf["err_age_502"], ip_limit_conf=ip_limit_conf, auth_conf=auth_conf, sub_filter="", gzip_conf=gzip_conf, security_conf=security_conf, redirect_conf=redirect_conf, proxy_conf=proxy_conf, proxy_cache=get.proxy_json_conf["proxy_cache"]["cache_conf"], server_log=get.proxy_json_conf["proxy_log"]["log_conf"], site_path=get.proxy_json_conf["site_path"], websocket_support=websocket_support, monitor_conf=monitor_conf, ) # 2024/4/21 下午10:46 设置商业ssl证书 def set_cert(self, get): ''' @name @author wzz <2024/4/21 下午10:46> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.oid = get.get("oid", "") if get.oid == "": return public.returnResult(status=False, msg="oid不能为空!") get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.siteName = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelSSL import panelSSL ssl_obj = panelSSL() set_result = ssl_obj.set_cert(get) if set_result["status"] == False: return set_result get.proxy_json_conf["ssl_info"]["ssl_status"] = True get.proxy_json_conf["https_port"] = "443" self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return set_result # 2024/4/21 下午11:03 关闭SSl证书 def close_ssl(self, get): ''' @name @author wzz <2024/4/21 下午11:04> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.siteName = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelSite import panelSite result = panelSite().CloseSSLConf(get) if not result["status"]: return result get.proxy_json_conf["ssl_info"]["ssl_status"] = False get.proxy_json_conf["https_port"] = "443" self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/21 下午11:10 保存指定网站的SSL证书 def set_ssl(self, get): ''' @name 保存指定网站的SSL证书 @author wzz <2024/4/21 下午11:12> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.key = get.get("key", "") if get.key == "": return public.returnResult(status=False, msg="key不能为空!") get.csr = get.get("csr", "") if get.csr == "": return public.returnResult(status=False, msg="csr不能为空!") get.siteName = get.site_name get.type = -1 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelSite import panelSite result = panelSite().SetSSL(get) if not result["status"]: # return public.returnResult(status=False, msg=result["msg"]) return result get.proxy_json_conf["ssl_info"]["ssl_status"] = True get.proxy_json_conf["https_port"] = "443" self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/21 下午11:29 部署测试证书 def set_test_cert(self, get): ''' @name @author wzz <2024/4/21 下午11:30> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.partnerOrderId = get.get("partnerOrderId", "") if get.partnerOrderId == "": return public.returnResult(status=False, msg="partnerOrderId不能为空!") get.siteName = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelSSL import panelSSL ssl_obj = panelSSL() set_result = ssl_obj.GetSSLInfo(get) if set_result["status"] == False: return set_result get.proxy_json_conf["ssl_info"]["ssl_status"] = True get.proxy_json_conf["https_port"] = "443" self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return set_result # 2024/4/21 下午11:33 申请let' encrypt证书 def apply_cert_api(self, get): ''' @name @author wzz <2024/4/21 下午11:34> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.domains = get.get("domains", "") if get.domains == "": return public.returnResult(status=False, msg="domains不能为空!") get.auth_type = get.get("auth_type", "") if get.auth_type == "": return public.returnResult(status=False, msg="auth_type不能为空!") get.auth_to = get.get("auth_to", "") if get.auth_to == "": return public.returnResult(status=False, msg="auth_to不能为空!") get.auto_wildcard = get.get("auto_wildcard", "") if get.auto_wildcard == "": return public.returnResult(status=False, msg="auto_wildcard不能为空!") get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.siteName = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from acme_v2 import acme_v2 acme = acme_v2() result = acme.apply_cert_api(get) if not result["status"]: return result get.proxy_json_conf["ssl_info"]["ssl_status"] = True get.proxy_json_conf["https_port"] = "443" self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/21 下午11:36 验证let' encrypt dns def apply_dns_auth(self, get): ''' @name @author wzz <2024/4/21 下午11:36> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.index = get.get("index", "") if get.index == "": return public.returnResult(status=False, msg="index不能为空!") from acme_v2 import acme_v2 acme = acme_v2() return acme.apply_dns_auth(get) # 2024/4/21 下午11:44 设置证书夹里面的证书 def SetBatchCertToSite(self, get): ''' @name @author wzz <2024/4/21 下午11:44> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.BatchInfo = get.get("BatchInfo", "") if get.BatchInfo == "": return public.returnResult(status=False, msg="BatchInfo不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelSSL import panelSSL ssl_obj = panelSSL() set_result = ssl_obj.SetBatchCertToSite(get) if not "successList" in set_result: return set_result for re in set_result["successList"]: if re["status"] and re["siteName"] == get.site_name: get.proxy_json_conf["ssl_info"]["ssl_status"] = True break self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return set_result # 2024/4/22 上午9:43 设置强制https def set_force_https(self, get): ''' @name 设置强制https @param get: site_name: 网站名 force_https: 1/0 @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.force_https = get.get("force_https/d", 999) if get.force_https == 999: return public.returnResult(status=False, msg="force_https不能为空!") get.siteName = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["ssl_info"]["force_https"] = True if get.force_https == 1 else False from panelSite import panelSite if get.force_https == 1: result = panelSite().HttpToHttps(get) else: result = panelSite().CloseToHttps(get) if not result["status"]: return result self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/22 上午10:27 创建重定向 def CreateRedirect(self, get): ''' @name @author wzz <2024/4/22 上午10:27> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.domainorpath = get.get("domainorpath", "") if get.domainorpath == "": return public.returnResult(status=False, msg="domainorpath不能为空!") get.redirecttype = get.get("redirecttype", "") if get.redirecttype == "": return public.returnResult(status=False, msg="redirecttype不能为空!") get.redirectpath = get.get("redirectpath", "") if get.domainorpath == "path" and get.redirectpath == "": return public.returnResult(status=False, msg="redirectpath不能为空!") get.tourl = get.get("tourl", "") if get.tourl == "": return public.returnResult(status=False, msg="tourl不能为空!") get.redirectdomain = get.get("redirectdomain", "") if get.domainorpath == "domain" and get.redirectdomain == "": return public.returnResult(status=False, msg="redirectdomain不能为空!") get.redirectname = get.get("redirectname", "") if get.redirectname == "": return public.returnResult(status=False, msg="redirectname不能为空!") get.sitename = get.site_name get.type = 1 get.holdpath = 1 get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["redirect"]["redirect_status"] = True from panelRedirect import panelRedirect result = panelRedirect().CreateRedirect(get) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/22 上午10:45 删除指定网站的某个重定向规则 def DeleteRedirect(self, get): ''' @name 删除指定网站的某个重定向规则 @author wzz <2024/4/22 上午10:45> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.redirectname = get.get("redirectname", "") if get.redirectname == "": return public.returnResult(status=False, msg="redirectname不能为空!") get.sitename = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") from panelRedirect import panelRedirect redirect_list = panelRedirect().GetRedirectList(get) if len(redirect_list) == 0: get.proxy_json_conf["redirect"]["redirect_status"] = False self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return panelRedirect().DeleteRedirect(get) # 2024/4/23 上午10:38 编辑指定网站的某个重定向规则 def ModifyRedirect(self, get): ''' @name 编辑指定网站的某个重定向规则 @author wzz <2024/4/23 上午10:38> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.domainorpath = get.get("domainorpath", "") if get.domainorpath == "": return public.returnResult(status=False, msg="domainorpath不能为空!") get.redirecttype = get.get("redirecttype", "") if get.redirecttype == "": return public.returnResult(status=False, msg="redirecttype不能为空!") get.redirectpath = get.get("redirectpath", "") if get.domainorpath == "path" and get.redirectpath == "": return public.returnResult(status=False, msg="redirectpath不能为空!") get.tourl = get.get("tourl", "") if get.tourl == "": return public.returnResult(status=False, msg="tourl不能为空!") get.redirectdomain = get.get("redirectdomain", "") if get.domainorpath == "domain" and get.redirectdomain == "": return public.returnResult(status=False, msg="redirectdomain不能为空!") get.redirectname = get.get("redirectname", "") if get.redirectname == "": return public.returnResult(status=False, msg="redirectname不能为空!") get.sitename = get.site_name get.type = get.get("type/d", 1) get.holdpath = get.get("holdpath/d", 1) from panelRedirect import panelRedirect return panelRedirect().ModifyRedirect(get) # 2024/4/26 下午3:32 获取指定网站指定重定向规则的信息 def GetRedirectFile(self, get): ''' @name 获取指定网站指定重定向规则的信息 @author wzz <2024/4/26 下午3:32> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.path = get.get("path", "") if get.path == "": return public.returnResult(status=False, msg="path不能为空!") if not os.path.exists(get.path): return public.returnResult(status=False, msg="重定向已停止或配置文件目录不存在!") import files f = files.files() return f.GetFileBody(get) # 2024/4/22 上午11:12 设置防盗链 def SetSecurity(self, get): ''' @name 设置防盗链 @author wzz <2024/4/22 上午11:12> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.fix = get.get("fix", "") if get.fix == "": return public.returnResult(status=False, msg="fix不能为空!") get.domains = get.get("domains", "") if get.domains == "": return public.returnResult(status=False, msg="domains不能为空!") get.return_rule = get.get("return_rule", "") if get.return_rule == "": return public.returnResult(status=False, msg="return_rule不能为空!") get.http_status = get.get("http_status", "") if get.http_status == "": return public.returnResult(status=False, msg="http_status不能为空!") get.status = get.get("status", "") if get.status == "": return public.returnResult(status=False, msg="status不能为空!") get.id = get.get("id", "") if get.id == "": return public.returnResult(status=False, msg="id不能为空!") get.name = get.site_name get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["security"]["security_status"] = True if get.status == "true" else False get.proxy_json_conf["security"]["static_resource"] = get.fix get.proxy_json_conf["security"]["domains"] = get.domains get.proxy_json_conf["security"]["return_resource"] = get.return_rule get.proxy_json_conf["security"]["http_status"] = True if get.http_status else False from panelSite import panelSite result = panelSite().SetSecurity(get) if not result["status"]: return result self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return result # 2024/4/23 下午3:07 添加全局IP黑白名单 def add_ip_limit(self, get): ''' @name 添加全局IP黑白名单 @author wzz <2024/4/23 下午3:08> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ips = get.get("ips", "") if get.ips == "": return public.returnResult(status=False, msg="ips不能为空,请输入IP,一行一个!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.ips = get.ips.split("\n") for ip in get.ips: if ip not in get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)]: get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)].append(ip) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/23 下午3:12 删除全局IP黑白名单 def del_ip_limit(self, get): ''' @name 删除全局IP黑白名单 @author wzz <2024/4/23 下午3:12> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ip = get.get("ip", "") if get.ip == "": return public.returnResult(status=False, msg="ip不能为空,请输入IP!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if get.ip in get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)]: get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)].remove(get.ip) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/23 下午3:13 批量删除全局IP黑白名单 def batch_del_ip_limit(self, get): ''' @name 批量删除全局IP黑白名单 @author wzz <2024/4/23 下午3:14> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white", "all"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ips = get.get("ips", "") if get.ips == "": return public.returnResult(status=False, msg="ips不能为空,请输入IP,一行一个!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.ips = get.ips.split("\n") for ip in get.ips: if get.ip_type == "all": if ip in get.proxy_json_conf["ip_limit"]["ip_black"]: get.proxy_json_conf["ip_limit"]["ip_black"].remove(ip) if ip in get.proxy_json_conf["ip_limit"]["ip_white"]: get.proxy_json_conf["ip_limit"]["ip_white"].remove(ip) else: if ip in get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)]: get.proxy_json_conf["ip_limit"]["ip_{}".format(get.ip_type)].remove(ip) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/22 下午9:01 获取指定网站的方向代理列表 def get_proxy_list(self, get): ''' @name @author wzz <2024/4/22 下午9:02> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if len(get.proxy_json_conf["proxy_info"]) == 0: return public.returnResult(status=False, msg="没有代理信息!") subs_filter = get.proxy_json_conf["subs_filter"] if "subs_filter" in get.proxy_json_conf else public.ExecShell("nginx -V 2>&1|grep 'ngx_http_substitutions_filter' -o")[0] != "" if get.proxy_path != "": for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["global_websocket"] = get.proxy_json_conf["websocket"]["websocket_status"] info["subs_filter"] = subs_filter if "http://unix:" in info["proxy_pass"]: info["proxy_pass"] = info["proxy_pass"].replace("http://unix:", "") return public.returnResult(data=info) else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) public.set_module_logs('dk_site_proxy', 'get_proxy_list', 1) return public.returnResult(data=get.proxy_json_conf["proxy_info"]) # 2024/4/23 上午11:16 获取指定网站的所有配置信息 def get_global_conf(self, get): ''' @name 获取指定网站的所有配置信息 @author wzz <2024/4/23 上午11:16> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") return public.returnResult(data=get.proxy_json_conf) # 2024/4/22 下午9:04 设置指定网站指定URL的反向代理 def set_url_proxy(self, get): ''' @name @author wzz <2024/4/22 下午9:04> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.proxy_host = get.get("proxy_host", "") if get.proxy_host == "": return public.returnResult(status=False, msg="proxy_host不能为空!") get.proxy_pass = get.get("proxy_pass", "") if get.proxy_pass == "": return public.returnResult(status=False, msg="proxy_pass不能为空!") get.proxy_type = get.get("proxy_type", "") if get.proxy_type == "": return public.returnResult(status=False, msg="proxy_type不能为空!") get.proxy_connect_timeout = get.get("proxy_connect_timeout", "60s") get.proxy_send_timeout = get.get("proxy_send_timeout", "600s") get.proxy_read_timeout = get.get("proxy_read_timeout", "600s") get.remark = get.get("remark", "") if get.remark != "": get.remark = public.xssencode2(get.remark) if get.proxy_type == "unix": if not get.proxy_pass.startswith("http://unix:"): if not get.proxy_pass.startswith("/"): return public.returnResult(status=False, msg="unix文件路径必须以/或http://unix:开头,如/tmp/flask_app.sock!") if not get.proxy_pass.endswith(".sock"): return public.returnResult(status=False, msg="unix文件必须以.sock结尾,如/tmp/flask_app.sock!") if not os.path.exists(get.proxy_pass): return public.returnResult(status=False, msg="代理目标不存在!") get.proxy_pass = "http://unix:" + get.proxy_pass elif get.proxy_type == "http": if not get.proxy_pass.startswith("http://") and not get.proxy_pass.startswith("https://"): return public.returnResult(status=False, msg="代理目标必须以http://或https://开头!") get.websocket = get.get("websocket/d", 1) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if get.proxy_json_conf["websocket"]["websocket_status"] and get.websocket != 1: return public.returnResult(status=False, msg="全局websocket为开启状态,不允许单独关闭此URL的websocket支持!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["proxy_host"] = get.proxy_host info["proxy_pass"] = get.proxy_pass info["proxy_type"] = get.proxy_type info["timeout"]["proxy_connect_timeout"] = get.proxy_connect_timeout.replace("s", "") info["timeout"]["proxy_send_timeout"] = get.proxy_send_timeout.replace("s", "") info["timeout"]["proxy_read_timeout"] = get.proxy_read_timeout.replace("s", "") info["websocket"]["websocket_status"] = True if get.websocket == 1 else False info["remark"] = get.remark break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/22 下午9:34 删除指定网站指定URL的反向代理 def del_url_proxy(self, get): ''' @name 删除指定网站指定URL的反向代理 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: get.proxy_json_conf["proxy_info"].remove(info) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/22 下午9:36 设置指定网站指定URL反向代理的备注 def set_url_remark(self, get): ''' @name 设置指定网站指定URL反向代理的备注 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.remark = get.get("remark", "") if get.remark != "": get.remark = public.xssencode2(get.remark) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["remark"] = get.remark break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/22 下午9:40 添加指定网站指定URL的内容替换 def add_sub_filter(self, get): ''' @name 添加指定网站指定URL的内容替换 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.oldstr = get.get("oldstr", "") get.newstr = get.get("newstr", "") if get.oldstr == "" and get.newstr == "": return public.returnResult(status=False, msg="oldstr和newstr不能同时为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.sub_type = get.get("sub_type", "g") if get.sub_type == "": get.sub_type = "g" import re if not re.match(r'^[ior]+$|^g(?!.*o)|^o(?!.*g)$', get.sub_type): return public.returnResult(status=False, msg="get.sub_type 只能包含 'g'、'i'、'o' 或 'r' 中的字母组合,并且 'g' 和 'o' 不能同时存在!") is_subs = public.ExecShell("nginx -V 2>&1|grep 'ngx_http_substitutions_filter' -o")[0] if not is_subs and re.search(u'[\u4e00-\u9fa5]', get.oldstr + get.newstr): return public.returnResult(status=False, msg="您输入的内容包含中文,检测到当前nginx版本不支持,请尝试重新安装nginx 1.20以上的版本后重试!") if get.sub_type != "g" and not is_subs: return public.returnResult(status=False, msg="检测到当前nginx版本仅支持默认替换类型,请尝试重新安装nginx 1.20以上的版本后重试!") if not "g" in get.sub_type and not "o" in get.sub_type: get.sub_type = "g" + get.sub_type for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: for sub in info["sub_filter"]["sub_filter_str"]: if get.oldstr == sub["oldstr"]: return public.returnResult(status=False, msg="替换前内容:【{}】的配置信息已存在,请勿重复添加!".format( get.oldstr)) info["sub_filter"]["sub_filter_str"].append( { "sub_type": get.sub_type, "oldstr": get.oldstr, "newstr": get.newstr } ) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/22 下午10:00 删除指定网站指定URL的内容替换 def del_sub_filter(self, get): ''' @name 删除指定网站指定URL的内容替换 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.oldstr = get.get("oldstr", "") get.newstr = get.get("newstr", "") if get.oldstr == "" and get.newstr == "": return public.returnResult(status=False, msg="oldstr和newstr不能同时为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: for sub in info["sub_filter"]["sub_filter_str"]: if get.oldstr == sub["oldstr"]: info["sub_filter"]["sub_filter_str"].remove(sub) break else: return public.returnResult(status=False, msg="未找到替换前内容:【{}】的配置信息!".format(get.oldstr)) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/22 下午10:03 设置指定网站指定URL的内容压缩 def set_url_gzip(self, get): ''' @name 设置指定网站指定URL的内容压缩 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.gzip_status = get.get("gzip_status/d", 999) if get.gzip_status == 999: return public.returnResult(status=False, msg="gzip_status不能为空,请传number 1或0!") get.gzip_min_length = get.get("gzip_min_length", "10k") get.gzip_comp_level = get.get("gzip_comp_level", "6") if get.gzip_min_length[0] == "0" or get.gzip_min_length.startswith("-"): return public.returnResult(status=False, msg="gzip_min_length参数不合法,请输入大于0的数字!") if get.gzip_comp_level == "0" or get.gzip_comp_level.startswith("-"): return public.returnResult(status=False, msg="gzip_comp_level参数不合法,请输入大于0的数字!") get.gzip_types = get.get( "gzip_types", "text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js" ) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["gzip"]["gzip_status"] = True if get.gzip_status == 1 else False if get.gzip_status == 1: info["gzip"]["gzip_types"] = get.gzip_types info["gzip"]["gzip_min_length"] = get.gzip_min_length info["gzip"]["gzip_comp_level"] = get.gzip_comp_level info["gzip"]["gzip_conf"] = ("gzip on;" "\n gzip_min_length {gzip_min_length};" "\n gzip_buffers 4 16k;" "\n gzip_http_version 1.1;" "\n gzip_comp_level {gzip_comp_level};" "\n gzip_types {gzip_types};" "\n gzip_vary on;" "\n gzip_proxied expired no-cache no-store private auth;" "\n gzip_disable \"MSIE [1-6]\.\";").format( gzip_min_length=get.gzip_min_length, gzip_comp_level=get.gzip_comp_level, gzip_types=get.gzip_types, ) else: info["gzip"]["gzip_conf"] = "" break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/22 下午10:15 添加指定网站指定URL的IP黑白名单 def add_url_ip_limit(self, get): ''' @name 添加指定网站指定URL的IP黑白名单 @author wzz <2024/4/22 下午10:16> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ips = get.get("ips", "") if get.ips == "": return public.returnResult(status=False, msg="ips不能为空,请输入IP,一行一个!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.ips = get.ips.split("\n") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: for ip in get.ips: if get.ip_type == "black": if not ip in info["ip_limit"]["ip_black"]: info["ip_limit"]["ip_black"].append(ip) else: if not ip in info["ip_limit"]["ip_white"]: info["ip_limit"]["ip_white"].append(ip) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/22 下午10:21 删除指定网站指定URL的IP黑白名单 def del_url_ip_limit(self, get): ''' @name 删除指定网站指定URL的IP黑白名单 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ip = get.get("ip", "") if get.ip == "": return public.returnResult(status=False, msg="ip不能为空,请输入IP!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: if get.ip in info["ip_limit"]["ip_{ip_type}".format(ip_type=get.ip_type)]: info["ip_limit"]["ip_{ip_type}".format(ip_type=get.ip_type)].remove(get.ip) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/24 上午11:21 批量删除指定网站指定URL的IP黑白名单 def batch_del_url_ip_limit(self, get): ''' @name 批量删除指定网站指定URL的IP黑白名单 @author wzz <2024/4/24 上午11:22> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.ip_type = get.get("ip_type", "black") if get.ip_type not in ["black", "white", "all"]: return public.returnResult(status=False, msg="ip_type参数错误,必须传black或white!") get.ips = get.get("ips", "") if get.ips == "": return public.returnResult(status=False, msg="ips不能为空,请输入IP,一行一个!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: get.ips = get.ips.split("\n") if get.ip_type == "all": for ip in get.ips: if ip in info["ip_limit"]["ip_black"]: info["ip_limit"]["ip_black"].remove(ip) if ip in info["ip_limit"]["ip_white"]: info["ip_limit"]["ip_white"].remove(ip) else: for ip in get.ips: if ip in info["ip_limit"]["ip_{ip_type}".format(ip_type=get.ip_type)]: info["ip_limit"]["ip_{ip_type}".format(ip_type=get.ip_type)].remove(ip) break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="删除成功!") # 2024/4/22 下午8:14 设置指定网站指定URL的缓存 def set_url_cache(self, get): ''' @name 设置指定网站指定URL的缓存 @param get: @return: ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.cache_status = get.get("cache_status/d", 999) if get.cache_status == 999: return public.returnResult(status=False, msg="cache_status不能为空,请传number 1或0!") get.expires = get.get("expires", "1d") if get.expires[0] == "0" or get.expires.startswith("-"): return public.returnResult(status=False, msg="expires参数不合法,请输入大于0的数字!") expires = "expires {}".format(get.expires) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") static_cache = ("\n location ~ .*\\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$" "\n {{" "\n {expires};" "\n error_log /dev/null;" "\n access_log /dev/null;" "\n }}").format( expires=expires, ) for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["proxy_cache"]["cache_status"] = True if get.cache_status == 1 else False info["proxy_cache"]["expires"] = get.expires if get.cache_status == 1: info["proxy_cache"]["cache_conf"] = ("\n proxy_cache {cache_zone};" "\n proxy_cache_key $host$uri$is_args$args;" "\n proxy_ignore_headers Set-Cookie Cache-Control expires X-Accel-Expires;" "\n proxy_cache_valid 200 304 301 302 {expires};" "\n proxy_cache_valid 404 1m;" "{static_cache}").format( cache_zone=get.proxy_json_conf["proxy_cache"]["cache_zone"], expires=get.expires, static_cache=static_cache, ) else: info["proxy_cache"]["cache_conf"] = "" break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/24 上午9:57 设置指定网站指定URL的自定义配置 def set_url_custom_conf(self, get): ''' @name 设置指定网站指定URL的自定义配置 @author wzz <2024/4/24 上午9:58> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_path = get.get("proxy_path", "") if get.proxy_path == "": return public.returnResult(status=False, msg="proxy_path不能为空!") get.custom_conf = get.get("custom_conf", "") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") for info in get.proxy_json_conf["proxy_info"]: if info["proxy_path"] == get.proxy_path: info["custom_conf"] = get.custom_conf break else: return public.returnResult(status=False, msg="未找到此URL【{}】的代理信息!".format(get.proxy_path)) update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") @staticmethod def nginx_get_log_file(nginx_config: str, is_error_log: bool = False): import re if is_error_log: re_data = re.findall(r"error_log +(/(\S+/?)+) ?(.*?);", nginx_config) else: re_data = re.findall(r"access_log +(/(\S+/?)+) ?(.*?);", nginx_config) if re_data is None: return None for i in re_data: file_path = i[0].strip(";") if file_path != "/dev/null": return file_path return None def xsssec(self, text): replace_list = { "<": "<", ">": ">", "'": "'", '"': """, } for k, v in replace_list.items(): text = text.replace(k, v) return public.xssencode2(text) # 2024/4/24 下午5:39 获取指定网站的网站日志 def GetSiteLogs(self, get): ''' @name 获取指定网站的网站日志 @author wzz <2024/4/24 下午5:39> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.type = get.get("type", "access") log_name = get.site_name if get.type != "access": log_name = get.site_name + ".error" get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") if get.proxy_json_conf["proxy_log"]["log_type"] == "default": log_file = public.get_logs_path() + "/" + log_name + '.log' elif get.proxy_json_conf["proxy_log"]["log_type"] == "file": log_file = get.proxy_json_conf["proxy_log"]["log_path"] + "/" + log_name + '.log' else: return public.returnResult(data={"msg": "", "size": 0}) if os.path.exists(log_file): return public.returnResult( data={ "msg": self.xsssec(public.GetNumLines(log_file, 1000)), "size": public.to_size(os.path.getsize(log_file)) } ) return public.returnResult(data={"msg": "", "size": 0}) # 2024/4/25 上午10:51 清理指定网站的反向代理缓存 def clear_cache(self, get): ''' @name 清理指定网站的反向代理缓存 @author wzz <2024/4/25 上午10:51> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") cache_dir = "/www/wwwroot/{site_name}/proxy_cache_dir".format(site_name=get.site_name) if os.path.exists(cache_dir): public.ExecShell("rm -rf {cache_dir}/*".format(cache_dir=cache_dir)) public.serviceReload() return public.returnResult(msg="清理成功!") return public.returnResult(msg="清理失败,缓存目录不存在!") # 2024/4/25 下午9:24 设置指定网站的https端口 def set_https_port(self, get): ''' @name 设置指定网站的https端口 @author wzz <2024/4/25 下午9:24> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.site_name = get.get("site_name", "") if get.site_name == "": return public.returnResult(status=False, msg="site_name不能为空!") get.https_port = get.get("https_port", "443") if not public.checkPort(get.https_port) and get.https_port != "443": return public.returnResult(status=False, msg="https端口【{}】不合法!".format(get.https_port)) get.proxy_json_conf = self.read_json_conf(get) if not get.proxy_json_conf: return public.returnResult(status=False, msg="读取配置文件失败,请删除网站重新添加!") get.proxy_json_conf["https_port"] = get.https_port update_result = self.update_conf(get) if not update_result["status"]: return public.returnResult(status=False, msg=update_result["msg"]) return public.returnResult(msg="设置成功!") # 2024/4/23 下午2:12 保存并重新生成新的nginx配置文件 def update_conf(self, get): ''' @name @author wzz <2024/4/23 下午2:13> @param "data":{"参数名":""} <数据类型> 参数描述 @return dict{"status":True/False,"msg":"提示信息"} ''' get.conf_file = public.get_setup_path() + '/panel/vhost/nginx/' + get.site_name + '.conf' self.generate_config(get) get.data = get.site_conf get.encoding = "utf-8" get.path = get.conf_file import files f = files.files() save_result = f.SaveFileBody(get) if save_result["status"] == False: return public.returnResult(status=False, msg=save_result["msg"]) self._site_proxy_conf_path = "{path}/{site_name}/{site_name}.json".format( path=self._proxy_config_path, site_name=get.site_name ) public.writeFile(self._site_proxy_conf_path, json.dumps(get.proxy_json_conf)) return public.returnResult(msg="保存成功!")