ehh. I'm sorry.

This commit is contained in:
Matěj Divecký 2023-10-26 15:55:27 +02:00
parent f7c8eed701
commit 5becd6d9a1
8 changed files with 137 additions and 26 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@ __pycache__
clusters.json
/nginx
/autossl
.env

View file

@ -1,8 +1,20 @@
# Nginx configurator (patent for that name is pending...)
# TODO
* Add a way to generate autoincrementing config ID
* document dhparam.pem generation
* Prepare config templates for nginx and dehydrated?
* document dhparam.pem generation (`openssl dhparam -out ssl-dhparams.pem 4096` in /etc/autossl)
* Limit current SSH keys to only config rsync and nginx reload
* Write down how it works in human language
* Create a guide how to use it to intrawiki
* Teach everybody how to use it...
# Setup
* `python3 -m venv .venv`
* `source .venv/bin/activate`
* `pip3 install -r ./requirements.txt`
* `cp env.sample .env` # and customize to your needs
# Contributions

5
env.sample Normal file
View file

@ -0,0 +1,5 @@
NGINX_DIR="/etc/nginx"
DOMAINS_TXT="/etc/autossl/domains.txt"
DEHYDRATED_LOC="/etc/autossl/dehydrated.sh"
REMOTE="10.0.0.1"
REMOTE_SSH_KEY="./ssh.key"

View file

@ -1,18 +1,34 @@
import os
import json
import pyinputplus as pyip
from jinja2 import Environment, PackageLoader, select_autoescape
from dotenv import load_dotenv
import n_ssl
# Get clusters from json config
with open("clusters.json") as json_file:
CLUSTERS = json.load(json_file)["clusters"]
# Setup Jinja2
jin = Environment(loader=PackageLoader("n-gen"), autoescape=select_autoescape())
jin = Environment(loader=PackageLoader("n_gen"), autoescape=select_autoescape())
# ID of next config - TBD - read this from list of configs and increment!
CONF_ID = 1
load_dotenv()
NGINX_DIR = os.getenv('NGINX_DIR')
# Go through config names and find highest config number. Increment by 1 and use as new ID
def get_conf_id(nginx_dir):
list_auto = os.listdir(nginx_dir + "/sites/auto")
list_custom = os.listdir(nginx_dir + "/sites/custom")
domain_list = list_auto + list_custom
last_id = 0
for dom in domain_list:
id = int(dom.split('-')[0])
if id > last_id:
last_id = id
new_id = last_id + 1
return(new_id)
def get_domains():
new_domain = True
domains = []
@ -85,26 +101,59 @@ def input_check(domains, upstreams, port, proto):
exit()
def fill_template(id, domains, upstreams, port, proto):
def create_nginx_config(id, domains, upstreams, port, proto):
template = jin.get_template("nginx-site.conf")
return template.render(
id=id, domains=domains, upstreams=upstreams, port=port, proto=proto
)
def write_nginx_config(config, nginx_dir, domains, conf_id):
filename = str(conf_id) + "-" + domains[0] + ".conf"
path = nginx_dir + "/sites/auto/" + filename
with open(path, "w") as conf_file:
conf_file.write(config)
def create_ssl_config(conf_id):
template = jin.get_template("ssl.conf")
return template.render(id=conf_id)
def write_ssl_config(config, conf_id, nginx_dir):
filename = str(conf_id) + ".conf"
path = nginx_dir + "/ssl/" + filename
with open(path, "w") as conf_file:
conf_file.write(config)
def ssl_continue():
if pyip.inputYesNo("Do you want to prepare ssl certs and replicate the config? (y/n) ") == "yes":
n_ssl.main()
else:
print("Ok, you can run n_ssl.py to do it later.")
exit()
def main():
print("This script will generate nginx configuration and for new service.\n")
conf_id = get_conf_id(NGINX_DIR)
domains = get_domains()
upstreams = get_upstreams(CLUSTERS)
port = get_port()
proto = get_proto()
input_check(domains, upstreams, port, proto)
print(fill_template(CONF_ID, domains, upstreams, port, proto))
nginx_config = create_nginx_config(conf_id, domains, upstreams, port, proto)
write_nginx_config(nginx_config, NGINX_DIR, domains, conf_id)
ssl_config = create_ssl_config(conf_id)
write_ssl_config(ssl_config, conf_id, NGINX_DIR)
print("Nginx config created.")
ssl_continue()
# def test():
# print(fill_template("1110", ['nolog.cz', 'www.nolog.cz'], ['10.0.0.1', '10.0.0.2'], 80, 'https://'))
# print(create_nginx_config("1110", ['nolog.cz', 'www.nolog.cz'], ['10.0.0.1', '10.0.0.2'], 80, 'https://'))
if __name__ == "__main__":
main()
# test()

