160 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/python3
 | 
						|
 | 
						|
from pathlib import Path
 | 
						|
 | 
						|
from nginx.config.api import (Section, Location, EmptyBlock, Comment,
 | 
						|
                              KeyValueOption, Block)
 | 
						|
from nginx.config.helpers import duplicate_options
 | 
						|
 | 
						|
PROXY_OPTIONS = [
 | 
						|
        ["Host", "$http_host"],
 | 
						|
        ["X-Real-IP", "$remote_addr"],
 | 
						|
        ["X-Forwarded-For", "$proxy_add_x_forwarded_for"],
 | 
						|
        ["X-Forwarded-Host", "$host,443"],
 | 
						|
        ["X-Forwarded-Server", "$host"],
 | 
						|
        ["X-Forwarded-Proto", "$scheme"],
 | 
						|
        ["X-Forwarded-Uri", "$request_uri"],
 | 
						|
        ["X-Forwarded-Ssl", "on"],
 | 
						|
        ["X-Real-IP", "$remote_addr"]
 | 
						|
]
 | 
						|
 | 
						|
FPM_OPTIONS = [
 | 
						|
    ["HTTPS", "on"],
 | 
						|
    ["PATH_INFO", "$path_info"],
 | 
						|
    ["SCRIPT_FILENAME", "$document_root$fastcgi_script_name"],
 | 
						|
    ["modHeadersAvailable", "true"],
 | 
						|
    ["front_controller_active", "true"]
 | 
						|
]
 | 
						|
 | 
						|
PROXY_WEBSOCKETS_OPTIONS = [
 | 
						|
    ["Upgrade", "$http_upgrade"],
 | 
						|
    ["Connection", "Upgrade"]
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
class NginxSiteBuilder:
 | 
						|
 | 
						|
    def __init__(self, domain, site_number=0, root="/srv/www/htdocs",
 | 
						|
                 authelia=True):
 | 
						|
 | 
						|
        self._filename = f"{site_number:02d}-{domain}.conf"
 | 
						|
        self._domain = domain
 | 
						|
        self._add_base_template(authelia)
 | 
						|
        self.add_logging()
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self._config)
 | 
						|
 | 
						|
    __repr__ = __str__
 | 
						|
 | 
						|
    def _add_base_template(self, authelia=True):
 | 
						|
        server = Section(
 | 
						|
            "server",
 | 
						|
            duplicate_options("listen", [["443 ssl http2"],
 | 
						|
                                         ["[::]:443 ssl http2"]]),
 | 
						|
            server_name=self.domain,
 | 
						|
            server_tokens="off"
 | 
						|
        )
 | 
						|
        blocks = [["common_ssl.conf"]]
 | 
						|
        if authelia:
 | 
						|
            blocks.append(["authelia.conf"])
 | 
						|
        includes = duplicate_options("include", blocks)
 | 
						|
        server.sections.add(includes)
 | 
						|
 | 
						|
        self._config = server
 | 
						|
 | 
						|
    @property
 | 
						|
    def filename(self):
 | 
						|
        return self._filename
 | 
						|
 | 
						|
    @property
 | 
						|
    def domain(self):
 | 
						|
        return self._domain
 | 
						|
 | 
						|
    @property
 | 
						|
    def config(self):
 | 
						|
        return self._config
 | 
						|
 | 
						|
    def write(self, path: Path):
 | 
						|
        destination = path / self.filename
 | 
						|
        with destination.open("w") as handle:
 | 
						|
            handle.write(str(self._config))
 | 
						|
 | 
						|
    def add_upstream(self, name="server", host="127.0.0.1", port=5555):
 | 
						|
        upstream = Block(f"upstream %{name}", server=f"{host}:{port}")
 | 
						|
        upstream.sections.add(self._config)
 | 
						|
        self._config = upstream
 | 
						|
 | 
						|
    def add_logging(self, suffix="nginx"):
 | 
						|
 | 
						|
        if isinstance(self.domain, list):
 | 
						|
            domain = self.domain[0].replace(".", "_")
 | 
						|
        else:
 | 
						|
            domain = domain.replace(".", "_")
 | 
						|
 | 
						|
        syslog = f"syslog:server=unix:/dev/log,tag={domain}_{suffix},"
 | 
						|
        access = syslog + "severity=info,nohostname"
 | 
						|
        error = syslog + "severity=error,nohostname"
 | 
						|
 | 
						|
        logs = EmptyBlock(
 | 
						|
            access_log=access,
 | 
						|
            error_log=error)
 | 
						|
        self._config.sections.add(logs)
 | 
						|
 | 
						|
    def add_proxied_location(self, location="/", address="127.0.0.1",
 | 
						|
                             port=8443, websocket=True, auth=True):
 | 
						|
 | 
						|
        location = Location(location,
 | 
						|
                            proxy_pass=f"http://{address}:{port}",
 | 
						|
                            gzip="off")
 | 
						|
 | 
						|
        if auth:
 | 
						|
            location.sections.add(KeyValueOption("include", "auth.conf"))
 | 
						|
 | 
						|
        proxy_options = duplicate_options(
 | 
						|
            "proxy_set_header",
 | 
						|
            PROXY_OPTIONS
 | 
						|
            )
 | 
						|
 | 
						|
        if websocket:
 | 
						|
            comment = Comment(comment="Websockets")
 | 
						|
            proxy_options.sections.add(comment)
 | 
						|
            http_version = EmptyBlock(proxy_http_version="1.1")
 | 
						|
            websocket_cfg = duplicate_options(
 | 
						|
                "proxy_set_header",
 | 
						|
                PROXY_WEBSOCKETS_OPTIONS
 | 
						|
            )
 | 
						|
            http_version.sections.add(websocket_cfg)
 | 
						|
            proxy_options.sections.add(http_version)
 | 
						|
 | 
						|
        location.sections.add(proxy_options)
 | 
						|
        self._config.sections.add(location)
 | 
						|
 | 
						|
    def add_php_try_files(self, location="/"):
 | 
						|
 | 
						|
        location = Location(location,
 | 
						|
                            try_files=["$uri", "$uri/",
 | 
						|
                                       f"{location}index.php?$query_string"])
 | 
						|
 | 
						|
        self._config.sections.add(location)
 | 
						|
 | 
						|
    def add_php_block(self):
 | 
						|
 | 
						|
        location = Location(r"~ ^(?<script_name>.+?\.php)(?<path_info>/.*)?$",
 | 
						|
                            try_files="$script_name = 404",
 | 
						|
                            include="fastcgi_params",
 | 
						|
                            fastcgi_pass="unix:/run/php-fpm/php-fpm.sock",
 | 
						|
                            fastcgi_hide_header="X-Powered-By")
 | 
						|
 | 
						|
        location.sections.add(duplicate_options("fastcgi_param", FPM_OPTIONS))
 | 
						|
 | 
						|
        self._config.sections.add(location)
 | 
						|
 | 
						|
    def add_uwsgi_location(self, location="/", socket=None, auth=False):
 | 
						|
 | 
						|
        location = Location(location, uwsgi_pass=socket,
 | 
						|
                            include="uwsgi_params")
 | 
						|
        if auth:
 | 
						|
            location.sections.add(KeyValueOption("include", "auth.conf"))
 | 
						|
 | 
						|
        self._config.sections.add(location)
 |