Compare commits

..

16 commits
v2 ... main

9 changed files with 58 additions and 107 deletions

View file

@ -1,6 +1,6 @@
# Nginx cluster configurator - ncc # Nginx cluster configurator - ncc
Manages the local nginx configuration and replicates changes to a backup. Quality of life script for nginx and dehydrated.
## Features ## Features
@ -18,18 +18,33 @@ Manages the local nginx configuration and replicates changes to a backup.
* Create a guide how to use it to intrawiki * Create a guide how to use it to intrawiki
* Teach everybody how to use it... * Teach everybody how to use it...
# Build
Run `build.sh` on a linux(-ish) machine. The output is a tarball `ncc.tar`.
# Installation # Installation
* Extract `ncc.tar` to a location on the server * Install dependencies: nginx, keepalived (optional i guess), rsync, ssh, python3
* Copy configuration `config` to `/etc/ncc` and modify to suit your environment * Install `ncc` through pip (or pipx) from this git repository
* Add `/etc/ncc/ncc-hook.sh` as a hook to your `dehydrated` installation ```
* Add `ncc` to your `PATH` pip install -U git+https://git.nolog.cz/NoLog.cz/nginx-configurator.git
* Optionally add shell completion: ```
* Bash: `_NCC_COMPLETE=bash_source ncc > /etc/bash_completion.d/ncc && . /etc/bash_completion.d/ncc` * Create a `ncc.yml` file (see `ncc.yml.sample`)
* Create a base nginx config (in `conf_dir`):
It should look like this:
```
conf/
nginx.conf
sites/
...
dehydrated/
dehydrated.sh <= you need to download dehydrated from github.com/dehydrated-io/dehydrated
config <= you don't have to configure anything, i recommend using AUTO_CLEANUP=yes
...
```
* Register to CA with dehydrated (`./dehydrated.sh --register --accept-terms`)
* Optional (for `new` command): Create a `templates` folder inside `conf_dir` and create some templates.
* Deploy once with a valid configuration (like a default http server that will
serve `/var/www/dehydrated`), so that dehydrated will be able to deploy
challenges.
* Done.
# Usage # Usage
@ -41,16 +56,14 @@ Usage: ncc [OPTIONS] COMMAND [ARGS]...
MUST BE RAN ON MASTER (will detect automatically) MUST BE RAN ON MASTER (will detect automatically)
Options: Options:
--skip-master-check --help Show this message and exit.
--help Show this message and exit.
Commands: Commands:
autossl Renew SSL certificates and replicate changes edit Edit a site
delete Delete a service list List all sites and the files they are located in
edit Edit a service new Create a new site
list List exsiting services and domain names associated with them test Run nginx -t on the configuration
new Create a new service up Deploy the configuration to the cluster
reload Replicate the local config and reload the nginx cluster
``` ```
# Contributions # Contributions

View file

@ -1,20 +0,0 @@
#!/bin/bash
DIR=$(mktemp -d)
pip install -r requirements.txt --target="$DIR"
cp -r nginx_configurator "$DIR"
cp -r config "$DIR"
#python3 -m zipapp -p "/bin/python3" -m "nginx_configurator.main:cli" -o ncc "$DIR"
# create entrypoint
cat > "$DIR/ncc" <<EOF
#!/bin/python3
from nginx_configurator import main
main.cli()
EOF
chmod +x "$DIR/ncc"
tar -cf ncc.tar -C "$DIR" .
rm -r "$DIR"

View file