View file

@ -1,16 +1,19 @@
import os
import subprocess
import re
import sysrsync
from dotenv import load_dotenv
# NGINX_DIR="/etc/nginx"
# DOMAINS_TXT = "/etc/autossl/domains.txt"
# DEHYDRATED_LOC = "/etc/autossl/dehydrated.sh"
NGINX_DIR = "./nginx"
DOMAINS_TXT = "./autossl/domains.txt"
DEHYDRATED_LOC = "./autossl/dehydrated.sh"
REMOTE = "10.55.55.55" # make a .env variable or something like that. It will be different on each server
load_dotenv()
NGINX_DIR = os.getenv('NGINX_DIR')
DOMAINS_TXT = os.getenv('DOMAINS_TXT')
DEHYDRATED_LOC = os.getenv('DEHYDRATED_LOC')
REMOTE = os.getenv('REMOTE')
REMOTE_SSH_KEY = os.getenv('REMOTE_SSH_KEY')
def create_domfile():
@ -70,22 +73,51 @@ def reload_local_nginx():
exit()
def remote_replication(remote):
# Do RSYNC to second server
return True
def remote_replication(remote, ssh_key):
# Copy nginx config to second server
sysrsync.run(
source="/etc/nginx/",
destination="/etc/nginx/",
destination_ssh=remote,
private_key=ssh_key,
options=["-a"],
)
# Copy certificates to second server
sysrsync.run(
source="/etc/autossl/",
destination="/etc/autossl/",
destination_ssh=remote,
private_key=ssh_key,
options=["-a"],
)
def remote_reload(remote):
def remote_reload(remote, ssh_key):
# Check and reload nginx on second server
return True
nginx_check = subprocess.run(
["ssh", "-i", ssh_key, remote, "nginx", "-t"], capture_output=True, text=True
)
if nginx_check.returncode != 0:
print("Remote nginx config is not valid! Please check manually.")
print(nginx_check.stdout)
return False
else:
nginx_reload = subprocess.run(
["ssh", "-i", ssh_key, remote, "systemctl", "reload", "nginx.service"],
capture_output=True,
text=True,
)
if nginx_reload.returncode != 0:
print("Remote nginx reload failed, please check manually.")
print(nginx_reload.stdout)
def main():
# create_domfile()
create_domfile()
request_cert()
reload_local_nginx()
remote_replication(REMOTE)
remote_reload(REMOTE)
remote_replication(REMOTE, REMOTE_SSH_KEY)
remote_reload(REMOTE, REMOTE_SSH_KEY)
if __name__ == "__main__":

10
new_service.sh Normal file
View file

@ -0,0 +1,10 @@
#!/bin/bash
kill -s $(keepalived --signum=DATA) $(cat /var/run/keepalived.pid)
STATE=$(cat /tmp/keepalived.data |grep MASTER)
if [[ -z "${STATE}" ]]; then
echo "This is a secondary backup server, run the script on current master"
else
python3 n_gen.py
fi

View file

@ -1,2 +1,4 @@
pyinputplus
Jinja2
sysrsync
python-dotenv

View file

@ -1,5 +1,5 @@
# ID: {{ id }}
# Service configured by nxa.py
# Service configured by n_gen.py
upstream up_{{ id }} {
{%- for upstream in upstreams %}