mirror of https://github.com/Aidaho12/haproxy-wi
v8.2.0: Refactor and modularize Nginx proxy addition logic
Redesigned Nginx proxy addition by removing unused templates, consolidating scripts, and introducing new modular template structures. Improvements include dynamic JavaScript handlers, enhanced UI flow, better SSL and upstream management, and new functionality for headers and location-specific configurations. Cleaned up obsolete code and adjusted database version updating logic.pull/418/head
parent
da34363cb4
commit
40703576af
|
@ -12,6 +12,7 @@ from app.views.service.views import (ServiceView, ServiceActionView, ServiceBack
|
|||
ServiceConfigVersionsView, ServiceConfigList)
|
||||
from app.views.service.haproxy_section_views import ListenSectionView, UserListSectionView, PeersSectionView, \
|
||||
GlobalSectionView, DefaultsSectionView
|
||||
from app.views.service.nginx_section_views import UpstreamSectionView, ProxyPassSectionView
|
||||
from app.views.service.lets_encrypt_views import LetsEncryptsView, LetsEncryptView
|
||||
from app.views.service.haproxy_lists_views import HaproxyListView
|
||||
from app.views.ha.views import HAView, HAVIPView, HAVIPsView
|
||||
|
@ -78,6 +79,10 @@ register_api_id_ip(PeersSectionView, 'haproxy_peers_post', '/section/peers', met
|
|||
register_api_id_ip(PeersSectionView, 'haproxy_peers', '/section/peers/<section_name>', methods=['GET', 'PUT', 'DELETE'])
|
||||
register_api_id_ip(GlobalSectionView, 'haproxy_global', '/section/global', methods=['GET', 'PUT'])
|
||||
register_api_id_ip(DefaultsSectionView, 'haproxy_defaults', '/section/defaults', methods=['GET', 'PUT'])
|
||||
register_api_id_ip(UpstreamSectionView, 'nginx_upstream_post_p', '/section/upstream', methods=['POST'])
|
||||
register_api_id_ip(UpstreamSectionView, 'nginx_upstream_post', '/section/upstream/<section_name>', methods=['GET', 'PUT', 'DELETE'])
|
||||
register_api_id_ip(ProxyPassSectionView, 'nginx_proxy_pass_post_p', '/section/proxy_pass', methods=['POST'])
|
||||
register_api_id_ip(ProxyPassSectionView, 'nginx_proxy_pass_post', '/section/proxy_pass/<section_name>', methods=['GET', 'PUT', 'DELETE'])
|
||||
bp.add_url_rule('/service/<any(haproxy):service>/list/<list_name>/<color>', view_func=HaproxyListView.as_view('list_get'), methods=['GET'])
|
||||
bp.add_url_rule('/service/<any(haproxy):service>/list', view_func=HaproxyListView.as_view('list_post'), methods=['POST', 'PUT', 'DELETE'])
|
||||
bp.add_url_rule('/service/<any(nginx, apache):service>/<server_id>/config/list', view_func=ServiceConfigList.as_view('config_list_ip'), methods=['GET'])
|
||||
|
|
|
@ -465,70 +465,6 @@ def update_db_v_4_3_0():
|
|||
print("An error occurred:", e)
|
||||
|
||||
|
||||
def update_db_v_7_2_0():
|
||||
try:
|
||||
if mysql_enable:
|
||||
migrate(
|
||||
migrator.add_column('smon_ping_check', 'interval', IntegerField(default=120)),
|
||||
migrator.add_column('smon_http_check', 'interval', IntegerField(default=120)),
|
||||
migrator.add_column('smon_tcp_check', 'interval', IntegerField(default=120)),
|
||||
migrator.add_column('smon_dns_check', 'interval', IntegerField(default=120)),
|
||||
migrator.add_column('smon_ping_check', 'agent_id', IntegerField(default=1)),
|
||||
migrator.add_column('smon_http_check', 'agent_id', IntegerField(default=1)),
|
||||
migrator.add_column('smon_tcp_check', 'agent_id', IntegerField(default=1)),
|
||||
migrator.add_column('smon_dns_check', 'agent_id', IntegerField(default=1))
|
||||
)
|
||||
else:
|
||||
migrate(
|
||||
migrator.add_column('smon_ping_check', 'interval', IntegerField(constraints=[SQL('DEFAULT 120')])),
|
||||
migrator.add_column('smon_http_check', 'interval', IntegerField(constraints=[SQL('DEFAULT 120')])),
|
||||
migrator.add_column('smon_tcp_check', 'interval', IntegerField(constraints=[SQL('DEFAULT 120')])),
|
||||
migrator.add_column('smon_dns_check', 'interval', IntegerField(constraints=[SQL('DEFAULT 120')])),
|
||||
migrator.add_column('smon_ping_check', 'agent_id', IntegerField(constraints=[SQL('DEFAULT 1')])),
|
||||
migrator.add_column('smon_http_check', 'agent_id', IntegerField(constraints=[SQL('DEFAULT 1')])),
|
||||
migrator.add_column('smon_tcp_check', 'agent_id', IntegerField(constraints=[SQL('DEFAULT 1')])),
|
||||
migrator.add_column('smon_dns_check', 'agent_id', IntegerField(constraints=[SQL('DEFAULT 1')]))
|
||||
)
|
||||
except Exception as e:
|
||||
if e.args[0] == 'duplicate column name: agent_id' or str(e) == '(1060, "Duplicate column name \'agent_id\'")':
|
||||
print('Updating... DB has been updated to version 7.2.0')
|
||||
elif e.args[0] == 'duplicate column name: interval' or str(e) == '(1060, "Duplicate column name \'interval\'")':
|
||||
print('Updating... DB has been updated to version 7.2.0')
|
||||
else:
|
||||
print("An error occurred:", e)
|
||||
|
||||
|
||||
def update_db_v_7_2_0_1():
|
||||
try:
|
||||
Setting.delete().where(Setting.param == 'smon_check_interval').execute()
|
||||
Setting.delete().where((Setting.param == 'smon_keep_history_range') & (Setting.section == 'monitoring')).execute()
|
||||
Setting.delete().where((Setting.param == 'smon_ssl_expire_warning_alert') & (Setting.section == 'monitoring')).execute()
|
||||
Setting.delete().where((Setting.param == 'smon_ssl_expire_critical_alert') & (Setting.section == 'monitoring')).execute()
|
||||
except Exception as e:
|
||||
print("An error occurred:", e)
|
||||
else:
|
||||
print("Updating... DB has been updated to version 7.2.0-1")
|
||||
|
||||
|
||||
def update_db_v_7_2_3():
|
||||
try:
|
||||
if mysql_enable:
|
||||
migrate(
|
||||
migrator.add_column('checker_setting', 'mm_id', IntegerField(default=0)),
|
||||
migrator.add_column('smon', 'mm_channel_id', IntegerField(default=0)),
|
||||
)
|
||||
else:
|
||||
migrate(
|
||||
migrator.add_column('checker_setting', 'mm_id', IntegerField(constraints=[SQL('DEFAULT 0')])),
|
||||
migrator.add_column('smon', 'mm_channel_id', IntegerField(constraints=[SQL('DEFAULT 0')])),
|
||||
)
|
||||
except Exception as e:
|
||||
if e.args[0] == 'duplicate column name: mm_id' or str(e) == '(1060, "Duplicate column name \'mm_id\'")':
|
||||
print('Updating... DB has been updated to version 7.2.3')
|
||||
else:
|
||||
print("An error occurred:", e)
|
||||
|
||||
|
||||
def update_db_v_7_3_1():
|
||||
try:
|
||||
if mysql_enable:
|
||||
|
@ -723,7 +659,7 @@ def update_db_v_8_1_6():
|
|||
|
||||
def update_ver():
|
||||
try:
|
||||
Version.update(version='8.1.8').execute()
|
||||
Version.update(version='8.2.0').execute()
|
||||
except Exception:
|
||||
print('Cannot update version')
|
||||
|
||||
|
@ -741,9 +677,6 @@ def update_all():
|
|||
if check_ver() is None:
|
||||
update_db_v_3_4_5_22()
|
||||
update_db_v_4_3_0()
|
||||
update_db_v_7_2_0()
|
||||
update_db_v_7_2_0_1()
|
||||
update_db_v_7_2_3()
|
||||
update_db_v_7_3_1()
|
||||
update_db_v_7_4()
|
||||
update_db_v_8()
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
from typing import Union
|
||||
from typing import Union, Literal
|
||||
|
||||
from app.modules.db.db_model import SavedServer, Option, HaproxySection
|
||||
from app.modules.db.db_model import SavedServer, Option, HaproxySection, NginxSection
|
||||
from app.modules.db.common import out_error
|
||||
from app.modules.roxywi.class_models import HaproxyConfigRequest, HaproxyGlobalRequest, HaproxyDefaultsRequest
|
||||
from app.modules.roxywi.class_models import HaproxyConfigRequest, HaproxyGlobalRequest, HaproxyDefaultsRequest, NginxUpstreamRequest
|
||||
from app.modules.roxywi.exception import RoxywiResourceNotFound
|
||||
|
||||
SectionModel = {
|
||||
'haproxy': HaproxySection,
|
||||
'nginx': NginxSection,
|
||||
}
|
||||
|
||||
def update_saved_server(server, description, saved_id):
|
||||
try:
|
||||
|
@ -93,9 +97,16 @@ def select_saved_servers(**kwargs):
|
|||
return query_res
|
||||
|
||||
|
||||
def insert_new_section(server_id: int, section_type: str, section_name: str, body: HaproxyConfigRequest):
|
||||
def insert_new_section(
|
||||
server_id: int,
|
||||
section_type: str,
|
||||
section_name: str,
|
||||
body: Union[HaproxyConfigRequest, NginxUpstreamRequest],
|
||||
service: Literal['haproxy', 'nginx'] = 'haproxy'
|
||||
):
|
||||
model = SectionModel[service]
|
||||
try:
|
||||
return (HaproxySection.insert(
|
||||
return (model.insert(
|
||||
server_id=server_id,
|
||||
type=section_type,
|
||||
name=section_name,
|
||||
|
@ -105,7 +116,12 @@ def insert_new_section(server_id: int, section_type: str, section_name: str, bod
|
|||
out_error(e)
|
||||
|
||||
|
||||
def insert_or_update_new_section(server_id: int, section_type: str, section_name: str, body: Union[HaproxyGlobalRequest, HaproxyDefaultsRequest]):
|
||||
def insert_or_update_new_section(
|
||||
server_id: int,
|
||||
section_type: str,
|
||||
section_name: str,
|
||||
body: Union[HaproxyGlobalRequest, HaproxyDefaultsRequest]
|
||||
):
|
||||
try:
|
||||
return (HaproxySection.insert(
|
||||
server_id=server_id,
|
||||
|
@ -117,40 +133,54 @@ def insert_or_update_new_section(server_id: int, section_type: str, section_name
|
|||
out_error(e)
|
||||
|
||||
|
||||
def update_section(server_id: int, section_type: str, section_name: str, body: HaproxyConfigRequest):
|
||||
def update_section(
|
||||
server_id: int,
|
||||
section_type: str,
|
||||
section_name: str,
|
||||
body: Union[HaproxyConfigRequest, NginxUpstreamRequest],
|
||||
service: Literal['haproxy', 'nginx'] = 'haproxy'
|
||||
):
|
||||
model = SectionModel[service]
|
||||
try:
|
||||
HaproxySection.update(
|
||||
model.update(
|
||||
config=body.model_dump(mode='json')
|
||||
).where(
|
||||
(HaproxySection.server_id == server_id) & (HaproxySection.type == section_type) & (HaproxySection.name == section_name)
|
||||
(model.server_id == server_id) & (model.type == section_type) & (model.name == section_name)
|
||||
).execute()
|
||||
except HaproxySection.DoesNotExist:
|
||||
except model.DoesNotExist:
|
||||
raise RoxywiResourceNotFound
|
||||
except Exception as e:
|
||||
out_error(e)
|
||||
|
||||
|
||||
def get_section(server_id: int, section_type: str, section_name: str) -> HaproxySection:
|
||||
def get_section(
|
||||
server_id: int,
|
||||
section_type: str,
|
||||
section_name: str,
|
||||
service: Literal['haproxy', 'nginx'] = 'haproxy'
|
||||
) -> Union[HaproxySection, NginxSection]:
|
||||
model = SectionModel[service]
|
||||
try:
|
||||
return HaproxySection.get(
|
||||
(HaproxySection.server_id == server_id)
|
||||
& (HaproxySection.type == section_type)
|
||||
& (HaproxySection.name == section_name)
|
||||
return model.get(
|
||||
(model.server_id == server_id)
|
||||
& (model.type == section_type)
|
||||
& (model.name == section_name)
|
||||
)
|
||||
except HaproxySection.DoesNotExist:
|
||||
except model.DoesNotExist:
|
||||
raise RoxywiResourceNotFound
|
||||
except Exception as e:
|
||||
out_error(e)
|
||||
|
||||
|
||||
def delete_section(server_id: int, section_type: str, section_name: str):
|
||||
def delete_section(server_id: int, section_type: str, section_name: str, service: Literal['haproxy', 'nginx'] = 'haproxy') -> None:
|
||||
model = SectionModel[service]
|
||||
try:
|
||||
HaproxySection.delete().where(
|
||||
(HaproxySection.server_id == server_id)
|
||||
& (HaproxySection.type == section_type)
|
||||
& (HaproxySection.name == section_name)
|
||||
model.delete().where(
|
||||
(model.server_id == server_id)
|
||||
& (model.type == section_type)
|
||||
& (model.name == section_name)
|
||||
).execute()
|
||||
except HaproxySection.DoesNotExist:
|
||||
except model.DoesNotExist:
|
||||
raise RoxywiResourceNotFound
|
||||
except Exception as e:
|
||||
out_error(e)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from datetime import datetime
|
||||
|
||||
from peewee import ForeignKeyField
|
||||
from playhouse.migrate import *
|
||||
from playhouse.shortcuts import ReconnectMixin
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
|
@ -775,6 +776,18 @@ class HaproxySection(BaseModel):
|
|||
constraints = [SQL('UNIQUE (server_id, type, name)')]
|
||||
|
||||
|
||||
class NginxSection(BaseModel):
|
||||
id = AutoField
|
||||
server_id = ForeignKeyField(Server, on_delete='Cascade')
|
||||
type = CharField()
|
||||
name = CharField()
|
||||
config = JSONField()
|
||||
|
||||
class Meta:
|
||||
table_name = 'nginx_sections'
|
||||
constraints = [SQL('UNIQUE (server_id, type, name)')]
|
||||
|
||||
|
||||
class LetsEncrypt(BaseModel):
|
||||
id = AutoField
|
||||
server_id = ForeignKeyField(Server, null=True, on_delete='SET NULL')
|
||||
|
@ -789,6 +802,21 @@ class LetsEncrypt(BaseModel):
|
|||
table_name = 'lets_encrypt'
|
||||
|
||||
|
||||
class InstallationTasks(BaseModel):
|
||||
id = AutoField
|
||||
service_name = CharField()
|
||||
status = CharField(default='created')
|
||||
error = CharField(null=True)
|
||||
start_date = DateTimeField(default=datetime.now)
|
||||
finish_date = DateTimeField(default=datetime.now)
|
||||
group_id = ForeignKeyField(Groups, null=True, on_delete='SET NULL')
|
||||
user_id = ForeignKeyField(User, null=True, on_delete='SET NULL')
|
||||
server_ids = JSONField(null=True)
|
||||
|
||||
class Meta:
|
||||
table_name = 'installation_tasks'
|
||||
|
||||
|
||||
def create_tables():
|
||||
conn = connect()
|
||||
with conn:
|
||||
|
@ -799,5 +827,5 @@ def create_tables():
|
|||
NginxMetrics, SystemInfo, Services, UserName, GitSetting, CheckerSetting, ApacheMetrics, WafNginx, ServiceStatus,
|
||||
KeepaliveRestart, PD, SmonHistory, SmonAgent, SmonTcpCheck, SmonHttpCheck, SmonPingCheck, SmonDnsCheck, S3Backup,
|
||||
SmonStatusPage, SmonStatusPageCheck, HaCluster, HaClusterSlave, HaClusterVip, HaClusterVirt, HaClusterService,
|
||||
HaClusterRouter, MM, UDPBalancer, HaproxySection, LetsEncrypt]
|
||||
HaClusterRouter, MM, UDPBalancer, HaproxySection, LetsEncrypt, NginxSection, InstallationTasks]
|
||||
)
|
||||
|
|
|
@ -4,7 +4,8 @@ from typing import Optional, Annotated, Union, Literal, Any, Dict, List
|
|||
|
||||
from shlex import quote
|
||||
from pydantic_core import CoreSchema, core_schema
|
||||
from pydantic import BaseModel, Base64Str, StringConstraints, IPvAnyAddress, GetCoreSchemaHandler, AnyUrl, root_validator, EmailStr
|
||||
from pydantic import BaseModel, Base64Str, StringConstraints, IPvAnyAddress, GetCoreSchemaHandler, AnyUrl, \
|
||||
root_validator, EmailStr, model_validator
|
||||
|
||||
DomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
|
||||
WildcardDomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9\*](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
|
||||
|
@ -547,3 +548,83 @@ class ListRequest(BaseModel):
|
|||
|
||||
class IpRequest(BaseModel):
|
||||
ip: Union[IPvAnyAddress, DomainName]
|
||||
|
||||
|
||||
class NginxBackendServer(BaseModel):
|
||||
server: Union[IPvAnyAddress, DomainName]
|
||||
port: Annotated[int, Gt(1), Le(65535)]
|
||||
max_fails: int
|
||||
fail_timeout: int
|
||||
|
||||
|
||||
class NginxUpstreamRequest(BaseModel):
|
||||
name: EscapedString
|
||||
balance: Optional[Literal['ip_hash', 'least_conn', 'random', 'round_robin']]
|
||||
keepalive: Optional[int] = 32
|
||||
backend_servers: List[NginxBackendServer]
|
||||
type: Literal['upstream'] = 'upstream'
|
||||
action: Optional[Literal['save', 'test', 'reload', 'restart']] = "save"
|
||||
|
||||
@model_validator(mode='before')
|
||||
@classmethod
|
||||
def backend_server_cannot_be_empty(cls, values):
|
||||
if 'backend_servers' in values:
|
||||
if len(values['backend_servers']) == 0:
|
||||
raise ValueError('Backend servers cannot be empty')
|
||||
return values
|
||||
|
||||
|
||||
class NginxHeaders(BaseModel):
|
||||
path: Literal['proxy-header', 'header']
|
||||
name: str
|
||||
method: Literal['add', 'hide']
|
||||
value: Optional[str] = None
|
||||
|
||||
|
||||
class NginxHeaderRequest(BaseModel):
|
||||
action: Optional[Literal['add_header', 'proxy_set_header', 'proxy_hide_header']] = None
|
||||
name: Optional[str] = None
|
||||
value: Optional[str] = None
|
||||
|
||||
|
||||
class NginxLocationRequest(BaseModel):
|
||||
location: str = '/'
|
||||
proxy_connect_timeout: Optional[int] = 60
|
||||
proxy_read_timeout: Optional[int] = 60
|
||||
proxy_send_timeout: Optional[int] = 60
|
||||
headers: Optional[List[NginxHeaderRequest]] = None
|
||||
upstream: str
|
||||
|
||||
@model_validator(mode='before')
|
||||
@classmethod
|
||||
def location_cannot_be_empty(cls, values):
|
||||
if 'location' in values:
|
||||
if values['location'] == '':
|
||||
raise ValueError('Location cannot be empty')
|
||||
if not values['location'].startswith('/'):
|
||||
raise ValueError('Location must start with /')
|
||||
return values
|
||||
|
||||
@model_validator(mode='before')
|
||||
@classmethod
|
||||
def upstream_cannot_be_empty(cls, values):
|
||||
if 'upstream' in values:
|
||||
if values['upstream'] == '':
|
||||
raise ValueError('Upstream cannot be empty')
|
||||
return values
|
||||
|
||||
|
||||
class NginxProxyPassRequest(BaseModel):
|
||||
locations: List[NginxLocationRequest]
|
||||
name: EscapedString
|
||||
port: Annotated[int, Gt(1), Le(65535)]
|
||||
type: Literal['proxy_pass'] = 'proxy_pass'
|
||||
scheme: Literal['http', 'https'] = 'http'
|
||||
ssl_crt: Optional[str] = None
|
||||
ssl_key: Optional[str] = None
|
||||
ssl_offloading: Optional[bool] = False
|
||||
action: Optional[Literal['save', 'test', 'reload', 'restart']] = 'save'
|
||||
compression: bool = False
|
||||
compression_level: Annotated[int, Gt(0), Le(10)] = 6
|
||||
compression_min_length: Optional[int] = 1024
|
||||
compression_types: Optional[str] = 'text/plain text/css application/json application/javascript text/xml'
|
||||
|
|
|
@ -108,6 +108,15 @@ def get_remote_files(server_ip: str, config_dir: str, file_format: str):
|
|||
return config_files
|
||||
|
||||
|
||||
def get_remote_upstream_files(server_ip: str):
|
||||
service_config_dir = sql.get_setting('nginx_dir')
|
||||
config_dir = common.return_nice_path(service_config_dir)
|
||||
command = f'sudo ls {config_dir}/conf.d/upstream*.conf|awk -F"/" \'{{print $NF}}\''
|
||||
config_files = ssh_command(server_ip, command)
|
||||
config_files = config_files.replace('upstream_', '').replace('.conf', '')
|
||||
return config_files
|
||||
|
||||
|
||||
def get_system_info(server_ip: str) -> None:
|
||||
if server_ip == '':
|
||||
raise Exception('IP cannot be empty')
|
||||
|
|
|
@ -99,6 +99,11 @@ class SshConnection:
|
|||
except Exception as e:
|
||||
raise paramiko.SSHException(str(e))
|
||||
|
||||
def remove_sftp(self, full_path):
|
||||
sftp = self.ssh.open_sftp()
|
||||
sftp.remove(full_path)
|
||||
sftp.close()
|
||||
|
||||
def generate(self, command):
|
||||
with self as ssh_something:
|
||||
stdin, stdout, stderr = ssh_something.ssh.exec_command(command)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
import json
|
||||
import random
|
||||
from typing import Union
|
||||
from typing import Union, Literal
|
||||
from packaging import version
|
||||
|
||||
import ansible
|
||||
|
@ -160,14 +160,14 @@ def generate_haproxy_inv(json_data: ServiceInstall, installed_service: str) -> o
|
|||
return inv, server_ips
|
||||
|
||||
|
||||
def generate_haproxy_section_inv(json_data: dict, cfg: str) -> dict:
|
||||
def generate_section_inv(json_data: dict, cfg: str, service: Literal['haproxy', 'nginx']) -> dict:
|
||||
cert_path = sql.get_setting('cert_path')
|
||||
haproxy_dir = sql.get_setting('haproxy_dir')
|
||||
service_dir = sql.get_setting(f'{service}_dir')
|
||||
inv = {"server": {"hosts": {}}}
|
||||
inv['server']['hosts']['localhost'] = {
|
||||
"config": json_data,
|
||||
"cert_path": cert_path,
|
||||
"haproxy_dir": haproxy_dir,
|
||||
"service_dir": service_dir,
|
||||
"cfg": cfg,
|
||||
"action": 'create'
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ def generate_haproxy_section_inv(json_data: dict, cfg: str) -> dict:
|
|||
return inv
|
||||
|
||||
|
||||
def generate_haproxy_section_inv_for_del(cfg: str, section_type: str, section_name: str) -> dict:
|
||||
def generate_section_inv_for_del(cfg: str, section_type: str, section_name: str) -> dict:
|
||||
config = {'type': section_type, 'name': section_name}
|
||||
inv = {"server": {"hosts": {}}}
|
||||
inv['server']['hosts']['localhost'] = {
|
||||
|
@ -306,18 +306,18 @@ def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> dict:
|
|||
invent.write(str(inv))
|
||||
except Exception as e:
|
||||
server_mod.stop_ssh_agent(agent_pid)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot save inventory file', roxywi=1)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot save inventory file')
|
||||
|
||||
try:
|
||||
result = ansible_runner.run(**kwargs)
|
||||
except Exception as e:
|
||||
server_mod.stop_ssh_agent(agent_pid)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot run Ansible', roxywi=1)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot run Ansible')
|
||||
|
||||
try:
|
||||
server_mod.stop_ssh_agent(agent_pid)
|
||||
except Exception as e:
|
||||
roxywi_common.logging('Roxy-WI server', f'error: Cannot stop SSH agent {e}', roxywi=1)
|
||||
roxywi_common.logging('Roxy-WI server', f'error: Cannot stop SSH agent {e}')
|
||||
|
||||
os.remove(inventory)
|
||||
|
||||
|
@ -366,12 +366,12 @@ def run_ansible_locally(inv: dict, ansible_role: str) -> dict:
|
|||
with open(inventory, 'a') as invent:
|
||||
invent.write(str(inv))
|
||||
except Exception as e:
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot save inventory file', roxywi=1)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot save inventory file')
|
||||
|
||||
try:
|
||||
result = ansible_runner.run(**kwargs)
|
||||
except Exception as e:
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot run Ansible', roxywi=1)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot run Ansible')
|
||||
|
||||
os.remove(inventory)
|
||||
|
||||
|
@ -395,14 +395,14 @@ def service_actions_after_install(server_ips: str, service: str, json_data) -> N
|
|||
try:
|
||||
update_functions[service](server_ip)
|
||||
except Exception as e:
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot activate {service} on server {server_ip}', roxywi=1)
|
||||
roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot activate {service} on server {server_ip}')
|
||||
if service != 'keepalived':
|
||||
is_docker = json_data['services'][service]['docker']
|
||||
|
||||
if is_docker and service != 'keepalived':
|
||||
service_sql.insert_or_update_service_setting(server_id, service, 'dockerized', '1')
|
||||
service_sql.insert_or_update_service_setting(server_id, service, 'restart', '1')
|
||||
|
||||
if is_docker:
|
||||
service_sql.insert_or_update_service_setting(server_id, service, 'dockerized', '1')
|
||||
else:
|
||||
service_sql.insert_or_update_service_setting(server_id, service, 'dockerized', '0')
|
||||
if service == 'haproxy':
|
||||
try:
|
||||
_create_default_config_in_db(server_id)
|
||||
|
@ -476,8 +476,8 @@ def _install_ansible_collections():
|
|||
except Exception as e:
|
||||
roxywi_common.handle_exceptions(e,
|
||||
'Roxy-WI server',
|
||||
f'Cannot install as collection. {trouble_link}',
|
||||
roxywi=1)
|
||||
f'Cannot install as collection. {trouble_link}'
|
||||
)
|
||||
else:
|
||||
if exit_code != 0:
|
||||
raise Exception(f'error: Ansible collection installation was not successful: {exit_code}. {trouble_link}')
|
||||
|
|
|
@ -12,12 +12,14 @@ import app.modules.db.add as add_sql
|
|||
import app.modules.db.server as server_sql
|
||||
from app.middleware import check_services, get_user_params
|
||||
import app.modules.config.add as add_mod
|
||||
import app.modules.server.server as server_mod
|
||||
import app.modules.common.common as common
|
||||
import app.modules.roxywi.auth as roxywi_auth
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
import app.modules.roxy_wi_tools as roxy_wi_tools
|
||||
from app.views.service.haproxy_section_views import (GlobalSectionView, DefaultsSectionView, ListenSectionView,
|
||||
UserListSectionView, PeersSectionView)
|
||||
from app.views.service.nginx_section_views import UpstreamSectionView, ProxyPassSectionView
|
||||
from app.views.service.haproxy_lists_views import HaproxyListView
|
||||
|
||||
get_config = roxy_wi_tools.GetConfigVar()
|
||||
|
@ -40,6 +42,10 @@ register_api_id_ip(GlobalSectionView, 'haproxy_global_a', '/section/global', met
|
|||
register_api_id_ip(DefaultsSectionView, 'haproxy_defaults_a', '/section/defaults', methods=['GET', 'PUT'])
|
||||
bp.add_url_rule('/<any(haproxy):service>/list/<list_name>/<color>', view_func=HaproxyListView.as_view('list_get'), methods=['GET'])
|
||||
bp.add_url_rule('/<any(haproxy):service>/list', view_func=HaproxyListView.as_view('list_post'), methods=['POST', 'DELETE'])
|
||||
register_api_id_ip(UpstreamSectionView, 'nginx_section_upstream_post_a', '/section/upstream', methods=['POST'])
|
||||
register_api_id_ip(UpstreamSectionView, 'nginx_section_upstream_post', '/section/upstream/<section_name>', methods=['GET', 'PUT', 'DELETE'])
|
||||
register_api_id_ip(ProxyPassSectionView, 'nginx_section_proxy_pass_post_a', '/section/proxy_pass', methods=['POST'])
|
||||
register_api_id_ip(ProxyPassSectionView, 'nginx_section_proxy_pass_post', '/section/proxy_pass/<section_name>', methods=['GET', 'PUT', 'DELETE'])
|
||||
|
||||
|
||||
@bp.before_request
|
||||
|
@ -58,13 +64,15 @@ def add(service):
|
|||
:param service: Service name for service in what will be add
|
||||
:return: Template with Add page or redirect to the index if no needed permission
|
||||
"""
|
||||
user_subscription = roxywi_common.return_user_subscription()
|
||||
roxywi_auth.page_for_admin(level=3)
|
||||
kwargs = {
|
||||
'h2': 1,
|
||||
'add': request.form.get('add'),
|
||||
'conf_add': request.form.get('conf'),
|
||||
'lang': g.user_params['lang'],
|
||||
'all_servers': roxywi_common.get_dick_permit()
|
||||
'all_servers': roxywi_common.get_dick_permit(),
|
||||
'user_subscription': user_subscription,
|
||||
'saved_servers': add_sql.select_saved_servers()
|
||||
}
|
||||
|
||||
if service == 'haproxy':
|
||||
|
@ -74,18 +82,13 @@ def add(service):
|
|||
list_dir = lib_path + "/lists"
|
||||
white_dir = lib_path + "/lists/" + user_group + "/white"
|
||||
black_dir = lib_path + "/lists/" + user_group + "/black"
|
||||
dirs = (list_dir, white_dir, black_dir)
|
||||
|
||||
if not os.path.exists(list_dir):
|
||||
os.makedirs(list_dir)
|
||||
if not os.path.exists(list_dir + "/" + user_group):
|
||||
os.makedirs(list_dir + "/" + user_group)
|
||||
if not os.path.exists(white_dir):
|
||||
os.makedirs(white_dir)
|
||||
if not os.path.exists(black_dir):
|
||||
os.makedirs(black_dir)
|
||||
for dir_to_create in dirs:
|
||||
if not os.path.exists(dir_to_create):
|
||||
os.makedirs(dir_to_create)
|
||||
|
||||
kwargs.setdefault('options', add_sql.select_options())
|
||||
kwargs.setdefault('saved_servers', add_sql.select_saved_servers())
|
||||
kwargs.setdefault('white_lists', roxywi_common.get_files(folder=white_dir, file_format="lst"))
|
||||
kwargs.setdefault('black_lists', roxywi_common.get_files(folder=black_dir, file_format="lst"))
|
||||
kwargs.setdefault('maps', roxywi_common.get_files(folder=f'{lib_path}/maps/{user_group}', file_format="map"))
|
||||
|
@ -99,11 +102,18 @@ def add(service):
|
|||
|
||||
@bp.route('/haproxy/get_section_html')
|
||||
@get_user_params()
|
||||
def get_section_html():
|
||||
def get_haproxy_section_html():
|
||||
lang = g.user_params['lang']
|
||||
return render_template('ajax/config_show_add_sections.html', lang=lang)
|
||||
|
||||
|
||||
@bp.route('/nginx/get_section_html')
|
||||
@get_user_params()
|
||||
def get_nginx_section_html():
|
||||
lang = g.user_params['lang']
|
||||
return render_template('ajax/config_show_add_nginx_sections.html', lang=lang)
|
||||
|
||||
|
||||
@bp.route('/haproxy/bwlists/<color>/<int:group>')
|
||||
@validate()
|
||||
def get_bwlists(color: Literal['black', 'white'], group):
|
||||
|
@ -190,7 +200,8 @@ def delete_saved_server(server_id):
|
|||
@bp.route('/certs/<int:server_id>')
|
||||
def get_certs(server_id: int):
|
||||
server_ip = server_sql.get_server(server_id).ip
|
||||
return add_mod.get_ssl_certs(server_ip)
|
||||
cert_type = request.args.get('cert_type')
|
||||
return add_mod.get_ssl_certs(server_ip, cert_type)
|
||||
|
||||
|
||||
@bp.route('/cert/<int:server_id>/<cert_id>', methods=['DELETE', 'GET'])
|
||||
|
@ -207,7 +218,7 @@ def get_cert(server_id: int, cert_id: EscapedString):
|
|||
@validate(body=SSLCertUploadRequest)
|
||||
def upload_cert(body: SSLCertUploadRequest):
|
||||
try:
|
||||
data = add_mod.upload_ssl_cert(body.server_ip, body.name, body.cert.replace("'", ""))
|
||||
data = add_mod.upload_ssl_cert(body.server_ip, body.name, body.cert.replace("'", ""), body.cert_type)
|
||||
return jsonify(data), 201
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot upload SSL certificate')
|
||||
|
@ -243,58 +254,8 @@ def create_map():
|
|||
return add_mod.edit_map(map_name, group)
|
||||
|
||||
|
||||
@bp.post('/nginx/upstream')
|
||||
@bp.route('/get/upstreams/<int:server_id>')
|
||||
@get_user_params()
|
||||
def add_nginx_upstream():
|
||||
roxywi_auth.page_for_admin(level=3)
|
||||
|
||||
server_ip = common.is_ip_or_dns(request.form.get('serv'))
|
||||
new_upstream = request.form.get('upstream')
|
||||
balance = request.form.get("balance")
|
||||
config_add = ''
|
||||
servers_split = ''
|
||||
generate = request.form.get('generateconfig')
|
||||
|
||||
if balance == 'round_robin' or balance is None:
|
||||
balance = ''
|
||||
else:
|
||||
balance = f' {balance};\n'
|
||||
|
||||
if new_upstream != '':
|
||||
config_add = f'upstream {new_upstream} {{\n'
|
||||
config_add += balance
|
||||
config_name = f'upstream_{new_upstream}'
|
||||
|
||||
if request.form.get('keepalive') != '':
|
||||
config_add += f' keepalive {request.form.get("keepalive")};\n'
|
||||
|
||||
if request.form.get('servers') is not None:
|
||||
servers = request.form.getlist('servers')
|
||||
server_port = request.form.getlist('server_port')
|
||||
max_fails = request.form.getlist('max_fails')
|
||||
fail_timeout = request.form.getlist('fail_timeout')
|
||||
i = 0
|
||||
for server in servers:
|
||||
if server == '':
|
||||
continue
|
||||
try:
|
||||
max_fails_val = f'max_fails={max_fails[i]}'
|
||||
except Exception:
|
||||
max_fails_val = 'max_fails=1'
|
||||
|
||||
try:
|
||||
fail_timeout_val = f'fail_timeout={fail_timeout[i]}'
|
||||
except Exception:
|
||||
fail_timeout_val = 'fail_timeout=1'
|
||||
|
||||
servers_split += f" server {server}:{server_port[i]} {max_fails_val} {fail_timeout_val}s; \n"
|
||||
i += 1
|
||||
config_add += f'{servers_split} }}\n'
|
||||
|
||||
if generate:
|
||||
return config_add
|
||||
else:
|
||||
try:
|
||||
return add_mod.save_nginx_config(config_add, server_ip, config_name)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
def get_upstreams(server_id: int):
|
||||
server_ip = server_sql.get_server(server_id).ip
|
||||
return server_mod.get_remote_upstream_files(server_ip)
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
{% endif %}
|
||||
|
||||
{% if config.whitelist and config.whitelist != 'None' -%}
|
||||
acl white_list_{{ config.whitelist }} src -f {{ haproxy_dir }}/white/{{ config.whitelist }}
|
||||
acl white_list_{{ config.whitelist }} src -f {{ service_dir }}/white/{{ config.whitelist }}
|
||||
tcp-request content accept if white_list_{{ config.whitelist }}
|
||||
tcp-request content reject
|
||||
{% endif %}
|
||||
{% if config.blacklist and config.blacklist != 'None' -%}
|
||||
tcp-request connection reject if { src -f {{ haproxy_dir }}/black/{{ config.blacklist }} }
|
||||
tcp-request connection reject if { src -f {{ service_dir }}/black/{{ config.blacklist }} }
|
||||
{% endif %}
|
||||
|
||||
{% if config.acls != 'None' -%}
|
||||
|
@ -81,7 +81,7 @@
|
|||
{% endif -%}
|
||||
|
||||
{% if config.waf -%}
|
||||
filter spoe engine modsecurity config {{ haproxy_dir }}/waf.conf
|
||||
filter spoe engine modsecurity config {{ service_dir }}/waf.conf
|
||||
http-request deny if { var(txn.modsec.code) -m int gt 0 }
|
||||
{% endif -%}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: Create NGINX section
|
||||
hosts: localhost
|
||||
connection: local
|
||||
become: yes
|
||||
become_method: sudo
|
||||
gather_facts: yes
|
||||
roles:
|
||||
- role: nginx_section
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
- name: Create section
|
||||
when: action == 'create'
|
||||
block:
|
||||
|
||||
- name: Generate Nginx config
|
||||
template:
|
||||
src: proxy_pass.j2
|
||||
dest: "{{ cfg }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
when: config.type == 'proxy_pass'
|
||||
|
||||
- name: Generate upstream config
|
||||
template:
|
||||
src: upstream.j2
|
||||
dest: "{{ cfg }}"
|
||||
when: config.type == 'upstream'
|
|
@ -0,0 +1,170 @@
|
|||
# Roxy-WI MANAGED do not edit it directly
|
||||
{% if config.scheme == 'https' %}
|
||||
server {
|
||||
listen {{ config.port }} ssl{% if nginx_proxy.http2 %} http2{% endif %};
|
||||
ssl_certificate {{ config.ssl_crt }};
|
||||
ssl_certificate_key {{ config.ssl_key }};
|
||||
{% if nginx_proxy.security.hsts %}
|
||||
add_header Strict-Transport-Security "max-age={{ nginx_proxy.security.hsts_max_age }}; includeSubDomains" always;
|
||||
{% endif %}
|
||||
{% else %}
|
||||
server {
|
||||
listen {{ config.port }};
|
||||
{% endif %}
|
||||
|
||||
server_name {{ config.name }};
|
||||
|
||||
access_log /var/log/nginx/{{ config.name }}_access.log main buffer=16k flush=1m;
|
||||
error_log /var/log/nginx/{{ config.name }}_error.log;
|
||||
|
||||
{% if nginx_proxy.access_control.global_whitelist.enabled %}
|
||||
# ACCESS CONTROL: Global rules
|
||||
allow {% for ip in nginx_proxy.access_control.global_whitelist.ips %}{{ ip }} {% endfor %};
|
||||
|
||||
deny all;
|
||||
{% elif nginx_proxy.access_control.global_blacklist.enabled %}
|
||||
# ACCESS CONTROL: Global rules
|
||||
deny {% for ip in nginx_proxy.access_control.global_blacklist.ips %}{{ ip }}; {% endfor %}
|
||||
allow all;
|
||||
{% endif -%}
|
||||
|
||||
|
||||
{% if nginx_proxy.security.hide_server_tokens %}
|
||||
server_tokens off;
|
||||
{% endif %}
|
||||
|
||||
{% if nginx_proxy.security.security_headers %}
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "{{ nginx_proxy.security.content_security_policy }}" always;
|
||||
{% endif %}
|
||||
|
||||
{% if nginx_proxy.rate_limit.enabled %}
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone={{ nginx_proxy.rate_limit.zone.split()[0] }}:{{ nginx_proxy.rate_limit.zone.split()[1] }};
|
||||
{% endif %}
|
||||
|
||||
# Proxy rules
|
||||
{% for location in config.locations %}
|
||||
location {{ location.location }} {
|
||||
{% if nginx_proxy.rate_limit.enabled %}
|
||||
limit_req zone={{ nginx_proxy.rate_limit.zone.split()[0] }} burst={{ nginx_proxy.rate_limit.burst }};
|
||||
{% endif %}
|
||||
|
||||
{%- if nginx_proxy.access_control.location_whitelist.enabled %}
|
||||
# ACCESS CONTROL: Location-specific whitelist
|
||||
{% set path = '/' %}
|
||||
{% if path in nginx_proxy.access_control.location_whitelist.apply_to or nginx_proxy.access_control.location_whitelist.apply_to | length == 0 %}
|
||||
{% for ip in nginx_proxy.access_control.location_whitelist.ips %}allow {{ ip }}; {% endfor %}
|
||||
deny all;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
proxy_pass http://{{ location.upstream }};
|
||||
|
||||
# Headers
|
||||
{% for header in location.headers -%}
|
||||
{{ header.action }} {{ header.name }} {{ header.value }};
|
||||
{% endfor -%}
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout {{ location.proxy_connect_timeout }};
|
||||
proxy_read_timeout {{ location.proxy_read_timeout }};
|
||||
proxy_send_timeout {{ location.proxy_send_timeout }};
|
||||
|
||||
{% if nginx_proxy.websocket.enabled %}
|
||||
# WebSocket
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
{% endif %}
|
||||
|
||||
{% if nginx_proxy.caching.enabled %}
|
||||
# Caching
|
||||
proxy_cache {{ nginx_proxy.caching.zones[0].name }};
|
||||
proxy_cache_key "$scheme$request_method$host$request_uri";
|
||||
proxy_cache_valid 200 302 10m;
|
||||
proxy_cache_valid 404 1m;
|
||||
add_header X-Proxy-Cache $upstream_cache_status;
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
{% if nginx_proxy.static_files.enabled %}
|
||||
# Static files
|
||||
location {{ nginx_proxy.static_files.url_path }} {
|
||||
# ACCESS CONTROL: Location-specific whitelist
|
||||
{% if nginx_proxy.access_control.location_whitelist.enabled %}
|
||||
{% set path = nginx_proxy.static_files.url_path %}
|
||||
{% if path in nginx_proxy.access_control.location_whitelist.apply_to or nginx_proxy.access_control.location_whitelist.apply_to | length == 0 %}
|
||||
allow {% for ip in nginx_proxy.access_control.location_whitelist.ips %}{{ ip }}; {% endfor %}
|
||||
deny all;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
alias {{ nginx_proxy.static_files.path }}/;
|
||||
expires 30d;
|
||||
access_log off;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if nginx_proxy.error_pages.enabled %}
|
||||
# Custom error pages
|
||||
{% for code in nginx_proxy.error_pages.codes %}
|
||||
error_page {{ code }} /error_{{ code }}.html;
|
||||
{% endfor %}
|
||||
|
||||
location ~ ^/error_ {
|
||||
internal;
|
||||
root {{ nginx_proxy.error_pages.path }};
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if config.compression %}
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_types {{ config.compression_types }};
|
||||
gzip_min_length {{ config.compression_min_length }};
|
||||
gzip_comp_level {{ config.compression_level }};
|
||||
gzip_proxied any;
|
||||
{% endif %}
|
||||
|
||||
{% if nginx_proxy.security.hide_backend_headers %}
|
||||
# Hide backend headers
|
||||
proxy_hide_header X-Powered-By;
|
||||
proxy_hide_header Server;
|
||||
{% endif -%}
|
||||
}
|
||||
|
||||
{% if nginx_proxy.caching.enabled %}
|
||||
# Cache zones
|
||||
proxy_cache_path {{ nginx_proxy.caching.zones[0].path }}
|
||||
levels={{ nginx_proxy.caching.zones[0].levels }}
|
||||
keys_zone={{ nginx_proxy.caching.zones[0].name }}:{{ nginx_proxy.caching.zones[0].size }}
|
||||
inactive={{ nginx_proxy.caching.zones[0].inactive }};
|
||||
{% endif %}
|
||||
|
||||
{% if config.ssl_offloading -%}
|
||||
# HTTP to HTTPS redirect
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ config.name }};
|
||||
|
||||
{% if nginx_proxy.access_control.global_whitelist.enabled %}
|
||||
# ACCESS CONTROL: Apply global rules to redirect server
|
||||
allow {% for ip in nginx_proxy.access_control.global_whitelist.ips %}{{ ip }}; {% endfor %}
|
||||
deny all;
|
||||
{% elif nginx_proxy.access_control.global_blacklist.enabled %}
|
||||
deny {% for ip in nginx_proxy.access_control.global_blacklist.ips %}{{ ip }}; {% endfor %}
|
||||
allow all;
|
||||
{% endif %}
|
||||
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
{% endif %}
|
|
@ -0,0 +1,10 @@
|
|||
# Roxy-WI MANAGED do not edit it directly
|
||||
upstream {{ config.name }} {
|
||||
keepalive {{ config.keepalive }};
|
||||
{% if config.balance != 'round_robin' -%}
|
||||
{{ config.balance }};
|
||||
{% endif -%}
|
||||
{% for server in config.backend_servers %}
|
||||
server {{ server.server }}:{{ server.port }} max_fails={{ server.max_fails }} fail_timeout={{ server.fail_timeout }};
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
# Main server configuration
|
||||
nginx_proxy:
|
||||
http2: false # Enable HTTP/2 (requires SSL)
|
||||
|
||||
# Static files configuration
|
||||
static_files:
|
||||
enabled: false # Enable static file handling
|
||||
path: "/var/www/static" # Physical path to static files
|
||||
url_path: "/static/" # URL prefix for static files
|
||||
|
||||
# Security configurations
|
||||
security:
|
||||
hide_server_tokens: true # Hide Nginx version in headers
|
||||
hide_backend_headers: true # Hide backend server headers (e.g., X-Powered-By)
|
||||
security_headers: true # Enable security headers (X-Content-Type-Options, etc.)
|
||||
hsts: true # Enable HTTP Strict Transport Security
|
||||
hsts_max_age: 15768000 # HSTS duration in seconds (6 months)
|
||||
content_security_policy: "default-src 'self'" # Content Security Policy rules
|
||||
|
||||
# Rate limiting configuration
|
||||
rate_limit:
|
||||
enabled: false # Enable rate limiting
|
||||
zone: "ratelimit 10m rate=100r/s" # Rate limit zone (10MB memory, 100 req/sec)
|
||||
burst: 50 # Maximum burst capacity
|
||||
|
||||
# Caching configuration
|
||||
caching:
|
||||
enabled: false # Enable response caching
|
||||
zones:
|
||||
- name: "api_cache" # Cache zone name
|
||||
path: "/var/cache/nginx/api" # Disk path for cache
|
||||
size: "10m" # Memory zone size
|
||||
inactive: "60m" # Cache retention time for inactive entries
|
||||
levels: "1:2" # Directory structure levels
|
||||
|
||||
websocket:
|
||||
enabled: false
|
||||
|
||||
# Custom error pages
|
||||
error_pages:
|
||||
enabled: false # Enable custom error pages
|
||||
codes: [502, 503, 504] # HTTP status codes to handle
|
||||
path: "/var/www/errors" # Directory containing error HTML files
|
||||
|
||||
# IP access control
|
||||
access_control:
|
||||
global_whitelist:
|
||||
enabled: false # Global allow-list mode
|
||||
ips: ["192.168.1.0/24", "127.0.0.1"] # Allowed IPs/CIDR ranges
|
||||
global_blacklist:
|
||||
enabled: false # Global deny-list mode
|
||||
ips: ["203.0.113.0/24"] # Blocked IPs/CIDR ranges
|
||||
location_whitelist:
|
||||
enabled: false # Path-specific allow-list
|
||||
ips: ["172.16.0.0/16"] # Allowed IPs for specific paths
|
||||
apply_to: ["/admin", "/api"] # Protected paths
|
||||
|
||||
|
||||
# TCP/UDP proxy configuration
|
||||
tcp_proxies:
|
||||
- name: "mysql_proxy" # Proxy name
|
||||
enabled: false # Enable this proxy
|
||||
listen_port: 3306 # Listening port
|
||||
protocol: "tcp" # Protocol (tcp/udp)
|
||||
upstream_servers:
|
||||
- { ip: "10.0.1.1", port: 3306, weight: 3 } # Backend servers
|
||||
ssl_enabled: true # Enable SSL termination
|
||||
ssl_cert: "/etc/ssl/certs/mysql.crt" # SSL certificate
|
||||
ssl_key: "/etc/ssl/private/mysql.key" # SSL private key
|
||||
proxy_timeout: 3600s # Connection timeout
|
||||
proxy_connect_timeout: 60s # Backend connect timeout
|
|
@ -1,23 +1,11 @@
|
|||
window.onload = function() {
|
||||
var cur_url = window.location.href.split('/').pop();
|
||||
let activeTabIdx = $('#tabs').tabs('option','active');
|
||||
if (cur_url.split('#')[1] === 'ssl') {
|
||||
if (activeTabIdx === 4) {
|
||||
getLes();
|
||||
}
|
||||
}
|
||||
}
|
||||
$( function() {
|
||||
$("#tabs ul li").click(function () {
|
||||
let activeTab = $(this).find("a").attr("href");
|
||||
let activeTabClass = activeTab.replace('#', '');
|
||||
$('.menu li ul li').each(function () {
|
||||
activeSubMenu($(this), activeTabClass)
|
||||
});
|
||||
if (activeTab === '#ssl') {
|
||||
getLes();
|
||||
}
|
||||
});
|
||||
let activeTab = $(this).find("a").attr("href");
|
||||
let activeTabClass = activeTab.replace('#', '');
|
||||
$('.menu li ul li').each(function () {
|
||||
activeSubMenu($(this), activeTabClass)
|
||||
});
|
||||
});
|
||||
$("#listen-mode-select").on('selectmenuchange', function () {
|
||||
if ($("#listen-mode-select option:selected").val() === "tcp") {
|
||||
$("#https-listen-span").hide("fast");
|
||||
|
@ -325,52 +313,6 @@ $( function() {
|
|||
}
|
||||
});
|
||||
});
|
||||
$("#servers_table input").change(function () {
|
||||
let id = $(this).attr('id').split('-');
|
||||
updateSavedServer(id[2])
|
||||
|
||||
});
|
||||
$('[name=servers]').autocomplete({
|
||||
source: "/add/server/get/" + $('#group_id').val(),
|
||||
autoFocus: true,
|
||||
minLength: 1,
|
||||
select: function (event, ui) {
|
||||
$(this).append(ui.item.value + " ");
|
||||
$(this).next().focus();
|
||||
}
|
||||
})
|
||||
.autocomplete("instance")._renderItem = function (ul, item) {
|
||||
return $("<li>")
|
||||
.append("<div>" + item.value + "<br>" + item.desc + "</div>")
|
||||
.appendTo(ul);
|
||||
};
|
||||
$('#add-saved-server-button').click(function () {
|
||||
if ($('#saved-server-add-table').css('display', 'none')) {
|
||||
$('#saved-server-add-table').show("blind", "fast");
|
||||
}
|
||||
});
|
||||
$('#add-saved-server-new').click(function () {
|
||||
$.ajax({
|
||||
url: "/add/server",
|
||||
data: JSON.stringify({
|
||||
server: $('#new-saved-servers').val(),
|
||||
description: $('#new-saved-servers-description').val()
|
||||
}),
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function (data) {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$("#servers_table").append(data.data);
|
||||
setTimeout(function () {
|
||||
$(".newsavedserver").removeClass("update");
|
||||
}, 2500);
|
||||
$.getScript(overview);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$(":regex(id, template)").click(function () {
|
||||
if ($(':regex(id, template)').is(':checked')) {
|
||||
$(".prefix").show("fast");
|
||||
|
@ -394,181 +336,79 @@ $( function() {
|
|||
$("[name=port_check_text]").show("fast");
|
||||
}
|
||||
});
|
||||
let cur_url = window.location.href.split('/').pop();
|
||||
cur_url = cur_url.split('/');
|
||||
if (cur_url[0] == "add") {
|
||||
$("#cache").checkboxradio("disable");
|
||||
$("#waf").checkboxradio("disable");
|
||||
$("#serv").on('selectmenuchange', function () {
|
||||
change_select_acceleration("");
|
||||
change_select_waf("");
|
||||
});
|
||||
$("#cache2").checkboxradio("disable");
|
||||
$("#waf2").checkboxradio("disable");
|
||||
$("#serv2").on('selectmenuchange', function () {
|
||||
change_select_acceleration("2");
|
||||
change_select_waf("2");
|
||||
});
|
||||
$("#cache3").checkboxradio("disable");
|
||||
$("#serv3").on('selectmenuchange', function () {
|
||||
change_select_acceleration("3");
|
||||
});
|
||||
$('#compression').on("click", function () {
|
||||
if ($('#compression').is(':checked')) {
|
||||
$("#cache").checkboxradio("disable");
|
||||
$("#cache").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration("");
|
||||
}
|
||||
});
|
||||
$('#compression2').on("click", function () {
|
||||
if ($('#compression2').is(':checked')) {
|
||||
$("#cache2").checkboxradio("disable");
|
||||
$("#cache2").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration('2');
|
||||
}
|
||||
});
|
||||
$('#compression3').on("click", function () {
|
||||
if ($('#compression3').is(':checked')) {
|
||||
$("#cache3").checkboxradio("disable");
|
||||
$("#cache3").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration('3');
|
||||
}
|
||||
});
|
||||
$('#cache').on("click", function () {
|
||||
if ($('#cache').is(':checked')) {
|
||||
$("#compression").checkboxradio("disable");
|
||||
$("#compression").prop('checked', false);
|
||||
} else {
|
||||
$("#compression").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$('#cache2').on("click", function () {
|
||||
if ($('#cache2').is(':checked')) {
|
||||
$("#compression2").checkboxradio("disable");
|
||||
$("#compression2").prop('checked', false);
|
||||
} else {
|
||||
$("#compression2").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$('#cache3').on("click", function () {
|
||||
if ($('#cache3').is(':checked')) {
|
||||
$("#compression3").checkboxradio("disable");
|
||||
$("#compression3").prop('checked', false);
|
||||
} else {
|
||||
$("#compression3").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$("#add1").on("click", function () {
|
||||
$('.menu li ul li').each(function () {
|
||||
$(this).find('a').css('padding-left', '20px')
|
||||
$(this).find('a').css('border-left', '0px solid #5D9CEB');
|
||||
$(this).find('a').css('background-color', '#48505A');
|
||||
$(this).children("#add1").css('padding-left', '30px');
|
||||
$(this).children("#add1").css('border-left', '4px solid #5D9CEB');
|
||||
$(this).children("#add1").css('background-color', 'var(--right-menu-blue-rolor)');
|
||||
});
|
||||
$("#tabs").tabs("option", "active", 0);
|
||||
});
|
||||
$("#add3").on("click", function () {
|
||||
$('.menu li ul li').each(function () {
|
||||
$(this).find('a').css('padding-left', '20px')
|
||||
$(this).find('a').css('border-left', '0px solid #5D9CEB');
|
||||
$(this).find('a').css('background-color', '#48505A');
|
||||
$(this).children("#add3").css('padding-left', '30px');
|
||||
$(this).children("#add3").css('border-left', '4px solid #5D9CEB');
|
||||
$(this).children("#add3").css('background-color', 'var(--right-menu-blue-rolor)');
|
||||
});
|
||||
getLes();
|
||||
$("#tabs").tabs("option", "active", 4);
|
||||
});
|
||||
$("#add4").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 5);
|
||||
});
|
||||
$("#add5").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 6);
|
||||
});
|
||||
$("#add6").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 7);
|
||||
$("#userlist_serv").selectmenu("open");
|
||||
});
|
||||
$("#add7").on("click", function () {
|
||||
$('.menu li ul li').each(function () {
|
||||
$(this).find('a').css('padding-left', '20px')
|
||||
$(this).find('a').css('border-left', '0px solid #5D9CEB');
|
||||
$(this).find('a').css('background-color', '#48505A');
|
||||
$(this).children("#add7").css('padding-left', '30px');
|
||||
$(this).children("#add7").css('border-left', '4px solid #5D9CEB');
|
||||
$(this).children("#add7").css('background-color', 'var(--right-menu-blue-rolor)');
|
||||
});
|
||||
$("#tabs").tabs("option", "active", 9);
|
||||
});
|
||||
}
|
||||
$("#ssl_key_upload").click(function () {
|
||||
if (!checkIsServerFiled('#serv4')) return false;
|
||||
if (!checkIsServerFiled('#ssl_name', 'Enter the Certificate name')) return false;
|
||||
if (!checkIsServerFiled('#ssl_cert', 'Paste the contents of the certificate file')) return false;
|
||||
let jsonData = {
|
||||
server_ip: $('#serv4').val(),
|
||||
cert: $('#ssl_cert').val(),
|
||||
name: $('#ssl_name').val()
|
||||
}
|
||||
$.ajax({
|
||||
url: "/add/cert/add",
|
||||
data: JSON.stringify(jsonData),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
type: "POST",
|
||||
success: function (data) {
|
||||
if (data.error === 'failed') {
|
||||
toastr.error(data.error);
|
||||
} else {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i]) {
|
||||
if (data[i].indexOf('error: ') != '-1' || data[i].indexOf('Errno') != '-1') {
|
||||
toastr.error(data[i]);
|
||||
} else {
|
||||
toastr.success(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#cache").checkboxradio("disable");
|
||||
$("#waf").checkboxradio("disable");
|
||||
$("#serv").on('selectmenuchange', function () {
|
||||
change_select_acceleration("");
|
||||
change_select_waf("");
|
||||
});
|
||||
$('#ssl_key_view').click(function () {
|
||||
if (!checkIsServerFiled('#serv5')) return false;
|
||||
$.ajax({
|
||||
url: "/add/certs/" + $('#serv5').val(),
|
||||
success: function (data) {
|
||||
if (data.indexOf('error:') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
let i;
|
||||
let new_data = "";
|
||||
data = data.split("\n");
|
||||
let j = 1
|
||||
for (i = 0; i < data.length; i++) {
|
||||
data[i] = data[i].replace(/\s+/g, ' ');
|
||||
if (data[i] != '') {
|
||||
if (j % 2) {
|
||||
if (j != 0) {
|
||||
new_data += '</span>'
|
||||
}
|
||||
new_data += '<span class="list_of_lists">'
|
||||
} else {
|
||||
new_data += '</span><span class="list_of_lists">'
|
||||
|
||||
}
|
||||
j += 1
|
||||
new_data += ' <a onclick="view_ssl(\'' + data[i] + '\')" title="View ' + data[i] + ' cert">' + data[i] + '</a> '
|
||||
}
|
||||
}
|
||||
$("#ajax-show-ssl").html(new_data);
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#cache2").checkboxradio("disable");
|
||||
$("#waf2").checkboxradio("disable");
|
||||
$("#serv2").on('selectmenuchange', function () {
|
||||
change_select_acceleration("2");
|
||||
change_select_waf("2");
|
||||
});
|
||||
$("#cache3").checkboxradio("disable");
|
||||
$("#serv3").on('selectmenuchange', function () {
|
||||
change_select_acceleration("3");
|
||||
});
|
||||
$('#compression').on("click", function () {
|
||||
if ($('#compression').is(':checked')) {
|
||||
$("#cache").checkboxradio("disable");
|
||||
$("#cache").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration("");
|
||||
}
|
||||
});
|
||||
$('#compression2').on("click", function () {
|
||||
if ($('#compression2').is(':checked')) {
|
||||
$("#cache2").checkboxradio("disable");
|
||||
$("#cache2").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration('2');
|
||||
}
|
||||
});
|
||||
$('#compression3').on("click", function () {
|
||||
if ($('#compression3').is(':checked')) {
|
||||
$("#cache3").checkboxradio("disable");
|
||||
$("#cache3").prop('checked', false);
|
||||
} else {
|
||||
change_select_acceleration('3');
|
||||
}
|
||||
});
|
||||
$('#cache').on("click", function () {
|
||||
if ($('#cache').is(':checked')) {
|
||||
$("#compression").checkboxradio("disable");
|
||||
$("#compression").prop('checked', false);
|
||||
} else {
|
||||
$("#compression").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$('#cache2').on("click", function () {
|
||||
if ($('#cache2').is(':checked')) {
|
||||
$("#compression2").checkboxradio("disable");
|
||||
$("#compression2").prop('checked', false);
|
||||
} else {
|
||||
$("#compression2").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$('#cache3').on("click", function () {
|
||||
if ($('#cache3').is(':checked')) {
|
||||
$("#compression3").checkboxradio("disable");
|
||||
$("#compression3").prop('checked', false);
|
||||
} else {
|
||||
$("#compression3").checkboxradio("enable");
|
||||
}
|
||||
});
|
||||
$("#add4").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 4);
|
||||
});
|
||||
$("#add5").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 5);
|
||||
});
|
||||
$("#add6").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 6);
|
||||
$("#userlist_serv").selectmenu("open");
|
||||
});
|
||||
$('[name=add-server-input]').click(function () {
|
||||
$("[name=add_servers]").append(add_server_var);
|
||||
|
@ -691,7 +531,7 @@ $( function() {
|
|||
let server = $("#add-" + section_type + " select[name='server'] option:selected");
|
||||
if (!checkIsServerFiled("#add-" + section_type + " select[name='server'] option:selected")) return false;
|
||||
$.ajax({
|
||||
url: "/add/certs/" + server.val(),
|
||||
url: "/add/certs/" + server.val() + "?cert_type=pem",
|
||||
success: function (data) {
|
||||
data = data.replace(/\s+/g, ' ');
|
||||
response(data.split(" "));
|
||||
|
@ -810,7 +650,7 @@ $( function() {
|
|||
}
|
||||
});
|
||||
$("#options-" + section_type + "-show").click(function () {
|
||||
if ($("#options-"+section_type+"-show").is(':checked')) {
|
||||
if ($("#options-" + section_type + "-show").is(':checked')) {
|
||||
$("#options-" + section_type + "-show-div").show("fast");
|
||||
} else {
|
||||
$("#options-" + section_type + "-show-div").hide("fast");
|
||||
|
@ -957,7 +797,7 @@ function updateOptions(id) {
|
|||
if (data.indexOf('error:') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$("#option-" + id).addClass("update", 1000);
|
||||
$("#option-" + id).Class("update", 1000);
|
||||
setTimeout(function () {
|
||||
$("#option-" + id).removeClass("update");
|
||||
}, 2500);
|
||||
|
@ -965,159 +805,6 @@ function updateOptions(id) {
|
|||
}
|
||||
});
|
||||
}
|
||||
function confirmDeleteSavedServer(id) {
|
||||
$("#dialog-confirm").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: delete_word + " " + $('#servers-ip-' + id).val() + "?",
|
||||
buttons: [{
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
removeSavedServer(id);
|
||||
}
|
||||
}, {
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
function removeSavedServer(id) {
|
||||
$("#servers-saved-" + id).css("background-color", "#f2dede");
|
||||
$.ajax({
|
||||
url: "/add/server/" + id,
|
||||
type: "DELETE",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
statusCode: {
|
||||
204: function (xhr) {
|
||||
$("#servers-saved-" + id).remove();
|
||||
},
|
||||
404: function (xhr) {
|
||||
$("#servers-saved-" + id).remove();
|
||||
}
|
||||
},
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
if (data.status === "failed") {
|
||||
toastr.error(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateSavedServer(id) {
|
||||
toastr.clear();
|
||||
$.ajax( {
|
||||
url: "/add/server/" + id,
|
||||
type: "PUT",
|
||||
data: JSON.stringify({"server": $('#servers-ip-'+id).val(), description: $('#servers-desc-'+id).val(),}),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function( data ) {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data.error);
|
||||
} else {
|
||||
$("#servers-saved-"+id).addClass( "update", 1000 );
|
||||
setTimeout(function() {
|
||||
$( "#servers-saved-"+id ).removeClass( "update" );
|
||||
}, 2500 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
function view_ssl(id) {
|
||||
let raw_word = translate_div.attr('data-raw');
|
||||
if(!checkIsServerFiled('#serv5')) return false;
|
||||
$.ajax( {
|
||||
url: "/add/cert/" + $('#serv5').val() + '/' + id,
|
||||
success: function( data ) {
|
||||
if (data.indexOf('error: ') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$('#dialog-confirm-body').text(data);
|
||||
$( "#dialog-confirm-cert" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 670,
|
||||
modal: true,
|
||||
title: "Certificate from "+$('#serv5').val()+", name: "+id,
|
||||
buttons: [{
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}, {
|
||||
text: raw_word,
|
||||
click: function () {
|
||||
showRawSSL(id);
|
||||
}
|
||||
}, {
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
confirmDeleting("SSL cert", id, $(this), "");
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
function showRawSSL(id) {
|
||||
$.ajax({
|
||||
url: "/add/cert/get/raw/" + $('#serv5').val() + "/" + id,
|
||||
success: function (data) {
|
||||
if (data.indexOf('error: ') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$('#dialog-confirm-body').text(data);
|
||||
$("#dialog-confirm-cert").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 670,
|
||||
modal: true,
|
||||
title: "Certificate from " + $('#serv5').val() + ", name: " + id,
|
||||
buttons: [{
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}, {
|
||||
text: "Human readable",
|
||||
click: function () {
|
||||
view_ssl(id);
|
||||
}
|
||||
}, {
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
confirmDeleting("SSL cert", id, $(this), "");
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function deleteSsl(id) {
|
||||
if (!checkIsServerFiled('#serv5')) return false;
|
||||
$.ajax({
|
||||
url: "/add/cert/" + $("#serv5").val() + "/" + id,
|
||||
type: "DELETE",
|
||||
success: function (data) {
|
||||
if (data.indexOf('error: ') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
toastr.clear();
|
||||
toastr.success('SSL cert ' + id + ' has been deleted');
|
||||
$("#ssl_key_view").trigger("click");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function change_select_acceleration(id) {
|
||||
$.ajax({
|
||||
url: "/service/haproxy/" + $('#serv' + id + ' option:selected').val() + "/status",
|
||||
|
@ -1465,8 +1152,6 @@ function deleteId(id) {
|
|||
}
|
||||
var if_word = translate_div.attr('data-if-title');
|
||||
var then_word = translate_div.attr('data-then');
|
||||
var value_word = translate_div.attr('data-value');
|
||||
var name_word = translate_div.attr('data-name');
|
||||
var acl_option = '<p id="new_acl_p" style="border-bottom: 1px solid #ddd; padding-bottom: 10px;">\n' +
|
||||
'<b class="padding10">'+if_word+'</b>\n' +
|
||||
'<select name="acl_if">\n' +
|
||||
|
@ -1569,15 +1254,7 @@ function make_actions_for_adding_bind(section_id) {
|
|||
}
|
||||
});
|
||||
}
|
||||
function makeid(length) {
|
||||
let result = '';
|
||||
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let charactersLength = characters.length;
|
||||
for ( let i = 0; i < length; i++ ) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function changePortCheckFromServerPort() {
|
||||
$('[name=server_port]').on('input', function () {
|
||||
let iNum = parseInt($($(this)).val());
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
$( function() {
|
||||
$('#add-saved-server-button').click(function () {
|
||||
if ($('#saved-server-add-table').css('display', 'none')) {
|
||||
$('#saved-server-add-table').show("blind", "fast");
|
||||
}
|
||||
});
|
||||
$('#add-saved-server-new').click(function () {
|
||||
$.ajax({
|
||||
url: "/add/server",
|
||||
data: JSON.stringify({
|
||||
server: $('#new-saved-servers').val(),
|
||||
description: $('#new-saved-servers-description').val()
|
||||
}),
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function (data) {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$("#servers_table").append(data.data);
|
||||
setTimeout(function () {
|
||||
$(".newsavedserver").removeClass("update");
|
||||
}, 2500);
|
||||
$.getScript(overview);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#servers_table input").change(function () {
|
||||
let id = $(this).attr('id').split('-');
|
||||
updateSavedServer(id[2])
|
||||
});
|
||||
$('[name=servers]').autocomplete({
|
||||
source: "/add/server/get/" + $('#group_id').val(),
|
||||
autoFocus: true,
|
||||
minLength: 1,
|
||||
select: function (event, ui) {
|
||||
$(this).append(ui.item.value + " ");
|
||||
$(this).next().focus();
|
||||
}
|
||||
})
|
||||
.autocomplete("instance")._renderItem = function (ul, item) {
|
||||
return $("<li>")
|
||||
.append("<div>" + item.value + "<br>" + item.desc + "</div>")
|
||||
.appendTo(ul);
|
||||
};
|
||||
});
|
||||
function updateSavedServer(id) {
|
||||
toastr.clear();
|
||||
$.ajax( {
|
||||
url: "/add/server/" + id,
|
||||
type: "PUT",
|
||||
data: JSON.stringify({"server": $('#servers-ip-'+id).val(), description: $('#servers-desc-'+id).val(),}),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function( data ) {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data.error);
|
||||
} else {
|
||||
$("#servers-saved-"+id).addClass( "update", 1000 );
|
||||
setTimeout(function() {
|
||||
$( "#servers-saved-"+id ).removeClass( "update" );
|
||||
}, 2500 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
function confirmDeleteSavedServer(id) {
|
||||
$("#dialog-confirm").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: delete_word + " " + $('#servers-ip-' + id).val() + "?",
|
||||
buttons: [{
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
removeSavedServer(id);
|
||||
}
|
||||
}, {
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
function removeSavedServer(id) {
|
||||
$("#servers-saved-" + id).css("background-color", "#f2dede");
|
||||
$.ajax({
|
||||
url: "/add/server/" + id,
|
||||
type: "DELETE",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
statusCode: {
|
||||
204: function (xhr) {
|
||||
$("#servers-saved-" + id).remove();
|
||||
},
|
||||
404: function (xhr) {
|
||||
$("#servers-saved-" + id).remove();
|
||||
}
|
||||
},
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
if (data.status === "failed") {
|
||||
toastr.error(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,161 +1,263 @@
|
|||
$( function() {
|
||||
$(".redirectUpstream").on("click", function () {
|
||||
resetProxySettings();
|
||||
$("#tabs").tabs("option", "active", 1);
|
||||
$("#serv").selectmenu("open");
|
||||
});
|
||||
$( "#serv" ).on('selectmenuchange',function() {
|
||||
$(".redirectUpstream").on("click", function () {
|
||||
resetProxySettings();
|
||||
$("#tabs").tabs("option", "active", 2);
|
||||
$("#serv2").selectmenu("open");
|
||||
});
|
||||
$(".redirectProxyPass").on("click", function () {
|
||||
resetProxySettings();
|
||||
$("#tabs").tabs("option", "active", 1);
|
||||
$("#serv1").selectmenu("open");
|
||||
});
|
||||
$("#create-ssl-proxy_pass").on("click", function () {
|
||||
resetProxySettings();
|
||||
createSsl(1);
|
||||
});
|
||||
$("#serv2").on('selectmenuchange', function () {
|
||||
$('#name').focus();
|
||||
});
|
||||
let add_server_let = '<br /><input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server" style="margin: 2px 0 4px 0;">: ' +
|
||||
'<input name="server_port" required title="Backend port" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number"> ' +
|
||||
'max_fails: <input name="max_fails" required title="By default, the number of unsuccessful attempts is set to 1" size=5 value="1" class="form-control add_server_number" type="number">' +
|
||||
' fail_timeout: <input name="fail_timeout" required title="By default, the number of unsuccessful attempts is set to 1" size=5 value="1" class="form-control add_server_number" type="number">s'
|
||||
$('[name=add-server-input]').click(function() {
|
||||
$("[name=add_servers]").append(add_server_var);
|
||||
changePortCheckFromServerPort();
|
||||
$('[name=add-server-input]').click(function () {
|
||||
$("[name=add_servers]").append(add_server_nginx_var);
|
||||
});
|
||||
$('.advance-show-button').click(function() {
|
||||
$('.advance-show-button').click(function () {
|
||||
$('.advance').fadeIn();
|
||||
$('.advance-show-button').css('display', 'none');
|
||||
$('.advance-hide-button').css('display', 'block');
|
||||
return false;
|
||||
});
|
||||
$('.advance-hide-button').click(function() {
|
||||
$('.advance-hide-button').click(function () {
|
||||
$('.advance').fadeOut();
|
||||
$('.advance-show-button').css('display', 'block');
|
||||
$('.advance-hide-button').css('display', 'none');
|
||||
return false;
|
||||
});
|
||||
$("#scheme").on('selectmenuchange', function () {
|
||||
if ($("#scheme option:selected").val() === "http") {
|
||||
$('#hide-scheme').hide();
|
||||
} else {
|
||||
$('#hide-scheme').show();
|
||||
}
|
||||
});
|
||||
$("#compression").click(function () {
|
||||
if ($("#compression").is(':checked')) {
|
||||
$('#compression-options').show();
|
||||
} else {
|
||||
$('#compression-options').hide();
|
||||
}
|
||||
});
|
||||
$("#show_header").on("click", function () {
|
||||
$("#header_div").show();
|
||||
$("#add_header").show();
|
||||
$("#show_header").hide();
|
||||
});
|
||||
$("#add_header").click(function () {
|
||||
make_actions_for_adding_header('#header_div');
|
||||
});
|
||||
for (let section_type of ['ssl_key', 'ssl_crt']) {
|
||||
let cert_type = section_type.split('_')[1];
|
||||
$("#" + section_type).autocomplete({
|
||||
source: function (request, response) {
|
||||
let server = $("#add-proxy_pass select[name='server'] option:selected");
|
||||
if (!checkIsServerFiled("#add-proxy_pass select[name='server'] option:selected")) return false;
|
||||
$.ajax({
|
||||
url: "/add/certs/" + server.val() + "?cert_type=" + cert_type,
|
||||
success: function (data) {
|
||||
data = data.replace(/\s+/g, ' ');
|
||||
response(data.split(" "));
|
||||
}
|
||||
});
|
||||
},
|
||||
autoFocus: true,
|
||||
minLength: -1
|
||||
});
|
||||
}
|
||||
$("#proxy_pass-upstream").autocomplete({
|
||||
source: function (request, response) {
|
||||
let server = $("#add-proxy_pass select[name='server'] option:selected");
|
||||
if (!checkIsServerFiled("#add-proxy_pass select[name='server'] option:selected")) return false;
|
||||
$.ajax({
|
||||
url: "/add/get/upstreams/" + server.val(),
|
||||
success: function (data) {
|
||||
data = data.replace(/\s+/g, ' ');
|
||||
response(data.split(" "));
|
||||
}
|
||||
});
|
||||
},
|
||||
autoFocus: true,
|
||||
minLength: -1
|
||||
});
|
||||
$("#add5").on("click", function () {
|
||||
$("#tabs").tabs("option", "active", 3);
|
||||
});
|
||||
});
|
||||
var header_option = '<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="new_header_p">\n' +
|
||||
'<select name="headers_res">' +
|
||||
'<option value="------">------</option>' +
|
||||
'<option value="add_header">add_header</option>' +
|
||||
'<option value="proxy_set_header">proxy_set_header</option>' +
|
||||
'<option value="proxy_hide_header">proxy_hide_header</option>' +
|
||||
'</select>' +
|
||||
'\t<b class="padding10">'+name_word+'</b>' +
|
||||
'\t<input name="header_name" class="form-control">' +
|
||||
'\t<b class="padding10">'+value_word+'</b>' +
|
||||
'\t<input name="header_value" class="form-control">' +
|
||||
'\t<span class="minus minus-style" id="new_header_minus" title="Delete this header"></span>' +
|
||||
'</p>'
|
||||
function make_actions_for_adding_header(section_id) {
|
||||
let random_id = makeid(3);
|
||||
$(section_id).append(header_option);
|
||||
$('#new_header_minus').attr('onclick', 'deleteId(\''+random_id+'\')');
|
||||
$('#new_header_minus').attr('id', '');
|
||||
$('#new_header_p').attr('id', random_id);
|
||||
$('#new_header_minus').attr('id', '');
|
||||
$.getScript(awesome);
|
||||
$( "select" ).selectmenu();
|
||||
$('[name=headers_method]').selectmenu({width: 180});
|
||||
}
|
||||
function deleteId(id) {
|
||||
$('#' + id).remove();
|
||||
}
|
||||
function resetProxySettings() {
|
||||
$('[name=upstream]').val('');
|
||||
$('[name=name]').val('');
|
||||
$('input:checkbox').prop("checked", false);
|
||||
$('[name=check-servers]').prop("checked", true);
|
||||
$('input:checkbox').checkboxradio("refresh");
|
||||
$('.advance-show').fadeIn();
|
||||
$('.advance').fadeOut();
|
||||
$('[name=mode').val('http');
|
||||
$('select').selectmenu('refresh');
|
||||
$("#path-cert-listen").attr('required', false);
|
||||
$("#path-cert-frontend").attr('required', false);
|
||||
}
|
||||
function checkIsServerFiled(select_id, message = 'Select a server first') {
|
||||
if ($(select_id).val() == null || $(select_id).val() == '') {
|
||||
toastr.warning(message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function generateConfig(form_name) {
|
||||
let frm = $('#' + form_name);
|
||||
if (form_name == 'add-upstream') {
|
||||
serv = '#serv'
|
||||
name_id = '#name'
|
||||
}
|
||||
if (!checkIsServerFiled(serv)) return false;
|
||||
if (!checkIsServerFiled(name_id, 'The name cannot be empty')) return false;
|
||||
let input = $("<input>")
|
||||
.attr("name", "generateconfig").val("1").attr("type", "hidden").attr("id", "generateconfig");
|
||||
$('#' + form_name + ' input[name=acl_then_value]').each(function () {
|
||||
if (!$(this).val()) {
|
||||
$(this).val('IsEmptY')
|
||||
}
|
||||
});
|
||||
$('#' + form_name + ' input[name=ip]').each(function () {
|
||||
if (!$(this).val()) {
|
||||
$(this).val('IsEmptY')
|
||||
}
|
||||
});
|
||||
$('#' + form_name + ' input[name=port]').each(function () {
|
||||
if (!$(this).val()) {
|
||||
$(this).val('IsEmptY')
|
||||
}
|
||||
});
|
||||
frm.append(input);
|
||||
let generated_title = translate_div.attr('data-generated_config');
|
||||
$.ajax({
|
||||
url: frm.attr('action'),
|
||||
data: frm.serialize(),
|
||||
type: frm.attr('method'),
|
||||
success: function (data) {
|
||||
if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1') {
|
||||
toastr.clear();
|
||||
toastr.error(data);
|
||||
} else {
|
||||
$('#dialog-confirm-body').text(data);
|
||||
$("#dialog-confirm-cert").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 650,
|
||||
modal: true,
|
||||
title: generated_title,
|
||||
buttons: {
|
||||
Ok: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#generateconfig").remove();
|
||||
$('#' + form_name + ' input[name=ip]').each(function () {
|
||||
if ($(this).val() == 'IsEmptY') {
|
||||
$(this).val('')
|
||||
}
|
||||
});
|
||||
$('#' + form_name + ' input[name=port]').each(function () {
|
||||
if ($(this).val() == 'IsEmptY') {
|
||||
$(this).val('')
|
||||
}
|
||||
});
|
||||
}
|
||||
function addProxy(form_name) {
|
||||
function addProxy(form_name, generate = false) {
|
||||
let frm = $('#'+form_name);
|
||||
if (form_name == 'add-upstream') {
|
||||
serv = '#serv'
|
||||
name_id = '#name'
|
||||
let serv = '#serv1';
|
||||
let name_id = '';
|
||||
if (form_name === 'add-upstream') {
|
||||
serv = '#serv2'
|
||||
name_id = '#upstream-name'
|
||||
} else if (form_name === 'add-proxy_pass') {
|
||||
serv = '#serv1'
|
||||
name_id = '#proxy_pass'
|
||||
}
|
||||
if(!checkIsServerFiled(serv)) return false;
|
||||
if(!checkIsServerFiled(name_id, 'The name cannot be empty')) return false;
|
||||
$('#'+form_name +' input[name=ip]').each(function(){
|
||||
if ($(this).val().length === 0){
|
||||
$(this).val('IsEmptY')
|
||||
}
|
||||
});
|
||||
$('#'+form_name +' input[name=port]').each(function(){
|
||||
if ($(this).val().length === 0){
|
||||
$(this).val('IsEmptY')
|
||||
}
|
||||
});
|
||||
let json_data = getNginxFormData(frm, form_name);
|
||||
let section_type = form_name.split('-')[1]
|
||||
let q_generate = '';
|
||||
if (generate) {
|
||||
q_generate = '?generate=1';
|
||||
}
|
||||
$.ajax({
|
||||
url: frm.attr('action'),
|
||||
data: frm.serialize(),
|
||||
url: '/add/nginx/' + $(serv).val() + '/section/' + section_type + q_generate,
|
||||
data: JSON.stringify(json_data),
|
||||
type: frm.attr('method'),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function( data ) {
|
||||
data = data.replace(/\n/g, "<br>");
|
||||
if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1') {
|
||||
returnNiceCheckingConfig(data);
|
||||
} else if (data == '') {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data.error)
|
||||
} else if (data === '') {
|
||||
toastr.clear();
|
||||
toastr.error('error: Proxy cannot be empty');
|
||||
toastr.error('error: Something went wrong. Check configuration');
|
||||
} else {
|
||||
toastr.clear();
|
||||
returnNiceCheckingConfig(data);
|
||||
toastr.info('Section has been added. Do not forget to restart the server');
|
||||
resetProxySettings();
|
||||
if (generate) {
|
||||
$('#dialog-confirm-body').text(data.data);
|
||||
let generated_title = translate_div.attr('data-generated_config');
|
||||
$("#dialog-confirm-cert").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 650,
|
||||
modal: true,
|
||||
title: generated_title,
|
||||
buttons: {
|
||||
Ok: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
toastr.clear();
|
||||
data.data = data.data.replace(/\n/g, "<br>");
|
||||
if (returnNiceCheckingConfig(data.data) === 0) {
|
||||
toastr.info('Section has been added. Do not forget to restart the server');
|
||||
resetProxySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#'+form_name +' input[name=ip]').each(function(){
|
||||
if ($(this).val() == 'IsEmptY'){
|
||||
$(this).val('')
|
||||
}
|
||||
function getNginxFormData($form, form_name) {
|
||||
let section_type = form_name.split('-')[1]
|
||||
let unindexed_array = $form.serializeArray();
|
||||
let indexed_array = {};
|
||||
indexed_array['locations'] = [];
|
||||
indexed_array['backend_servers'] = [];
|
||||
let headers = [];
|
||||
|
||||
$.map(unindexed_array, function (n, i) {
|
||||
if (n['name'] === 'location') {
|
||||
let location = $('input[name="location"]').val();
|
||||
let proxy_connect_timeout = $('input[name="proxy_connect_timeout"]').val();
|
||||
let proxy_read_timeout = $('input[name="proxy_read_timeout"]').val();
|
||||
let proxy_send_timeout = $('input[name="proxy_send_timeout"]').val();
|
||||
let upstream = $('input[name="upstream"]').val();
|
||||
$('#header_div p').each(function () {
|
||||
let action = $(this).children().children('select[name="headers_res"] option:selected').val();
|
||||
let name = $(this).children('input[name="header_name"]').val();
|
||||
let value = $(this).children('input[name="header_value"]').val();
|
||||
if (action === '------') {
|
||||
return;
|
||||
}
|
||||
if (name === '') {
|
||||
return;
|
||||
}
|
||||
let header = {action, name, value};
|
||||
headers.push(header);
|
||||
});
|
||||
let location_config = {location, proxy_connect_timeout, proxy_read_timeout, proxy_send_timeout, headers, upstream};
|
||||
indexed_array['locations'].push(location_config)
|
||||
} else if (n['name'] === 'ssl_offloading') {
|
||||
if ($('input[name="ssl_offloading"]').is(':checked')) {
|
||||
indexed_array['ssl_offloading'] = true;
|
||||
} else {
|
||||
indexed_array['ssl_offloading'] = false;
|
||||
}
|
||||
} else {
|
||||
indexed_array[n['name']] = n['value'];
|
||||
}
|
||||
});
|
||||
$('#'+form_name +' input[name=port]').each(function(){
|
||||
if ($(this).val() == 'IsEmptY'){
|
||||
$(this).val('')
|
||||
$('#'+form_name+' span[name="add_servers"] p').each(function (){
|
||||
let server = $(this).children("input[name='servers']").val();
|
||||
if (server === undefined || server === '') {
|
||||
return;
|
||||
}
|
||||
let port = $(this).children("input[name='server_port']").val();
|
||||
let max_fails = $(this).children("input[name='max_fails']").val();
|
||||
let fail_timeout = $(this).children("input[name='fail_timeout']").val();
|
||||
let test_var = {server, port, max_fails, fail_timeout};
|
||||
indexed_array['backend_servers'].push(test_var);
|
||||
});
|
||||
}
|
||||
let elementsForDelete = [
|
||||
'servers', 'server_port', 'max_fails', 'fail_timeout', 'proxy_connect_timeout', 'proxy_read_timeout', 'proxy_send_timeout',
|
||||
'headers_res', 'header_name', 'header_value', 'upstream', 'server'
|
||||
]
|
||||
for (let element of elementsForDelete) {
|
||||
delete indexed_array[element]
|
||||
}
|
||||
return indexed_array;
|
||||
}
|
||||
function createSsl(TabId) {
|
||||
$('[name=port]').val('443');
|
||||
$("#tabs").tabs("option", "active", TabId);
|
||||
$("#hide-scheme").show("fast");
|
||||
$('#scheme').val('https');
|
||||
$('#ssl_offloading').prop("checked", true);
|
||||
$('input:checkbox').checkboxradio("refresh");
|
||||
$("#ssl_key").attr('required', true);
|
||||
if (TabId === 1) {
|
||||
TabId = '';
|
||||
}
|
||||
$("#serv" + TabId).selectmenu("open");
|
||||
$("#scheme").selectmenu("refresh");
|
||||
history.pushState('Add proxy pass', 'Add proxy pass', 'nginx#proxypass')
|
||||
}
|
||||
|
|
|
@ -284,9 +284,9 @@ function openSection(section) {
|
|||
}
|
||||
});
|
||||
}
|
||||
function delete_section(section_type, section_name, server_id) {
|
||||
function delete_section(section_type, section_name, server_id, service) {
|
||||
$.ajax({
|
||||
url: '/add/haproxy/' + server_id + '/section/' + section_type + '/' + section_name,
|
||||
url: '/add/' + service + '/' + server_id + '/section/' + section_type + '/' + section_name,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
method: "DELETE",
|
||||
statusCode: {
|
||||
|
@ -415,6 +415,7 @@ function editProxy(form_name, dialog_id, generate=false) {
|
|||
toastr.info('Section has been updated. Do not forget to restart the server');
|
||||
let ip = $('select[name=serv]').val();
|
||||
localStorage.setItem('restart', ip);
|
||||
$('#edit-section').remove();
|
||||
showConfig();
|
||||
$(dialog_id).dialog( "close" );
|
||||
}
|
||||
|
@ -647,25 +648,219 @@ function getFormData($form, form_name) {
|
|||
}
|
||||
return indexed_array;
|
||||
}
|
||||
function confirmDeleteSection(section_type, section_name, serv_val, dialog_id) {
|
||||
$( "#dialog-confirm" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: delete_word + " " + section_name + "?",
|
||||
buttons: [{
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
delete_section(section_type, section_name, serv_val);
|
||||
dialog_id.dialog("close");
|
||||
}
|
||||
}, {
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}]
|
||||
});
|
||||
function confirmDeleteSection(section_type, section_name, serv_val, dialog_id, service='haproxy') {
|
||||
$("#dialog-confirm").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: delete_word + " " + section_name + "?",
|
||||
buttons: [{
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
delete_section(section_type, section_name, serv_val, service);
|
||||
dialog_id.dialog("close");
|
||||
}
|
||||
}, {
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
function openNginxSection(section) {
|
||||
let section_type = section.split('_')[0];
|
||||
let section_name = section.split('_')[1];
|
||||
if (section_type === 'proxy-pass') {
|
||||
section_type = 'proxy_pass';
|
||||
}
|
||||
let url = '/add/nginx/' + $('#serv').val() + '/section/' + section_type + '/' + section_name;
|
||||
clearEditNginxSection();
|
||||
$.ajax({
|
||||
url: url,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
statusCode: {
|
||||
404: function (xhr) {
|
||||
window.open('/config/nginx/' + $('#serv').val() + '/edit/' + $('#config_file_name').val(), '_blank').focus();
|
||||
}
|
||||
},
|
||||
async: false,
|
||||
success: function (data) {
|
||||
$('.advance-show-button').click(function () {
|
||||
$('.advance').fadeIn();
|
||||
$('.advance-show-button').css('display', 'none');
|
||||
$('.advance-hide-button').css('display', 'block');
|
||||
return false;
|
||||
});
|
||||
$('.advance-hide-button').click(function () {
|
||||
$('.advance').fadeOut();
|
||||
$('.advance-show-button').css('display', 'block');
|
||||
$('.advance-hide-button').css('display', 'none');
|
||||
return false;
|
||||
});
|
||||
let section_id = '#add-' + section_type;
|
||||
$.getScript(awesome);
|
||||
$('#edit-' + section_type).show();
|
||||
$('#edit-' + section_type + ' caption').hide();
|
||||
$('#' + section_type + '-add-buttons').hide();
|
||||
let i = 0;
|
||||
Object.keys(data.config).forEach(function (key) {
|
||||
if ($(section_id + ' *[name="' + key + '"]').prop("tagName") === 'SELECT') {
|
||||
$(section_id + ' select[name="' + key + '"]').val(data.config[key]).change();
|
||||
} else if ($(section_id + ' *[name="' + key + '"]').prop("tagName") === 'TEXTAREA') {
|
||||
$(section_id + ' select[name="' + key + '"]').val(data.config['option']).change();
|
||||
} else {
|
||||
if ($(section_id + ' *[name="' + key + '"]').prop('type') === 'checkbox') {
|
||||
if (data.config[key]) {
|
||||
$(section_id + ' input[name="' + key + '"]').prop("checked", true);
|
||||
}
|
||||
} else {
|
||||
$(section_id + ' input[name="' + key + '"]').val(data.config[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (section_type === 'upstream') {
|
||||
if (data.config.backend_servers) {
|
||||
if (data.config.backend_servers.length > 3) {
|
||||
for (let i = 2; i < data.config.backend_servers.length; i++) {
|
||||
$("[name=add_servers]").append(add_server_nginx_var);
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
if (data.config.backend_servers.length > 0) {
|
||||
for (let bind of data.config.backend_servers) {
|
||||
$(section_id + ' input[name="servers"]').get(i).value = bind.server;
|
||||
$(section_id + ' input[name="server_port"]').get(i).value = bind.port;
|
||||
$(section_id + ' input[name="max_fails"]').get(i).value = bind.max_fails;
|
||||
$(section_id + ' input[name="fail_timeout"]').get(i).value = bind.fail_timeout;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (section_type === 'proxy_pass') {
|
||||
for (let location of data.locations) {
|
||||
if (location.headers) {
|
||||
if (location.length > 0) {
|
||||
i = 0;
|
||||
$("#add_header").on("click", function () {
|
||||
$("#header_div").show();
|
||||
$("#add_header").show();
|
||||
$("#add_header").hide();
|
||||
});
|
||||
$('#add_header').trigger('click');
|
||||
for (let header of data.config.headers) {
|
||||
make_actions_for_adding_header('#header_div')
|
||||
let headers_res_id = $(section_id + ' select[name="headers_res"]').get(i).id;
|
||||
$('#' + headers_res_id).val(header.path).change();
|
||||
$(section_id + ' input[name="header_name"]').get(i).value = header.name;
|
||||
$(section_id + ' input[name="header_value"]').get(i).value = header.value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#proxy_connect_timeout').val(location.proxy_connect_timeout);
|
||||
$('#proxy_read_timeout').val(location.proxy_read_timeout);
|
||||
$('#proxy_send_timeout').val(location.proxy_send_timeout);
|
||||
$('#proxy_pass-upstream').val(location.upstream);
|
||||
}
|
||||
if (data.compression) {
|
||||
$('#compression').prop("checked", true);
|
||||
$("#compression-options").show("fast");
|
||||
$('#compression_types').val(data.compression_types);
|
||||
$('#compression_min_length').val(data.compression_min_length);
|
||||
$('#compression_level').val(data.compression_level);
|
||||
} else {
|
||||
$('#compression').prop("checked", false);
|
||||
$("#compression-options").hide("fast");
|
||||
}
|
||||
if (data.scheme === 'https') {
|
||||
$('#scheme').val('https');
|
||||
$('#hide-scheme').show();
|
||||
$("#scheme").selectmenu();
|
||||
$("#scheme").selectmenu('refresh');
|
||||
}
|
||||
}
|
||||
$(section_id + ' select[name="server"]').selectmenu();
|
||||
$(section_id + ' select[name="server"]').selectmenu('refresh');
|
||||
$("input[type=checkbox]").checkboxradio();
|
||||
$("input[type=checkbox]").checkboxradio('refresh');
|
||||
$(section_id + ' select[name="server"]').val(data.server_id).change();
|
||||
$(section_id + ' select[name="server"]').selectmenu('disable').parent().parent().hide();
|
||||
$(section_id + ' input[name="name"]').prop("readonly", true).parent().parent().hide();
|
||||
let buttons = [{
|
||||
text: edit_word,
|
||||
click: function () {
|
||||
editNginxProxy('add-' + section_type, $(this));
|
||||
}
|
||||
}, {
|
||||
text: delete_word,
|
||||
click: function () {
|
||||
confirmDeleteSection(section_type, section_name, $('#serv').val(), $(this), 'nginx');
|
||||
}
|
||||
}, {
|
||||
text: cancel_word,
|
||||
click: function () {
|
||||
$(this).dialog("close");
|
||||
$('#edit-' + section_type).hide();
|
||||
}
|
||||
}]
|
||||
$("#edit-section").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 1100,
|
||||
modal: true,
|
||||
title: edit_word,
|
||||
close: function () {
|
||||
$('#edit-' + section_type).hide();
|
||||
},
|
||||
buttons: buttons
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function clearEditNginxSection() {
|
||||
$('#edit-section').empty();
|
||||
$.ajax({
|
||||
url: "/add/nginx/get_section_html",
|
||||
method: "GET",
|
||||
async: false,
|
||||
success: function(data) {
|
||||
$('#edit-section').html(data);
|
||||
$.getScript('/static/js/add_nginx.js');
|
||||
},
|
||||
})
|
||||
}
|
||||
function editNginxProxy(form_name, dialog_id, generate=false) {
|
||||
let frm = $('#'+form_name);
|
||||
let name_id = '#' +form_name + ' input[name="name"]';
|
||||
if(!checkIsServerFiled(name_id, 'The name cannot be empty')) return false;
|
||||
let json_data = getNginxFormData(frm, form_name);
|
||||
let section_type = form_name.split('-')[1]
|
||||
let url = '/add/nginx/' + $('#serv').val() + '/section/' + section_type + '/' + $(name_id).val();
|
||||
$.ajax({
|
||||
url: url,
|
||||
data: JSON.stringify(json_data),
|
||||
type: 'PUT',
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: function( data ) {
|
||||
if (data.status === 'failed') {
|
||||
toastr.error(data.error)
|
||||
} else if (data === '') {
|
||||
toastr.clear();
|
||||
toastr.error('error: Something went wrong. Check configuration');
|
||||
} else {
|
||||
toastr.clear();
|
||||
data.data = data.data.replace(/\n/g, "<br>");
|
||||
if (returnNiceCheckingConfig(data.data) === 0) {
|
||||
toastr.info('Section has been updated. Do not forget to restart the server');
|
||||
showConfig();
|
||||
$('#edit-section').remove();
|
||||
$(dialog_id).dialog( "close" );
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -703,7 +703,7 @@ $( function() {
|
|||
});
|
||||
$(".installmon").on("click", function () {
|
||||
$('.menu li ul li').each(function () {
|
||||
activeSubMenu($(this), 'instalmon');
|
||||
activeSubMenu($(this), 'installmon');
|
||||
});
|
||||
$("#tabs").tabs("option", "active", 1);
|
||||
});
|
||||
|
@ -845,41 +845,41 @@ async function ban() {
|
|||
$("input[type=submit], button").button('enable');
|
||||
$('#ban_10').hide();
|
||||
}
|
||||
function replace_text(id_textarea, text_var) {
|
||||
var str = $(id_textarea).val();
|
||||
var len = str.length;
|
||||
var len_var = text_var.length;
|
||||
var beg = str.indexOf(text_var);
|
||||
var end = beg + len_var
|
||||
var text_val = str.substring(0, beg) + str.substring(end, len);
|
||||
$(id_textarea).text(text_val);
|
||||
}
|
||||
function createHistroy() {
|
||||
// function replace_text(id_textarea, text_var) {
|
||||
// var str = $(id_textarea).val();
|
||||
// var len = str.length;
|
||||
// var len_var = text_var.length;
|
||||
// var beg = str.indexOf(text_var);
|
||||
// var end = beg + len_var
|
||||
// var text_val = str.substring(0, beg) + str.substring(end, len);
|
||||
// $(id_textarea).text(text_val);
|
||||
// }
|
||||
function createHistory() {
|
||||
if(localStorage.getItem('history') === null) {
|
||||
var get_history_array = ['login', 'login','login'];
|
||||
let get_history_array = ['login', 'login','login'];
|
||||
localStorage.setItem('history', JSON.stringify(get_history_array));
|
||||
}
|
||||
}
|
||||
function listHistroy() {
|
||||
var browse_history = JSON.parse(localStorage.getItem('history'));
|
||||
var history_link = '';
|
||||
var title = []
|
||||
var link_text = []
|
||||
var cur_path = window.location.pathname;
|
||||
function listHistory() {
|
||||
let browse_history = JSON.parse(localStorage.getItem('history'));
|
||||
let history_link = '';
|
||||
let title = []
|
||||
let link_text = []
|
||||
let cur_path = window.location.pathname;
|
||||
for(let i = 0; i < browse_history.length; i++){
|
||||
if (i == 0) {
|
||||
if (i === 0) {
|
||||
browse_history[0] = browse_history[1];
|
||||
}
|
||||
if (i == 1) {
|
||||
if (i === 1) {
|
||||
browse_history[1] = browse_history[2]
|
||||
}
|
||||
if (i == 2) {
|
||||
if (i === 2) {
|
||||
browse_history[2] = cur_path
|
||||
}
|
||||
$( function() {
|
||||
$('.menu li ul li').each(function () {
|
||||
var link1 = $(this).find('a').attr('href');
|
||||
if (browse_history[i].replace(/\/$/, "") == link1) {
|
||||
let link1 = $(this).find('a').attr('href');
|
||||
if (browse_history[i].replace(/\/$/, "") === link1) {
|
||||
title[i] = $(this).find('a').attr('title');
|
||||
link_text[i] = $(this).find('a').text();
|
||||
history_link = '<li><a href="'+browse_history[i]+'" title="'+title[i]+'">'+link_text[i]+'</a></li>'
|
||||
|
@ -890,8 +890,8 @@ function listHistroy() {
|
|||
}
|
||||
localStorage.setItem('history', JSON.stringify(browse_history));
|
||||
}
|
||||
createHistroy();
|
||||
listHistroy();
|
||||
createHistory();
|
||||
listHistory();
|
||||
|
||||
function changeCurrentGroupF(user_id) {
|
||||
$.ajax({
|
||||
|
@ -909,14 +909,14 @@ function changeCurrentGroupF(user_id) {
|
|||
});
|
||||
}
|
||||
function updateTips( t ) {
|
||||
var tips = $( ".validateTips" );
|
||||
let tips = $( ".validateTips" );
|
||||
tips.text( t ).addClass( "alert-warning" );
|
||||
tips.text( t ).addClass( "alert-one-row" );
|
||||
}
|
||||
function clearTips() {
|
||||
var tips = $( ".validateTips" );
|
||||
let tips = $( ".validateTips" );
|
||||
tips.html('Fields marked "<span class="need-field">*</span>" are required').removeClass( "alert-warning" );
|
||||
allFields = $( [] ).add( $('#new-server-add') ).add( $('#new-ip') ).add( $('#new-port')).add( $('#new-username') ).add( $('#new-password') )
|
||||
let allFields = $( [] ).add( $('#new-server-add') ).add( $('#new-ip') ).add( $('#new-port')).add( $('#new-username') ).add( $('#new-password') )
|
||||
allFields.removeClass( "ui-state-error" );
|
||||
}
|
||||
function checkLength( o, n, min ) {
|
||||
|
@ -1382,3 +1382,63 @@ function makeid(length) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
const INSTALLATION_TASKS_KEY = 'installationTasks';
|
||||
function getInstallationTasksFromSessionStorage() {
|
||||
const tasks = sessionStorage.getItem(INSTALLATION_TASKS_KEY);
|
||||
return tasks ? JSON.parse(tasks) : [];
|
||||
}
|
||||
function addItemToSessionStorageInstallTask(taskId) {
|
||||
if (!sessionStorage.getItem(INSTALLATION_TASKS_KEY)) {
|
||||
sessionStorage.setItem(INSTALLATION_TASKS_KEY, JSON.stringify([])); // Создаем пустой массив
|
||||
}
|
||||
let tasks = getInstallationTasksFromSessionStorage();
|
||||
|
||||
tasks.push(taskId);
|
||||
|
||||
sessionStorage.setItem(INSTALLATION_TASKS_KEY, JSON.stringify(tasks));
|
||||
}
|
||||
function removeItemFromSessionStorage(taskId) {
|
||||
let tasks = getInstallationTasksFromSessionStorage();
|
||||
|
||||
tasks = tasks.filter(item => item !== taskId);
|
||||
|
||||
sessionStorage.setItem(INSTALLATION_TASKS_KEY, JSON.stringify(tasks));
|
||||
}
|
||||
|
||||
function checkInstallationTask() {
|
||||
let tasks = getInstallationTasksFromSessionStorage(); // Извлекаем список
|
||||
if (tasks && tasks.length > 0) {
|
||||
tasks.forEach(item => {
|
||||
checkInstallationStatus(item);
|
||||
});
|
||||
} else {
|
||||
console.log('No tasks');
|
||||
clearInterval(checkInstallationTaskInterval);
|
||||
}
|
||||
}
|
||||
function runInstallationTaskCheck(tasks_ids) {
|
||||
toastr.info('Installation started. You can continue to use the system while it is installing');
|
||||
tasks_ids.forEach(item => {
|
||||
addItemToSessionStorageInstallTask(item);
|
||||
setTimeout(function () {
|
||||
setInterval(checkInstallationTask, 3000);
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
function checkInstallationStatus(taskId) {
|
||||
NProgress.configure({showSpinner: false});
|
||||
$.ajax({
|
||||
url: "/install/task-status/" + taskId,
|
||||
success: function (data) {
|
||||
if (data.status === 'completed') {
|
||||
toastr.success('Installation completed for ' + data.service_name);
|
||||
removeItemFromSessionStorage(taskId);
|
||||
} else if (data.status === 'failed') {
|
||||
toastr.error('Cannot install ' + data.service_name + '. Error: ' + data.error);
|
||||
removeItemFromSessionStorage(taskId);
|
||||
}
|
||||
}
|
||||
});
|
||||
NProgress.configure({showSpinner: true});
|
||||
}
|
||||
let checkInstallationTaskInterval = setInterval(checkInstallationTask, 3000);
|
||||
|
|
|
@ -40,3 +40,8 @@ const add_userlist_var = '<p><input name="userlist-user" title="User name" place
|
|||
const add_peer_var = '<p><input name="servers_name" required title="Peer name" size=14 placeholder="haproxyN" class="form-control">: ' +
|
||||
'<input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server">: ' +
|
||||
'<input name="server_port" required title="Backend port" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number"></p>'
|
||||
const add_server_nginx_var = '<p><input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server" style="margin: 2px 0 4px 0;">: ' +
|
||||
'<input name="server_port" required title="Backend port" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number"> ' +
|
||||
'max_fails: <input name="max_fails" required title="By default, the number of unsuccessful attempts is set to 1" size=5 value="1" class="form-control add_server_number" type="number">' +
|
||||
' fail_timeout: <input name="fail_timeout" required title="By default, the number of unsuccessful attempts is set to 1" size=5 value="1" class="form-control add_server_number" type="number">s ' +
|
||||
' <span class="minus minus-style" id="" title="Remove the server" onclick="$(this).parent().remove()"></span></p>'
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
{% set header_params = {'add-header': 'add-header', 'set-header': 'set-header', 'del-header': 'del-header'} %}
|
||||
{% set if_values = {'1':'Host name starts with','2':'Host name ends with','3':'Path starts with','4':'Path ends with', '6': 'Src ip'} %}
|
||||
{% set force_close = {'0':'Off','1':'Server only','2':'Force close','3':'Pretend keep alive'} %}
|
||||
|
||||
{% if user_subscription.user_status == 0 %}
|
||||
{% include 'include/no_sub.html' %}
|
||||
{% else %}
|
||||
<script src="/static/js/add.js"></script>
|
||||
<script src="/static/js/add_common.js"></script>
|
||||
<script src="/static/js/edit_config.js"></script>
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
|
@ -100,52 +103,7 @@
|
|||
</div>
|
||||
|
||||
<div id="add-servers">
|
||||
<table class="overview" id="servers_table">
|
||||
<tr class="overviewHead">
|
||||
<td class="padding10 first-collumn">{{lang.words.server|title()}}</td>
|
||||
<td class="padding10 first-collumn">{{lang.words.desc|title()}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for s in saved_servers %}
|
||||
<tr id="servers-saved-{{ s.id }}" class="{{ loop.cycle('odd', 'even') }}">
|
||||
{% if s.groups|string() == g.user_params['group_id']|string() or group|string() == '1' %}
|
||||
<td class="padding10 first-collumn">
|
||||
<input type="text" id="servers-ip-{{ s.id }}" value="{{ s.server }}" size="15" class="form-control">
|
||||
</td>
|
||||
<td class="padding10 first-collumn" style="width: 77%;">
|
||||
<input type="text" id="servers-desc-{{ s.id }}" value="{{ s.description }}" size="50" class="form-control">
|
||||
</td>
|
||||
<td>
|
||||
<a class="delete" onclick="confirmDeleteSavedServer({{ s.id }})" title="{{lang.words.delete|title()}} {{lang.words.server}} {{s.server}}" style="cursor: pointer;"></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.server}}" id="add-saved-server-button">+ {{lang.words.add|title()}}</span>
|
||||
<br /><br />
|
||||
<table class="overview" id="saved-server-add-table" style="display: none;">
|
||||
<tr class="overviewHead">
|
||||
<td class="padding10 first-collumn">{{lang.words.server|title()}}</td>
|
||||
<td>{{lang.words.desc|title()}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="padding10 first-collumn">
|
||||
{{ input('new-saved-servers', size='15') }}
|
||||
</td>
|
||||
<td style="width: 77%;">
|
||||
{{ input('new-saved-servers-description', size='50') }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="add-admin" id="add-saved-server-new" title="{{lang.words.add|title()}} {{lang.words.new|title()}} {{lang.words.server|title()}}" style="cursor: pointer;"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="ajax-servers"></div>
|
||||
<div class="add-note alert addName alert-info" style="width: inherit; margin-right: 15px;">
|
||||
{{lang.add_page.desc.servers}}
|
||||
</div>
|
||||
{% include 'include/add/servers.html' %}
|
||||
</div>
|
||||
<div id="userlist">
|
||||
{% include 'include/add/userlist.html' %}
|
||||
|
@ -299,4 +257,5 @@ for (var i = 0; i <= serv_ports.length; i++) {
|
|||
'This can be done easily in HAProxy by adding the keyword backup on the server line. If multiple backup servers are configured, only the first active one is used.">backup</label><input type="checkbox" name="backup" value="1" id="' + uniqId + '">');
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,75 +3,30 @@
|
|||
{% block h2 %}{{lang.menu_links.add_proxy.title}}{% endblock %}
|
||||
{% block content %}
|
||||
{% from 'include/input_macros.html' import input, checkbox, select %}
|
||||
{% set balance_params = dict() %}
|
||||
{% set balance_params = {'ip_hash':'ip_hash','least_conn':'least_conn','random':'random', 'round_robin': 'round-robin'} %}
|
||||
<script src="/static/js/add_nginx.js"></script>
|
||||
<script src="/static/js/add_common.js"></script>
|
||||
{% if user_subscription.user_status == 0 %}
|
||||
{% include 'include/no_sub.html' %}
|
||||
{% else %}
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#create" title="{{lang.words.add|title()}} {{lang.words.proxy}}: {{lang.words.add|title()}} {{lang.words.proxy}} - Roxy-WI">{{lang.words.add|title()}} {{lang.words.proxy}}</a></li>
|
||||
<li><a href="#proxypass" title="{{lang.words.add|title()}} {{lang.words.proxy}}: {{lang.words.add|title()}} Proxy pass - Roxy-WI">{{lang.words.add|title()}} Proxy pass</a></li>
|
||||
<li><a href="#upstream" title="{{lang.words.add|title()}} {{lang.words.proxy}}: {{lang.words.create|title()}} {{lang.words.upstream|title()}} - Roxy-WI">{{lang.words.upstream|title()}}</a></li>
|
||||
<li><a href="#add-servers" title="{{lang.words.add|title()}} {{lang.words.proxy}}: {{lang.words.servers|title()}} {{lang.words.templates}} - Roxy-WI">{{lang.words.servers|title()}}</a></li>
|
||||
</ul>
|
||||
<ul id='browse_histroy'></ul>
|
||||
{% include 'include/add_nginx_proxy.html' %}
|
||||
<div id="upstream">
|
||||
<form name="add-upstream" id="add-upstream" action="/add/nginx/upstream" method="post">
|
||||
<table class="add-table">
|
||||
<caption><h3>{{lang.words.add|title()}} upstream</h3></caption>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
|
||||
<td class="addOption">
|
||||
{{ select('serv', values=g.user_params['servers'], is_servers='true') }}
|
||||
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
|
||||
</td>
|
||||
<td rowspan="5" class="add-note addName alert-info">
|
||||
{{lang.add_nginx_page.desc.upstream_desc1}}
|
||||
<br /><br />
|
||||
{{lang.add_nginx_page.desc.upstream_desc2}}
|
||||
<br /><br />
|
||||
{{lang.add_nginx_page.desc.upstream_desc3}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.name|title()}}:</td>
|
||||
<td class="addOption">
|
||||
{{ input('name', name='upstream', title="Name upstream", placeholder="backend_servers", required='required') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance">
|
||||
<td class="addName">{{lang.words.balance|title()}}: </td>
|
||||
<td class="addOption">
|
||||
{{ select('balance', values=balance_params, selected='round-robin', required='required', class='force_close') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance">
|
||||
<td class="addName"><span title="{{lang.add_nginx_page.desc.keepalive}}" data-help="{{lang.add_nginx_page.desc.keepalive}}">Keepalive:</span></td>
|
||||
<td class="addOption">
|
||||
{{ input('name', name='keepalive', title=lang.add_nginx_page.desc.keepalive, placeholder="32") }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.servers|title()}}:</td>
|
||||
<td class="addOption">
|
||||
{% include 'include/add_nginx_servers.html' %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance-show">
|
||||
<td class="addOption" colspan="2">
|
||||
<button title="{{lang.add_page.buttons.show_full_settings}}" class="row-down advance-show-button">{{lang.words.show|title()}} {{lang.words.advanced}} {{lang.words.settings}}</button>
|
||||
<button title="{{lang.add_page.buttons.hide_full_settings}}" class="row-up advance-hide-button" style="display: none">{{lang.words.hide|title()}} {{lang.words.advanced}} {{lang.words.settings}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.add|title()}} {{lang.words.upstream|title()}}" onclick="addProxy('add-upstream')">{{lang.words.add|title()}}</a>
|
||||
</td>
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.generate|title()}} {{lang.words.and}} {{lang.words.display}} {{lang.words.config}}" onclick="generateConfig('add-upstream')">{{lang.words.generate|title()}} {{lang.words.config}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{% include 'include/add_nginx/add_nginx_proxy.html' %}
|
||||
<div id="proxypass">
|
||||
{% include 'include/add_nginx/proxy_pass.html' %}
|
||||
</div>
|
||||
<div id="upstream">
|
||||
{% include 'include/add_nginx/upstream.html' %}
|
||||
</div>
|
||||
<div id="add-servers">
|
||||
{% include 'include/add/servers.html' %}
|
||||
</div>
|
||||
<div id="dialog-confirm-cert-edit" title="View certificate " style="display: none;">
|
||||
<span><b>Note:</b> Each new address must be specified from a new line</span>
|
||||
<textarea id="edit_lists" style="width: 100%" rows=20></textarea>
|
||||
|
@ -81,6 +36,7 @@
|
|||
</div>
|
||||
<input type="hidden" id="group_id" value="{{ g.user_params['group_id'] }}">
|
||||
</div>
|
||||
{% include 'include/del_confirm.html' %}
|
||||
<script>
|
||||
$( function() {
|
||||
if (window.matchMedia('(max-width: 1280px)').matches || window.matchMedia('(max-width: 1024px)').matches || window.matchMedia('(max-width: 667px)').matches) {
|
||||
|
@ -90,4 +46,5 @@ $( function() {
|
|||
}
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
{% if role <= 3 %}
|
||||
{% if not is_serv_protected or role <= 2 %}
|
||||
{% if not configver %}
|
||||
{% if service != 'nginx' %}
|
||||
<a class="ui-button ui-widget ui-corner-all" title="Edit this run config" id="edit_link" href="/config/{{service}}/{{serv}}/edit/{{config_file_name}}">{{lang.words.edit|title()}}</a>
|
||||
{% else %}
|
||||
<a class="ui-button ui-widget ui-corner-all" title="Edit this run config" id="edit_link" onclick="openNginxSection('{{config_file_name.split("92")[-1].split(".conf")[0]}}')">{{lang.words.edit|title()}}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if service == 'haproxy' %}
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.add|title()}} {{lang.words.proxy}}" href="/add/haproxy#proxy">{{lang.words.add|title()}}</a>
|
||||
|
@ -76,6 +80,12 @@
|
|||
</span><div>
|
||||
{% continue %}
|
||||
{% endif %}
|
||||
{%- if "upstream {" in line -%}
|
||||
</div>
|
||||
<span class="param">{{ line }}
|
||||
</span><div>
|
||||
{% continue %}
|
||||
{% endif %}
|
||||
|
||||
{% if "listen " in line or "location" in line or "server_name" in line or "}" in line %}
|
||||
{% if "#" not in line %}
|
||||
|
@ -379,6 +389,7 @@
|
|||
{%- endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if configver %}
|
||||
<br>
|
||||
{% if role <= 3 %}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{% import 'languages/'+lang|default('en')+'.html' as lang %}
|
||||
{% from 'include/input_macros.html' import input, checkbox, select %}
|
||||
{% set balance_params = {'ip_hash':'ip_hash','least_conn':'least_conn','random':'random', 'round_robin': 'round-robin'} %}
|
||||
<div id="edit-proxy_pass" style="display: none;">
|
||||
{% include 'include/add_nginx/proxy_pass.html' %}
|
||||
</div>
|
||||
<div id="edit-upstream" style="display: none;">
|
||||
{% include 'include/add_nginx/upstream.html' %}
|
||||
</div>
|
|
@ -0,0 +1,46 @@
|
|||
<table class="overview" id="servers_table">
|
||||
<tr class="overviewHead">
|
||||
<td class="padding10 first-collumn">{{lang.words.server|title()}}</td>
|
||||
<td class="padding10 first-collumn">{{lang.words.desc|title()}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for s in saved_servers %}
|
||||
<tr id="servers-saved-{{ s.id }}" class="{{ loop.cycle('odd', 'even') }}">
|
||||
{% if s.groups|string() == g.user_params['group_id']|string() or group|string() == '1' %}
|
||||
<td class="padding10 first-collumn">
|
||||
<input type="text" id="servers-ip-{{ s.id }}" value="{{ s.server }}" size="15" class="form-control">
|
||||
</td>
|
||||
<td class="padding10 first-collumn" style="width: 77%;">
|
||||
<input type="text" id="servers-desc-{{ s.id }}" value="{{ s.description }}" size="50" class="form-control">
|
||||
</td>
|
||||
<td>
|
||||
<a class="delete" onclick="confirmDeleteSavedServer({{ s.id }})" title="{{lang.words.delete|title()}} {{lang.words.server}} {{s.server}}" style="cursor: pointer;"></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.server}}" id="add-saved-server-button">+ {{lang.words.add|title()}}</span>
|
||||
<br /><br />
|
||||
<table class="overview" id="saved-server-add-table" style="display: none;">
|
||||
<tr class="overviewHead">
|
||||
<td class="padding10 first-collumn">{{lang.words.server|title()}}</td>
|
||||
<td>{{lang.words.desc|title()}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="padding10 first-collumn">
|
||||
{{ input('new-saved-servers', size='15') }}
|
||||
</td>
|
||||
<td style="width: 77%;">
|
||||
{{ input('new-saved-servers-description', size='50') }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="add-admin" id="add-saved-server-new" title="{{lang.words.add|title()}} {{lang.words.new|title()}} {{lang.words.server|title()}}" style="cursor: pointer;"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="ajax-servers"></div>
|
||||
<div class="add-note alert addName alert-info" style="width: inherit; margin-right: 15px;">
|
||||
{{lang.add_page.desc.servers}}
|
||||
</div>
|
|
@ -0,0 +1,62 @@
|
|||
{% if add %}
|
||||
<div class="alert alert-success" style="position: absolute;top: 45px;left: 5px;">
|
||||
<div id="close">
|
||||
<span title="Close" style="cursor: pointer; float: right;">X</span>
|
||||
</div>
|
||||
<h3>{{ add }} {{lang.add_page.desc.was_success_added}}</h3>
|
||||
{{ conf_add }}
|
||||
</div>
|
||||
<script>
|
||||
$('#close').click(function(){
|
||||
$('.alert-success').remove();
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
<div id="create" style="margin-top: 20px;">
|
||||
<div id="left-collumn">
|
||||
<div class="div-pannel">
|
||||
<div class="div-server add-proxy-listen-head">
|
||||
<div class="server-name">
|
||||
<span title="{{lang.words.create|title()}} Proxy pass" class="redirectProxyPass span-link">{{lang.words.create|title()}} HTTP proxy pass</span>
|
||||
</div>
|
||||
<div class="server-desc add_proxy">
|
||||
{{lang.add_page.desc.create_nginx_proxy}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-pannel">
|
||||
<div class="div-server add-proxy-listen-head">
|
||||
<div class="server-name">
|
||||
<span title="{{lang.words.create|title()}} Proxy pass" class="redirectProxyPass span-link" id="create-ssl-proxy_pass">{{lang.words.create|title()}} HTTPS proxy pass</span>
|
||||
</div>
|
||||
<div class="server-desc add_proxy">
|
||||
{{lang.add_page.desc.create_nginx_ssl_proxy}} <a href="{{ url_for('service.ssl_service', service='nginx') }}" target="_blank">{{lang.words.uploaded}} {{lang.words.w_a}} PEM {{lang.words.cert}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="middle-collumn">
|
||||
<div class="div-pannel">
|
||||
<div class="div-server add-proxy-frontend-head">
|
||||
<div class="server-name">
|
||||
<span title="{{lang.words.create|title()}} {{lang.words.upstream|title()}}" class="redirectUpstream span-link">{{lang.words.create|title()}} {{lang.words.upstream|title()}}</span>
|
||||
</div>
|
||||
<div class="server-desc add_proxy">
|
||||
{{lang.add_nginx_page.desc.upstream_desc1}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-pannel">
|
||||
<div class="div-server add-proxy-frontend-head">
|
||||
<div class="server-name">
|
||||
<span title="{{lang.words.create|title()}} {{lang.words.w_a}} {{lang.words.server}} {{lang.words.template}}" class="span-link" id="add5">{{lang.words.create|title()}} {{lang.words.w_a}} {{lang.words.server}} {{lang.words.template}}</span>
|
||||
</div>
|
||||
<div class="server-desc add_proxy">
|
||||
{{lang.add_page.desc.server_temp}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right-collumn">
|
||||
</div>
|
||||
</div>
|
|
@ -4,20 +4,24 @@
|
|||
}
|
||||
</style>
|
||||
<span name="add_servers">
|
||||
<p>
|
||||
<input name="servers" required title="{{lang.words.backend|title()}} IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control">:
|
||||
<input name="server_port" required title="{{lang.words.backend|title()}} {{lang.words.port}}" size=8 placeholder="yyy" class="form-control add_server_number" type="number">
|
||||
<span name="max_fails">max_fails:</span> <input name="max_fails" required title="" data-help="{{lang.add_nginx_page.desc.max_fails}}" size=8 class="form-control add_server_number" value="1" type="number">
|
||||
<span name="fail_timeout">fail_timeout:</span> <input name="fail_timeout" required size=8 value="1" class="form-control add_server_number" type="number" title="" data-help="{{lang.add_nginx_page.desc.fail_timeout}}">s
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
<input name="servers" title="{{lang.words.backend|title()}} IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server"><span class="second-server">:</span>
|
||||
<input name="server_port" title="{{lang.words.backend|title()}} {{lang.words.port}}" size=8 placeholder="yyy" class="form-control second-server add_server_number" type="number">
|
||||
<span name="max_fails">max_fails:</span> <input name="max_fails" required title="" data-help="{{lang.add_nginx_page.desc.max_fails}}" size=8 class="form-control add_server_number" value="1" type="number">
|
||||
<span name="fail_timeout">fail_timeout:</span> <input name="fail_timeout" required size=8 value="1" class="form-control add_server_number" type="number" title="" data-help="{{lang.add_nginx_page.desc.fail_timeout}}">s
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
<input name="servers" title="{{lang.words.backend|title()}} IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server"><span class="second-server">:</span>
|
||||
<input name="server_port" title="{{lang.words.backend|title()}} {{lang.words.port}}" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number">
|
||||
<span name="max_fails">max_fails:</span> <input name="max_fails" required size=8 class="form-control add_server_number" value="1" type="number" title="" data-help="{{lang.add_nginx_page.desc.max_fails}}">
|
||||
<span name="fail_timeout">fail_timeout:</span> <input name="fail_timeout" required size=8 value="1" class="form-control add_server_number" type="number" title="" data-help="{{lang.add_nginx_page.desc.fail_timeout}}">s
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<a class="link add-server backend_server" name="add-server-input" title="{{lang.words.add|title()}} upstream" style="cursor: pointer;"></a>
|
|
@ -0,0 +1,123 @@
|
|||
{% set header_res = {'add_header': 'add_header', 'proxy_set_header': 'proxy_set_header', 'proxy_hide_header': 'proxy_hide_header'} %}
|
||||
<style>
|
||||
.proxy-timeout {
|
||||
width: 140px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
<form name="add-proxy_pass" id="add-proxy_pass" action="/add/nginx/proxy_pass" method="post">
|
||||
<table class="add-table">
|
||||
<caption><h3>{{lang.words.add|title()}} proxy pass</h3></caption>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
|
||||
<td class="addOption">
|
||||
{{ select('serv1', name='server', values=g.user_params['servers'], is_servers='true', by_id='true') }}
|
||||
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
|
||||
</td>
|
||||
<td rowspan="5" class="add-note addName alert-info">
|
||||
Proxy pass is a Nginx directive that forwards incoming client requests to a specified backend server (like Apache, Node.js, or a microservice) and relays the response back to the client. It supports protocols like HTTP, HTTPS, WebSocket, and gRPC, making it versatile for reverse proxying. Key parameters include:
|
||||
<br />
|
||||
<br />
|
||||
Header control: Uses proxy_set_header to forward client IP (X-Real-IP) or protocol (X-Forwarded-Proto).
|
||||
<br />
|
||||
<br />
|
||||
Timeouts: Timeouts (proxy_connect_timeout).
|
||||
<br />
|
||||
<br />
|
||||
(Summary: It’s the backbone of Nginx reverse proxying, handling routing, balancing, and security.)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.name|title()}}:</td>
|
||||
<td class="addOption">
|
||||
{{ input('proxy_pass', name='name', title="Domain name or IP", placeholder="example.com", required='required') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">
|
||||
HTTP {{lang.words.scheme|title()}}:
|
||||
</td>
|
||||
<td class="addOption">
|
||||
{% set scheme_params={'http': 'HTTP', 'https': 'HTTPS'} %}
|
||||
{{ select('scheme', values=scheme_params, selected='http', required='required', class='force_close') }}
|
||||
<br>
|
||||
<br>
|
||||
<div id="hide-scheme" style="display: none;">
|
||||
{{ checkbox('ssl_offloading', title=lang.add_page.desc.http_https, desc='HTTP->HTTPS') }}<br>
|
||||
<span class="tooltip tooltipTop">{{lang.words.enter2|title()}} {{lang.words.name}} {{lang.words.of}} {{lang.words.file2}}, {{lang.add_page.desc.press_down}}:</span><br />
|
||||
{{ input('ssl_key', placeholder='cert.key') }}
|
||||
{{ input('ssl_crt', placeholder='cert.crt') }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">
|
||||
{{lang.words.port|title()}}:
|
||||
</td>
|
||||
<td class="addOption">
|
||||
{{ input('port', name='port', title='Port to bind', placeholder="80", required='required', type='number', style='width: 40px;') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">Location:</td>
|
||||
<td class="addOption nginx-location">
|
||||
<p>
|
||||
{{ input('location', name='location', title="Location", value="/", required='required') }}
|
||||
<br>
|
||||
<br>
|
||||
<span class="proxy-timeout">Proxy connect timeout:</span>
|
||||
{{ input('proxy_connect_timeout', name='proxy_connect_timeout', title='Proxy connect timeout', value="60", type='number', style='width: 40px;') }}
|
||||
<br>
|
||||
<span class="proxy-timeout">Proxy read timeout:</span>
|
||||
{{ input('proxy_read_timeout', name='proxy_read_timeout', title='Proxy read timeout', value="60", type='number', style='width: 40px;') }}
|
||||
<br>
|
||||
<span class="proxy-timeout">Proxy send timeout:</span>
|
||||
{{ input('proxy_send_timeout', name='proxy_send_timeout', title='Proxy send timeout', value="60", type='number', style='width: 40px;') }}<br><br>
|
||||
{{lang.words.headers|title()}}: <span title="{{lang.words.add|title()}} {{lang.words.headers}}" id="show_header" class="link add-server"></span>
|
||||
<div id="header_div" style="display: none;">
|
||||
<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="header_p">
|
||||
{{ select('headers_res', name='headers_res', values=header_res, first='------', class='force_close') }}
|
||||
<b class="padding10">{{lang.words.name}}</b>
|
||||
{{ input('header_name', name="header_name") }}
|
||||
<b class="padding10">{{lang.words.value}}</b>
|
||||
{{ input('header_value', name="header_value") }}
|
||||
<span class="minus minus-style" onclick="deleteId('header_p')" title="{{lang.words.delete|title()}}"></span>
|
||||
</p>
|
||||
</div>
|
||||
<span>
|
||||
<a class="link add-server" id="add_header" title="{{lang.words.add|title()}} {{lang.words.headers}}" style="display: none;"></a>
|
||||
</span>
|
||||
<br>
|
||||
Upstream: {{ input('proxy_pass-upstream', name='upstream', placeholder='upstream_config') }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{ lang.words.compression|title() }}:</td>
|
||||
<td class="addOption">
|
||||
{{ checkbox('compression', title=lang.add_page.desc.http_compression, value='true', desc=lang.words.compression|title()) }}
|
||||
<div id="compression-options" style="display: none;">
|
||||
<span class="proxy-timeout">{{ lang.words.types|title() }}:</span>
|
||||
{{ input('compression_types', value='text/plain text/css application/json application/javascript text/xml', style='width: 250px;') }}<br>
|
||||
<span class="proxy-timeout">{{ lang.words.min|title() }} {{ lang.words.length }}:</span>
|
||||
{{ input('compression_min_length', value='1024', type='number', style='width: 50px;') }}<br>
|
||||
<span class="proxy-timeout">{{ lang.words.level|title() }}:</span>
|
||||
{{ input('compression_level', value='6', type='number', style='width: 50px;') }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="proxy_pass-add-buttons">
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.add|title()}} proxy pass" onclick="addProxy('add-proxy_pass')">{{lang.words.add|title()}}</a>
|
||||
</td>
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.generate|title()}} {{lang.words.and}} {{lang.words.display}} {{lang.words.config}}" onclick="addProxy('add-proxy_pass', generate=true)">{{lang.words.generate|title()}} {{lang.words.config}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<script>
|
||||
$("#scheme" ).selectmenu({
|
||||
width: 100
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,57 @@
|
|||
<form name="add-upstream" id="add-upstream" action="/add/nginx/upstream" method="post">
|
||||
<table class="add-table">
|
||||
<caption><h3>{{lang.words.add|title()}} upstream</h3></caption>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
|
||||
<td class="addOption">
|
||||
{{ select('serv2', name='server', values=g.user_params['servers'], is_servers='true', by_id='true') }}
|
||||
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
|
||||
</td>
|
||||
<td rowspan="5" class="add-note addName alert-info">
|
||||
{{lang.add_nginx_page.desc.upstream_desc1}}
|
||||
<br /><br />
|
||||
{{lang.add_nginx_page.desc.upstream_desc2}}
|
||||
<br /><br />
|
||||
{{lang.add_nginx_page.desc.upstream_desc3}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.name|title()}}:</td>
|
||||
<td class="addOption">
|
||||
{{ input('upstream-name', name='name', title="Name upstream", placeholder="backend_servers", required='required') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance">
|
||||
<td class="addName">{{lang.words.balance|title()}}: </td>
|
||||
<td class="addOption">
|
||||
{{ select('balance', values=balance_params, selected='round_robin', required='required', class='force_close') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance">
|
||||
<td class="addName"><span title="{{lang.add_nginx_page.desc.keepalive}}" data-help="{{lang.add_nginx_page.desc.keepalive}}">Keepalive:</span></td>
|
||||
<td class="addOption">
|
||||
{{ input('keepalive', name='keepalive', title=lang.add_nginx_page.desc.keepalive, value="32") }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="addName">{{lang.words.servers|title()}}:</td>
|
||||
<td class="addOption">
|
||||
{% include 'include/add_nginx/add_nginx_servers.html' %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="advance-show">
|
||||
<td class="addOption" colspan="2">
|
||||
<button title="{{lang.add_page.buttons.show_full_settings}}" class="row-down advance-show-button">{{lang.words.show|title()}} {{lang.words.advanced}} {{lang.words.settings}}</button>
|
||||
<button title="{{lang.add_page.buttons.hide_full_settings}}" class="row-up advance-hide-button" style="display: none">{{lang.words.hide|title()}} {{lang.words.advanced}} {{lang.words.settings}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="upstream-add-buttons">
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.add|title()}} {{lang.words.upstream|title()}}" onclick="addProxy('add-upstream')">{{lang.words.add|title()}}</a>
|
||||
</td>
|
||||
<td class="addButton">
|
||||
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.generate|title()}} {{lang.words.and}} {{lang.words.display}} {{lang.words.config}}" onclick="addProxy('add-upstream', generate=true)">{{lang.words.generate|title()}} {{lang.words.config}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
|
@ -1,32 +0,0 @@
|
|||
{% if add %}
|
||||
<div class="alert alert-success" style="position: absolute;top: 45px;left: 5px;">
|
||||
<div id="close">
|
||||
<span title="Close" style="cursor: pointer; float: right;">X</span>
|
||||
</div>
|
||||
<h3>{{ add }} {{lang.add_page.desc.was_success_added}}</h3>
|
||||
{{ conf_add }}
|
||||
</div>
|
||||
<script>
|
||||
$('#close').click(function(){
|
||||
$('.alert-success').remove();
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
<div id="create" style="margin-top: 20px;">
|
||||
<div id="left-collumn">
|
||||
<div class="div-pannel">
|
||||
<div class="div-server add-proxy-listen-head">
|
||||
<div class="server-name">
|
||||
<span title="{{lang.words.create|title()}} {{lang.words.upstream|title()}}" class="redirectUpstream span-link">{{lang.words.create|title()}} {{lang.words.upstream|title()}}</span>
|
||||
</div>
|
||||
<div class="server-desc add_proxy">
|
||||
{{lang.add_nginx_page.desc.upstream_desc1}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="middle-collumn">
|
||||
</div>
|
||||
<div id="right-collumn">
|
||||
</div>
|
||||
</div>
|
|
@ -405,6 +405,8 @@
|
|||
"server_temp": "Create, edit and delete servers. And after use them as autocomplete in the 'Add' sections",
|
||||
"use_add": "And use it in the 'Add' sections",
|
||||
"comma_separated": "You can specify several, separated by a comma or a space",
|
||||
"create_nginx_ssl_proxy": "Create HTTPS Proxy with the SSL termination on NGINX and SSL offload. NGINX will send to backends HTTP traffic. You need have",
|
||||
"create_nginx_proxy": "Proxy pass in Nginx forwards client requests to a specified backend server (like Node.js or Python) and returns the response to the client. It’s the core directive for reverse proxying, enabling load balancing, SSL termination, and routing traffic to different services.",
|
||||
},
|
||||
"buttons": {
|
||||
"disable_ssl_check": "Disable SSL check",
|
||||
|
@ -962,5 +964,8 @@
|
|||
"theme": "theme",
|
||||
"dark": "dark",
|
||||
"light": "light",
|
||||
"types": "types",
|
||||
"min": "minimum",
|
||||
"length": "length",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -405,6 +405,8 @@
|
|||
"server_temp": "Créer, modifier et supprimer des serveurs. Et par la suite, utilisez-les en tant que liste déroulante dans les sections 'Ajouter'",
|
||||
"use_add": "Et utilisez-le dans les sections 'Ajouter'.",
|
||||
"comma_separated": "Vous pouvez en spécifier plusieurs, séparés par une virgule ou un espace",
|
||||
"create_nginx_ssl_proxy": "Créez un proxy HTTPS avec terminaison SSL sur NGINX et déchargement SSL. NGINX enverra le trafic HTTP aux backends. Vous devez disposer dee",
|
||||
"create_nginx_proxy": "Dans Nginx, la commande proxy transmet les requêtes client à un serveur back-end spécifique (comme Node.js ou Python) et renvoie la réponse au client. Il s'agit de la directive principale pour le proxy inverse, permettant l'équilibrage de charge, la terminaison SSL et le routage du trafic vers différents services.",
|
||||
},
|
||||
"buttons": {
|
||||
"disable_ssl_check": "Désactiver la vérification SSL",
|
||||
|
@ -962,5 +964,8 @@
|
|||
"theme": "thème",
|
||||
"dark": "sombre",
|
||||
"light": "léger",
|
||||
"types": "types",
|
||||
"min": "minimum",
|
||||
"length": "longueur",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -405,6 +405,8 @@
|
|||
"server_temp": "Crie, edite e exclua servidores com determinados parâmetros. Usá-los como preenchimento automático nas seções 'Adicionar'",
|
||||
"use_add": "Usa isso as seções 'Adicionar'",
|
||||
"comma_separated": "Você pode especificar vários, separados por uma vírgula ou um espaço",
|
||||
"create_nginx_ssl_proxy": "Crie um proxy HTTPS com terminação SSL no NGINX e descarregamento SSL. O NGINX enviará tráfego HTTP para os backends. Você precisa terw",
|
||||
"create_nginx_proxy": "A passagem de proxy no Nginx encaminha solicitações do cliente para um servidor backend especificado (como Node.js ou Python) e retorna a resposta ao cliente. É a diretiva principal para proxy reverso, permitindo balanceamento de carga, terminação SSL e roteamento de tráfego para diferentes serviços.",
|
||||
},
|
||||
"buttons": {
|
||||
"disable_ssl_check": "Ativar a verificação de SSL",
|
||||
|
@ -962,5 +964,8 @@
|
|||
"theme": "thema",
|
||||
"dark": "escuro",
|
||||
"light": "claro",
|
||||
"types": "tipos",
|
||||
"min": "mínima",
|
||||
"length": "comprimento",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -405,6 +405,8 @@
|
|||
"server_temp": "Создание, редактирование и удаление серверов. И после использовать их как автозаполнение в разделах «Добавить прокси»",
|
||||
"use_add": "И использовать их в разделах «Добавить прокси»",
|
||||
"comma_separated": "Можно указать несколько, разделенных запятой, либо пробелом",
|
||||
"create_nginx_ssl_proxy": "Создайте HTTPS-прокси с терминацией SSL на NGINX и разгрузкой SSL. NGINX будет отправлять на серверные части HTTP-трафик. Вам нужно иметь",
|
||||
"create_nginx_proxy": "Прокси-передача в Nginx перенаправляет клиентские запросы на указанный бэкенд-сервер (например, Node.js или Python) и возвращает ответ клиенту. Это основная директива для обратного проксирования, включающая балансировку нагрузки, терминацию SSL и маршрутизацию трафика на различные сервисы.",
|
||||
},
|
||||
"buttons": {
|
||||
"disable_ssl_check": "Отключить проверку SSL",
|
||||
|
@ -962,5 +964,8 @@
|
|||
"theme": "тема",
|
||||
"dark": "темная",
|
||||
"light": "светлая",
|
||||
"types": "типы",
|
||||
"min": "минимальная",
|
||||
"length": "длина",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -64,7 +64,7 @@ class HaproxySectionView(MethodView):
|
|||
if query.generate:
|
||||
cfg = '/tmp/haproxy-generated-config.cfg'
|
||||
os.system(f'touch {cfg}')
|
||||
inv = service_mod.generate_haproxy_section_inv(body.model_dump(mode='json'), cfg)
|
||||
inv = service_mod.generate_section_inv(body.model_dump(mode='json'), cfg, service)
|
||||
|
||||
try:
|
||||
output = service_mod.run_ansible_locally(inv, 'haproxy_section')
|
||||
|
@ -153,15 +153,17 @@ class HaproxySectionView(MethodView):
|
|||
def _edit_config(service, server: Server, body: HaproxyConfigRequest, action: Literal['create', 'delete'], **kwargs) -> str:
|
||||
cfg = config_common.generate_config_path(service, server.ip)
|
||||
if action == 'create':
|
||||
inv = service_mod.generate_haproxy_section_inv(body.model_dump(mode='json'), cfg)
|
||||
inv = service_mod.generate_section_inv(body.model_dump(mode='json'), cfg, service)
|
||||
else:
|
||||
inv = service_mod.generate_haproxy_section_inv_for_del(cfg, kwargs.get('section_type'), kwargs.get('section_name'))
|
||||
inv = service_mod.generate_section_inv_for_del(cfg, kwargs.get('section_type'), kwargs.get('section_name'))
|
||||
|
||||
try:
|
||||
config_mod.get_config(server.ip, cfg, service=service)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
os.system(f'cp {cfg} {cfg}.old')
|
||||
|
||||
try:
|
||||
output = service_mod.run_ansible_locally(inv, 'haproxy_section')
|
||||
except Exception as e:
|
||||
|
@ -176,7 +178,7 @@ class HaproxySectionView(MethodView):
|
|||
else:
|
||||
action = 'save'
|
||||
|
||||
output = config_mod.master_slave_upload_and_restart(server.ip, cfg, action, 'haproxy')
|
||||
output = config_mod.master_slave_upload_and_restart(server.ip, cfg, action, 'haproxy', oldcfg=f'{cfg}.old')
|
||||
|
||||
return output
|
||||
|
||||
|
|
|
@ -0,0 +1,883 @@
|
|||
import os
|
||||
from typing import Union, Literal
|
||||
|
||||
from flask.views import MethodView
|
||||
from flask_pydantic import validate
|
||||
from flask import jsonify, g
|
||||
from flask_jwt_extended import jwt_required
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
import app.modules.db.sql as sql
|
||||
import app.modules.db.add as add_sql
|
||||
import app.modules.db.server as server_sql
|
||||
import app.modules.server.ssh as mod_ssh
|
||||
import app.modules.config.config as config_mod
|
||||
import app.modules.config.common as config_common
|
||||
import app.modules.service.installation as service_mod
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
from app.middleware import get_user_params, page_for_admin, check_group, check_services
|
||||
from app.modules.db.db_model import Server
|
||||
from app.modules.roxywi.class_models import BaseResponse, DataStrResponse, NginxUpstreamRequest, IdDataStrResponse, \
|
||||
ErrorResponse, GenerateConfigRequest, NginxProxyPassRequest
|
||||
from app.modules.common.common_classes import SupportClass
|
||||
|
||||
|
||||
class NginxSectionView(MethodView):
|
||||
methods = ['GET', 'POST', 'PUT', 'DELETE']
|
||||
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
|
||||
|
||||
@staticmethod
|
||||
def get(service: Literal['nginx'], section_type: str, section_name: str, server_id: Union[int, str]):
|
||||
try:
|
||||
server_id = SupportClass().return_server_ip_or_id(server_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, '')
|
||||
|
||||
try:
|
||||
server_sql.get_server_with_group(server_id, g.user_params['group_id'])
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
|
||||
|
||||
try:
|
||||
section = add_sql.get_section(server_id, section_type, section_name, service)
|
||||
output = {'server_id': section.server_id.server_id, **model_to_dict(section, recurse=False),
|
||||
'id': f'{server_id}-{section_name}'}
|
||||
output.update(section.config)
|
||||
return jsonify(output)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get NGINX section')
|
||||
|
||||
def post(self,
|
||||
service: Literal['nginx'],
|
||||
section_type: str,
|
||||
server_id: Union[int, str],
|
||||
body: Union[NginxUpstreamRequest, NginxProxyPassRequest],
|
||||
query: GenerateConfigRequest
|
||||
):
|
||||
try:
|
||||
server_id = SupportClass().return_server_ip_or_id(server_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, '')
|
||||
|
||||
try:
|
||||
server = server_sql.get_server_with_group(server_id, g.user_params['group_id'])
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
|
||||
if query.generate:
|
||||
cfg = '/tmp/nginx-generated-config.conf'
|
||||
os.system(f'touch {cfg}')
|
||||
inv = service_mod.generate_section_inv(body.model_dump(mode='json'), cfg, service)
|
||||
|
||||
try:
|
||||
output = service_mod.run_ansible_locally(inv, 'nginx_section')
|
||||
if len(output['failures']) > 0 or len(output['dark']) > 0:
|
||||
raise Exception('Cannot create NGINX section. Check Apache error log')
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, f'Cannot create NGINX section: {e}')
|
||||
try:
|
||||
with open(cfg, 'r') as file:
|
||||
conf = file.read()
|
||||
except Exception as e:
|
||||
raise Exception(f'error: Cannot read config file: {e}')
|
||||
try:
|
||||
os.remove(cfg)
|
||||
except Exception:
|
||||
pass
|
||||
return DataStrResponse(data=conf).model_dump(mode='json'), 200
|
||||
|
||||
try:
|
||||
output = self._edit_config(service, server, body, 'create')
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create NGINX section')
|
||||
|
||||
if 'Fatal' in output or 'error' in output:
|
||||
return ErrorResponse(error=output).model_dump(mode='json'), 500
|
||||
|
||||
try:
|
||||
add_sql.insert_new_section(server_id, section_type, body.name, body, service)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot add NGINX section')
|
||||
|
||||
return IdDataStrResponse(data=output, id=f'{server_id}-{body.name}').model_dump(mode='json'), 201
|
||||
|
||||
def put(self,
|
||||
service: Literal['nginx'],
|
||||
section_type: str,
|
||||
section_name: str,
|
||||
server_id: Union[int, str],
|
||||
body: Union[NginxUpstreamRequest, NginxProxyPassRequest]
|
||||
):
|
||||
try:
|
||||
server_id = SupportClass().return_server_ip_or_id(server_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, '')
|
||||
|
||||
try:
|
||||
server = server_sql.get_server_with_group(server_id, g.user_params['group_id'])
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
|
||||
|
||||
try:
|
||||
output = self._edit_config(service, server, body, 'create')
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create HAProxy section')
|
||||
|
||||
if 'Fatal' in output or 'error' in output:
|
||||
return ErrorResponse(error=output).model_dump(mode='json'), 500
|
||||
else:
|
||||
try:
|
||||
add_sql.update_section(server_id, section_type, section_name, body, service)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update NGINX section')
|
||||
|
||||
return DataStrResponse(data=output).model_dump(mode='json'), 201
|
||||
|
||||
def delete(self, service: Literal['nginx'], section_type: str, section_name: str, server_id: Union[int, str]):
|
||||
try:
|
||||
server_id = SupportClass().return_server_ip_or_id(server_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, '')
|
||||
|
||||
try:
|
||||
server = server_sql.get_server_with_group(server_id, g.user_params['group_id'])
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
|
||||
|
||||
try:
|
||||
config_file_name = self._create_config_path(service, section_type, section_name)
|
||||
with mod_ssh.ssh_connect(server.ip) as ssh:
|
||||
ssh.remove_sftp(config_file_name)
|
||||
add_sql.delete_section(server_id, section_type, section_name, service)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete NGINX section')
|
||||
|
||||
return BaseResponse().model_dump(mode='json'), 204
|
||||
|
||||
@staticmethod
|
||||
def _create_config_path(service: str, config_type: str, name: str) -> str:
|
||||
service_dir = sql.get_setting(f'{service}_dir')
|
||||
if config_type == 'upstream':
|
||||
config_file_name = f'{service_dir}/conf.d/upstream_{name}.conf'
|
||||
else:
|
||||
config_file_name = f'{service_dir}/sites-enabled/proxy-pass_{name}.conf'
|
||||
return config_file_name
|
||||
|
||||
def _edit_config(self, service, server: Server, body: NginxUpstreamRequest, action: Literal['create', 'delete'], **kwargs) -> str:
|
||||
cfg = config_common.generate_config_path(service, server.ip)
|
||||
print('cfg', cfg)
|
||||
config_file_name = self._create_config_path(service, body.type, body.name)
|
||||
|
||||
if action == 'create':
|
||||
inv = service_mod.generate_section_inv(body.model_dump(mode='json'), cfg, service)
|
||||
else:
|
||||
inv = service_mod.generate_section_inv_for_del(cfg, kwargs.get('section_type'), kwargs.get('section_name'))
|
||||
|
||||
try:
|
||||
config_mod.get_config(server.ip, cfg, service=service, config_file_name=config_file_name)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
os.system(f'mv {cfg} {cfg}.old')
|
||||
|
||||
try:
|
||||
output = service_mod.run_ansible_locally(inv, 'nginx_section')
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
if len(output['failures']) > 0 or len(output['dark']) > 0:
|
||||
raise Exception('Cannot create NGINX section. Check Apache error log')
|
||||
|
||||
if body:
|
||||
if body.action:
|
||||
action = str(body.action)
|
||||
else:
|
||||
action = 'save'
|
||||
|
||||
output = config_mod.master_slave_upload_and_restart(server.ip, cfg, action, service, config_file_name=config_file_name, oldcfg=f'{cfg}.old')
|
||||
|
||||
return output
|
||||
|
||||
|
||||
class UpstreamSectionView(NginxSectionView):
|
||||
methods = ['GET', 'POST', 'PUT', 'DELETE']
|
||||
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
|
||||
|
||||
def __init__(self):
|
||||
self.section_type = 'upstream'
|
||||
|
||||
@validate()
|
||||
def get(self, service: Literal['nginx'], section_name: str, server_id: Union[int, str]):
|
||||
"""
|
||||
NginxUpstreamView API
|
||||
|
||||
This is the NginxUpstreamView API where you can get configurations of NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX upstream section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of the section to fetch.
|
||||
responses:
|
||||
200:
|
||||
description: NGINX upstream configuration.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
type: object
|
||||
properties:
|
||||
backend_servers:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
server:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
max_fails:
|
||||
type: integer
|
||||
fail_timeout:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
balance:
|
||||
type: string
|
||||
keepalive:
|
||||
type: integer
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
server_id:
|
||||
type: integer
|
||||
type:
|
||||
type: string
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
404:
|
||||
description: Section not found.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().get(service, self.section_type, section_name, server_id)
|
||||
|
||||
@validate(body=NginxUpstreamRequest, query=GenerateConfigRequest)
|
||||
def post(self,
|
||||
service: Literal['nginx'],
|
||||
server_id: Union[int, str],
|
||||
body: NginxUpstreamRequest,
|
||||
query: GenerateConfigRequest
|
||||
):
|
||||
"""
|
||||
NginxUpstreamView API
|
||||
|
||||
This is the NginxUpstreamView API where you can create NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX upstream section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
backend_servers:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
server:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
max_fails:
|
||||
type: integer
|
||||
fail_timeout:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
description: The name of the upstream
|
||||
balance:
|
||||
type: string
|
||||
description: Could be 'round_robin', 'ip_hash', 'least_conn' or 'random'
|
||||
default: round_robin
|
||||
keepalive:
|
||||
type: integer
|
||||
default: 32
|
||||
responses:
|
||||
200:
|
||||
description: NGINX section successfully created.
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().post(service, self.section_type, server_id, body, query)
|
||||
|
||||
@validate(body=NginxUpstreamRequest)
|
||||
def put(self,
|
||||
service: Literal['nginx'],
|
||||
server_id: Union[int, str],
|
||||
section_name: str,
|
||||
body: NginxUpstreamRequest,
|
||||
query: GenerateConfigRequest
|
||||
):
|
||||
"""
|
||||
This is the NginxUpstreamView API where you can update the NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX upstream section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of section to update.
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
backend_servers:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
server:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
max_fails:
|
||||
type: integer
|
||||
fail_timeout:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
description: The name of the upstream to update.
|
||||
balance:
|
||||
type: string
|
||||
description: Could be 'round_robin', 'ip_hash', 'least_conn' or 'random'
|
||||
default: round_robin
|
||||
keepalive:
|
||||
type: integer
|
||||
default: 32
|
||||
responses:
|
||||
200:
|
||||
description: NGINX section successfully created.
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().put(service, self.section_type, section_name, server_id, body)
|
||||
|
||||
@validate()
|
||||
def delete(self, service: Literal['nginx'], section_name: str, server_id: Union[int, str]):
|
||||
"""
|
||||
NginxUpstreamView sections API
|
||||
|
||||
This is the NginxUpstreamView API where you can delete configurations of NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX upstream section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of the section to fetch.
|
||||
responses:
|
||||
204:
|
||||
description: NGINX section configuration.
|
||||
"""
|
||||
return super().delete(service, self.section_type, section_name, server_id)
|
||||
|
||||
|
||||
class ProxyPassSectionView(NginxSectionView):
|
||||
methods = ['GET', 'POST', 'PUT', 'DELETE']
|
||||
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
|
||||
|
||||
def __init__(self):
|
||||
self.section_type = 'proxy_pass'
|
||||
|
||||
@validate()
|
||||
def get(self, service: Literal['nginx'], section_name: str, server_id: Union[int, str]):
|
||||
"""
|
||||
NginxProxyPassView API
|
||||
|
||||
This is the NginxProxyPassView API where you can get configurations of NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX proxy_pass section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of the section to fetch.
|
||||
responses:
|
||||
200:
|
||||
description: Proxy Pass Section details retrieved successfully.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
compression:
|
||||
type: boolean
|
||||
description: Indicates whether compression is enabled.
|
||||
compression_level:
|
||||
type: integer
|
||||
description: Specifies the compression level (from 1 to 9).
|
||||
compression_min_length:
|
||||
type: integer
|
||||
description: Minimum response size in bytes for compression to apply.
|
||||
compression_types:
|
||||
type: string
|
||||
description: MIME types (space-separated) that compression applies to.
|
||||
id:
|
||||
type: string
|
||||
description: Unique ID of the proxy pass section.
|
||||
locations:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
location:
|
||||
type: string
|
||||
description: Path of the location block (e.g., `/`).
|
||||
headers:
|
||||
type: array
|
||||
description: List of headers for the location.
|
||||
items:
|
||||
type: object
|
||||
proxy_connect_timeout:
|
||||
type: integer
|
||||
description: Timeout value for connecting to the upstream server (in seconds).
|
||||
proxy_read_timeout:
|
||||
type: integer
|
||||
description: Timeout for reading data from the upstream server (in seconds).
|
||||
proxy_send_timeout:
|
||||
type: integer
|
||||
description: Timeout for sending data to the upstream server (in seconds).
|
||||
upstream:
|
||||
type: string
|
||||
description: Name of the upstream server.
|
||||
name:
|
||||
type: string
|
||||
description: Name of the proxy pass configuration.
|
||||
port:
|
||||
type: integer
|
||||
description: Port on which this proxy pass runs.
|
||||
scheme:
|
||||
type: string
|
||||
enum:
|
||||
- http
|
||||
- https
|
||||
description: Protocol used by the proxy.
|
||||
server_id:
|
||||
type: integer
|
||||
description: ID of the associated server.
|
||||
ssl_crt:
|
||||
type: string
|
||||
description: SSL certificate file name.
|
||||
ssl_key:
|
||||
type: string
|
||||
description: SSL private key file name.
|
||||
ssl_offloading:
|
||||
type: boolean
|
||||
description: Indicates whether SSL offloading is enabled.
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- proxy_pass
|
||||
description: Section type (e.g., "proxy_pass").
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
404:
|
||||
description: Section not found.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().get(service, self.section_type, section_name, server_id)
|
||||
|
||||
@validate(body=NginxProxyPassRequest, query=GenerateConfigRequest)
|
||||
def post(self,
|
||||
service: Literal['nginx'],
|
||||
server_id: Union[int, str],
|
||||
body: NginxProxyPassRequest,
|
||||
query: GenerateConfigRequest
|
||||
):
|
||||
"""
|
||||
NginxProxyPassView API
|
||||
|
||||
This is the NginxProxyPassView API where you can create NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX proxy_pass section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- locations
|
||||
- name
|
||||
- scheme
|
||||
- port
|
||||
properties:
|
||||
locations:
|
||||
type: array
|
||||
description: List of locations associated with this proxy pass section.
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- location
|
||||
- proxy_connect_timeout
|
||||
- proxy_read_timeout
|
||||
- proxy_send_timeout
|
||||
- upstream
|
||||
properties:
|
||||
location:
|
||||
type: string
|
||||
description: Path of the location block (e.g., `/`).
|
||||
default: /
|
||||
proxy_connect_timeout:
|
||||
type: string
|
||||
description: Timeout value for connecting to the upstream server (in seconds).
|
||||
default: 60
|
||||
proxy_read_timeout:
|
||||
type: string
|
||||
description: Timeout for reading data from the upstream server (in seconds).
|
||||
default: 60
|
||||
proxy_send_timeout:
|
||||
type: string
|
||||
description: Timeout for sending data to the upstream server (in seconds).
|
||||
default: 60
|
||||
headers:
|
||||
type: array
|
||||
description: List of headers for the location (currently empty).
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- action
|
||||
- name
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action to perform on the header (e.g., "add_header").
|
||||
enum:
|
||||
- add_header
|
||||
- proxy_set_header
|
||||
- proxy_hide_header
|
||||
name:
|
||||
type: string
|
||||
description: Name of the header.
|
||||
example: X-Real-IP
|
||||
value:
|
||||
type: string
|
||||
description: Value of the header.
|
||||
upstream:
|
||||
type: string
|
||||
description: Name of the upstream server.
|
||||
name:
|
||||
type: string
|
||||
description: Domain name or IP of the proxy pass section.
|
||||
scheme:
|
||||
type: string
|
||||
enum:
|
||||
- http
|
||||
- https
|
||||
description: Scheme (protocol) for the proxy pass section.
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the proxy pass section operates.
|
||||
ssl_offloading:
|
||||
type: boolean
|
||||
description: Indicates whether SSL offloading is enabled.
|
||||
default: false
|
||||
ssl_key:
|
||||
type: string
|
||||
description: SSL private key file name. Need if scheme is https.
|
||||
ssl_crt:
|
||||
type: string
|
||||
description: SSL certificate file name. Need if scheme is https
|
||||
compression_types:
|
||||
type: string
|
||||
description: Space-separated list of MIME types to be compressed.
|
||||
default: text/plain text/css application/json application/javascript text/xml
|
||||
compression_min_length:
|
||||
type: string
|
||||
description: Minimum response size in bytes for compression to apply.
|
||||
default: 1024
|
||||
compression_level:
|
||||
type: string
|
||||
description: The compression level (e.g., 1 to 9).
|
||||
default: 6
|
||||
responses:
|
||||
200:
|
||||
description: NGINX section successfully created.
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().post(service, self.section_type, server_id, body, query)
|
||||
|
||||
@validate(body=NginxProxyPassRequest)
|
||||
def put(self,
|
||||
service: Literal['nginx'],
|
||||
server_id: Union[int, str],
|
||||
section_name: str,
|
||||
body: NginxProxyPassRequest,
|
||||
query: GenerateConfigRequest
|
||||
):
|
||||
"""
|
||||
This is the NginxProxyPassView API where you can update the NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX proxy_pass section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of section to update.
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- locations
|
||||
- name
|
||||
- scheme
|
||||
- port
|
||||
properties:
|
||||
locations:
|
||||
type: array
|
||||
description: List of locations associated with this proxy pass section.
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- location
|
||||
- proxy_connect_timeout
|
||||
- proxy_read_timeout
|
||||
- proxy_send_timeout
|
||||
- upstream
|
||||
properties:
|
||||
location:
|
||||
type: string
|
||||
description: Path of the location block (e.g., `/`).
|
||||
default: /
|
||||
proxy_connect_timeout:
|
||||
type: string
|
||||
description: Timeout value for connecting to the upstream server (in seconds).
|
||||
default: 60
|
||||
proxy_read_timeout:
|
||||
type: string
|
||||
description: Timeout for reading data from the upstream server (in seconds).
|
||||
default: 60
|
||||
proxy_send_timeout:
|
||||
type: string
|
||||
description: Timeout for sending data to the upstream server (in seconds).
|
||||
default: 60
|
||||
headers:
|
||||
type: array
|
||||
description: List of headers for the location (currently empty).
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- action
|
||||
- name
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action to perform on the header (e.g., "add_header").
|
||||
enum:
|
||||
- add_header
|
||||
- proxy_set_header
|
||||
- proxy_hide_header
|
||||
name:
|
||||
type: string
|
||||
description: Name of the header.
|
||||
example: X-Real-IP
|
||||
value:
|
||||
type: string
|
||||
description: Value of the header.
|
||||
upstream:
|
||||
type: string
|
||||
description: Name of the upstream server.
|
||||
name:
|
||||
type: string
|
||||
description: Domain name or IP of the proxy pass section.
|
||||
scheme:
|
||||
type: string
|
||||
enum:
|
||||
- http
|
||||
- https
|
||||
description: Scheme (protocol) for the proxy pass section.
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the proxy pass section operates.
|
||||
ssl_offloading:
|
||||
type: boolean
|
||||
description: Indicates whether SSL offloading is enabled.
|
||||
default: false
|
||||
ssl_key:
|
||||
type: string
|
||||
description: SSL private key file name. Need if scheme is https.
|
||||
ssl_crt:
|
||||
type: string
|
||||
description: SSL certificate file name. Need if scheme is https
|
||||
compression_types:
|
||||
type: string
|
||||
description: Space-separated list of MIME types to be compressed.
|
||||
default: text/plain text/css application/json application/javascript text/xml
|
||||
compression_min_length:
|
||||
type: string
|
||||
description: Minimum response size in bytes for compression to apply.
|
||||
default: 1024
|
||||
compression_level:
|
||||
type: string
|
||||
description: The compression level (e.g., 1 to 9).
|
||||
default: 6
|
||||
responses:
|
||||
200:
|
||||
description: NGINX section successfully created.
|
||||
400:
|
||||
description: Invalid parameters.
|
||||
500:
|
||||
description: Internal server error.
|
||||
"""
|
||||
return super().put(service, self.section_type, section_name, server_id, body)
|
||||
|
||||
@validate()
|
||||
def delete(self, service: Literal['nginx'], section_name: str, server_id: Union[int, str]):
|
||||
"""
|
||||
NginxProxyPassView sections API
|
||||
|
||||
This is the NginxProxyPassView API where you can delete configurations of NGINX sections.
|
||||
|
||||
---
|
||||
tags:
|
||||
- NGINX proxy_pass section
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- nginx
|
||||
description: The service to which this section belongs.
|
||||
- name: server_id
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Server ID or IP address
|
||||
- name: section_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of the section to fetch.
|
||||
responses:
|
||||
204:
|
||||
description: NGINX section configuration.
|
||||
"""
|
||||
return super().delete(service, self.section_type, section_name, server_id)
|
Loading…
Reference in New Issue