@ -15,8 +15,8 @@ ssl_certificate_key $keypath;
ssl_certificate $certpath; ssl_certificate $certpath;
""".lstrip() """.lstrip()
SERVER_BLOCK_RE = re.compile(r"(?:^|[{};])\s*server\s*{", re.MULTILINE) SERVER_BLOCK_RE = re.compile(r"(?:^|[{};])\s*server\s*{", re.MULTILINE)
INCLUDE_RE = re.compile(r"(?:^|[{};])\s*include\s+([^;]+);", re.MULTILINE) INCLUDE_RE = re.compile(r"(?:^|[{};])\s*include\s+([^;]+)(?=;)", re.MULTILINE)
SERVER_NAME_RE = re.compile(r"(?:^|[{};])\s*server_name\s+([^;]+);", re.MULTILINE) SERVER_NAME_RE = re.compile(r"(?:^|[{};])\s*server_name\s+([^;]+)(?=;)", re.MULTILINE)
class ConfigError(Exception): class ConfigError(Exception):
@ -65,7 +65,7 @@ def get_sites(cfg: Path) -> Generator[Tuple[Path, str]]:
config_part = _remove_comments(c[1]) config_part = _remove_comments(c[1])
for server_block in _get_server_blocks(config_part): for server_block in _get_server_blocks(config_part):
sn = next(re.finditer(SERVER_NAME_RE, server_block)) sn = next(re.finditer(SERVER_NAME_RE, server_block), None)
if not sn: if not sn:
continue continue
@ -87,7 +87,7 @@ def generate_ssl(cfg: Path, domainstxt_file: Path) -> int:
config_part = _remove_comments(c[1]) config_part = _remove_comments(c[1])
for server_block in _get_server_blocks(config_part): for server_block in _get_server_blocks(config_part):
sn = next(re.finditer(SERVER_NAME_RE, server_block)) sn = next(re.finditer(SERVER_NAME_RE, server_block), None)
if not sn: if not sn:
continue continue

View file

@ -97,7 +97,13 @@ def cli():
help="Try to fetch certificates and deploy", help="Try to fetch certificates and deploy",
) )
@click.option("--skip-master-check", type=bool, is_flag=True) @click.option("--skip-master-check", type=bool, is_flag=True)
def up(certs_only: bool, skip_master_check: bool): @click.option(
"--skip-certs",
type=bool,
is_flag=True,
help="Do not fetch certificates",
)
def up(certs_only: bool, skip_master_check: bool, skip_certs: bool):
"""Deploy the configuration to the cluster """Deploy the configuration to the cluster
Does the following: Does the following:
@ -123,20 +129,21 @@ def up(certs_only: bool, skip_master_check: bool):
Path(CONFIG["dehydrated_dir"]) / "domains.txt", Path(CONFIG["dehydrated_dir"]) / "domains.txt",
) )
ec, stdout = sysaction.run_shell( if not skip_certs:
( ec, stdout = sysaction.run_shell(
str(dehydrated_dir / "dehydrated.sh"), (
"-c", str(dehydrated_dir / "dehydrated.sh"),
*(["-g"] if certs_only else []), "-c",
), *(["-g"] if certs_only else []),
window_height=5, ),
) window_height=5,
if ec != 0:
log = Path(tempfile.mktemp())
log.write_text(stdout)
raise NccException(
f"dehydrated returned {ec} (log: {click.format_filename(log)})"
) )
if ec != 0:
log = Path(tempfile.mktemp())
log.write_text(stdout)
raise NccException(
f"dehydrated returned {ec} (log: {click.format_filename(log)})"
)
if not certs_only: if not certs_only:
ec, stdout = sysaction.run_shell( ec, stdout = sysaction.run_shell(

View file

@ -1,11 +0,0 @@
# ID: {{ id }}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <domain>; # AUTOSSL > {{ id }}
include ssl/{{ id }}.conf;
return 200;
}

View file

@ -1,34 +0,0 @@
# ID: {{ id }}
# Service configured by ncc
upstream up_{{ id }} {
{%- for upstream in upstreams %}
server {{ upstream }}:{{ port }};
{%- endfor %}
}
server {
server_name{% for domain in domains %} {{ domain }}{% endfor %}; # AUTOSSL > {{ id }}
listen 443 ssl http2;
listen [::]:443 ssl http2;
# ssl
include /etc/nginx/ssl/{{ id }}.conf;
# logging
include include/logging-nolog.conf; # Change to "logging-debug" if needed
# gzip compression
include include/gzip.conf;
# security headers
include include/security-headers.conf;
# reverse proxy
location / {
proxy_pass {{ proto }}up_{{ id }};
include include/proxy-headers.conf;
}
}

View file

@ -1,4 +0,0 @@
ssl_certificate /etc/autossl/certs/{{ alias }}/fullchain.pem;
ssl_certificate_key /etc/autossl/certs/{{ alias }}/privkey.pem;
include include/ssl_defaults.conf;
ssl_dhparam /etc/autossl/ssl-dhparams.pem;

View file

@ -2,7 +2,7 @@ from setuptools import setup
setup( setup(
name='ncc', name='ncc',
version='1.0.0', version='1.1.0',
packages=['ncc'], packages=['ncc'],
install_requires=[ install_requires=[
'click', 'click',