Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
5494ceba1d | |||
e5e11af36d | |||
c8a31d1d74 | |||
e56c2fadb7 | |||
825e866e88 |
9 changed files with 107 additions and 58 deletions
51
README.md
51
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Nginx cluster configurator - ncc
|
# Nginx cluster configurator - ncc
|
||||||
|
|
||||||
Quality of life script for nginx and dehydrated.
|
Manages the local nginx configuration and replicates changes to a backup.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -18,33 +18,18 @@ Quality of life script for nginx and dehydrated.
|
||||||
* 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
|
||||||
|
|
||||||
* Install dependencies: nginx, keepalived (optional i guess), rsync, ssh, python3
|
* Extract `ncc.tar` to a location on the server
|
||||||
* Install `ncc` through pip (or pipx) from this git repository
|
* Copy configuration `config` to `/etc/ncc` and modify to suit your environment
|
||||||
```
|
* Add `/etc/ncc/ncc-hook.sh` as a hook to your `dehydrated` installation
|
||||||
pip install -U git+https://git.nolog.cz/NoLog.cz/nginx-configurator.git
|
* Add `ncc` to your `PATH`
|
||||||
```
|
* Optionally add shell completion:
|
||||||
* Create a `ncc.yml` file (see `ncc.yml.sample`)
|
* Bash: `_NCC_COMPLETE=bash_source ncc > /etc/bash_completion.d/ncc && . /etc/bash_completion.d/ncc`
|
||||||
* 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
|
||||||
|
|
||||||
|
@ -56,14 +41,16 @@ Usage: ncc [OPTIONS] COMMAND [ARGS]...
|
||||||
MUST BE RAN ON MASTER (will detect automatically)
|
MUST BE RAN ON MASTER (will detect automatically)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--help Show this message and exit.
|
--skip-master-check
|
||||||
|
--help Show this message and exit.
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
edit Edit a site
|
autossl Renew SSL certificates and replicate changes
|
||||||
list List all sites and the files they are located in
|
delete Delete a service
|
||||||
new Create a new site
|
edit Edit a service
|
||||||
test Run nginx -t on the configuration
|
list List exsiting services and domain names associated with them
|
||||||
up Deploy the configuration to the cluster
|
new Create a new service
|
||||||
|
reload Replicate the local config and reload the nginx cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
# Contributions
|
# Contributions
|
||||||
|
|
20
build.sh
Executable file
20
build.sh
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/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"
|
|
@ -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), None)
|
sn = next(re.finditer(SERVER_NAME_RE, server_block))
|
||||||
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), None)
|
sn = next(re.finditer(SERVER_NAME_RE, server_block))
|
||||||
if not sn:
|
if not sn:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
35
ncc/main.py
35
ncc/main.py
|
@ -97,13 +97,7 @@ 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)
|
||||||
@click.option(
|
def up(certs_only: bool, skip_master_check: bool):
|
||||||
"--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:
|
||||||
|
@ -129,21 +123,20 @@ def up(certs_only: bool, skip_master_check: bool, skip_certs: bool):
|
||||||
Path(CONFIG["dehydrated_dir"]) / "domains.txt",
|
Path(CONFIG["dehydrated_dir"]) / "domains.txt",
|
||||||
)
|
)
|
||||||
|
|
||||||
if not skip_certs:
|
ec, stdout = sysaction.run_shell(
|
||||||
ec, stdout = sysaction.run_shell(
|
(
|
||||||
(
|
str(dehydrated_dir / "dehydrated.sh"),
|
||||||
str(dehydrated_dir / "dehydrated.sh"),
|
"-c",
|
||||||
"-c",
|
*(["-g"] if certs_only else []),
|
||||||
*(["-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(
|
||||||
|
|
0
ncc/templates/__init__.py
Normal file
0
ncc/templates/__init__.py
Normal file
11
ncc/templates/nginx-minimal.conf
Normal file
11
ncc/templates/nginx-minimal.conf
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# ID: {{ id }}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
|
server_name <domain>; # AUTOSSL > {{ id }}
|
||||||
|
include ssl/{{ id }}.conf;
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
34
ncc/templates/nginx-site.conf
Normal file
34
ncc/templates/nginx-site.conf
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
ncc/templates/ssl.conf
Normal file
4
ncc/templates/ssl.conf
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
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;
|
2
setup.py
2
setup.py
|
@ -2,7 +2,7 @@ from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ncc',
|
name='ncc',
|
||||||
version='1.1.0',
|
version='1.0.0',
|
||||||
packages=['ncc'],
|
packages=['ncc'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'click',
|
'click',
|
||||||
|
|
Loading…
Reference in a new issue