Version 0.6.0 (2026-04-01)

Changes:
- add config validation option via Makefile
- add `default-http{,s}-port` commands to add_servers.py
- update add_servers.py to pass generic parameters to servers in templates
- add nginx_conf.d directory usage for more than one custom nginx configurations
- rename `port` and `ssl_port` to `http{,s}_port` for templates
- add `http{,s}_custom_params` to templates
This commit is contained in:
2026-03-25 16:16:01 +03:00
parent 94259c5f99
commit 8946fa4244
14 changed files with 314 additions and 78 deletions

View File

@@ -4,52 +4,43 @@ from __future__ import annotations
import argparse
import os
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Any
import jinja2
import yaml
@dataclass
class Server:
"""Server entry for nginx.conf file."""
name: str
all_names: str | None = None
proxy_pass: str | None = None
certificate_dir: str | None = None
port: int = None
ssl_port: int = None
server_options: list[str] = field(default_factory=list)
location_options: list[str] = field(default_factory=list)
DEFAULT_HTTP_PORT = 80
DEFAULT_HTTPS_PORT = 443
certificates_path: str = "/etc/letsencrypt/live"
def __init__(
self,
http_port: int = ...,
https_port: int = ...,
**kwargs: dict[str, Any],
):
if http_port is ...:
http_port = Server.DEFAULT_HTTP_PORT
if https_port is ...:
https_port = Server.DEFAULT_HTTPS_PORT
self._params = dict(kwargs)
for additional_name, additional_value in zip(
["http_port", "https_port"],
[http_port, https_port],
):
self._params[additional_name] = additional_value
def __post_init__(self) -> None:
if self.server_options is None:
self.server_options = []
if self.location_options is None:
self.location_options = []
if self.all_names is None:
self.all_names = self.name
if self.port is None:
self.port = 80
if self.ssl_port is None:
self.ssl_port = 443
def __getattr__(self, name) -> Any:
return self._params.get(name)
def to_dict(self) -> dict:
"""Convert server class to dict for nginx.conf.j2 jinja2-template"""
return {
"name": self.name,
"all_names": self.all_names,
"proxy_pass": self.proxy_pass,
"server_options": self.server_options,
"location_options": self.location_options,
"certificate_dir": self.certificate_dir,
"port": self.port,
"ssl_port": self.ssl_port,
}
return dict(self._params)
@dataclass
@@ -59,6 +50,8 @@ class CLIParams:
nginx_template: str
domains_list_txt: str
servers_config: str
default_http_port: str
default_https_port: str
certificates_path: str
http_only: bool
output: str | None
@@ -69,7 +62,7 @@ def main() -> None:
parser = argparse.ArgumentParser("add-servers", description="Add domain servers to a given nginx.conf file")
parser.add_argument("--nginx-template", "-f", required=True, help="Path to nginx.conf.j2 template file")
parser.add_argument(
"--domains_list_txt",
"--domains-list-txt",
"-d",
required=True,
help="Path to file with domains which have ssl certificates",
@@ -81,6 +74,18 @@ def main() -> None:
default=None,
help="Path to servers configuration yaml file",
)
parser.add_argument(
"--default-http-port",
required=False,
default=80,
help="Default port for https protocol",
)
parser.add_argument(
"--default-https-port",
required=False,
default=443,
help="Default port for https protocol",
)
parser.add_argument(
"--certificates-path",
"-c",
@@ -97,6 +102,9 @@ def main() -> None:
args: CLIParams = parser.parse_args()
Server.DEFAULT_HTTP_PORT = args.default_http_port
Server.DEFAULT_HTTPS_PORT = args.default_https_port
if args.domains_list_txt is not None:
with open(args.domains_list_txt, "r", encoding="utf-8") as file:
domains_with_certs = [
@@ -117,22 +125,21 @@ def main() -> None:
servers: dict[str, dict[str, Any]] = data["servers"]
for server_name, params in servers.items():
params_part = dict(params)
all_names = params.get(
"all_names",
None if "*" not in server_name else f"{server_name} {server_name.replace('*.', '', 1)}",
)
certificate_dir = _get_certificate_path(
http_only=args.http_only,
domains_with_certs=domains_with_certs,
base_certs_path=args.certificates_path,
server_name=params.get("certificate_name") or server_name,
)
params_part.pop("all_names", None)
params_part.pop("certificate_name", None)
nginx_servers.append(
Server(
name=server_name,
all_names=params.get(
"all_names",
None if "*" not in server_name else f"{server_name} {server_name.replace('*.', '', 1)}",
),
proxy_pass=params.get("proxy_pass"),
certificate_dir=_get_certificate_path(
args.http_only, domains_with_certs, args.certificates_path, params.get("certificate_name") or server_name
),
port=params.get("port"),
ssl_port=params.get("ssl_port"),
server_options=params.get("server_options"),
location_options=params.get("location_options"),
)
Server(name=server_name, all_names=all_names, certificate_dir=certificate_dir, **params_part)
)
for domain in domains_with_certs:
if not any(
@@ -140,8 +147,7 @@ def main() -> None:
(server.all_names is None and domain == server.name)
or (
server.all_names is not None
and f" {domain}" in server.all_names
or server.all_names.startswith(domain)
and (f" {domain}" in server.all_names or server.all_names.startswith(domain))
)
)
for server in nginx_servers