mirror of
https://git.nolog.cz/NoLog.cz/nginx-configurator.git
synced 2025-01-31 03:43:35 +01:00
ehh. I'm sorry.
This commit is contained in:
parent
f7c8eed701
commit
5becd6d9a1
8 changed files with 137 additions and 26 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,4 +4,5 @@ __pycache__
|
||||||
.vscode
|
.vscode
|
||||||
clusters.json
|
clusters.json
|
||||||
/nginx
|
/nginx
|
||||||
/autossl
|
/autossl
|
||||||
|
.env
|
18
README.md
18
README.md
|
@ -1,9 +1,21 @@
|
||||||
# Nginx configurator (patent for that name is pending...)
|
# Nginx configurator (patent for that name is pending...)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
* Add a way to generate autoincrementing config ID
|
* Prepare config templates for nginx and dehydrated?
|
||||||
* document dhparam.pem generation
|
* 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
|
# Contributions
|
||||||
Please use `black` formatter.
|
Please use `black` formatter.
|
||||||
|
|
5
env.sample
Normal file
5
env.sample
Normal 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"
|
|
@ -1,18 +1,34 @@
|
||||||
|
import os
|
||||||
import json
|
import json
|
||||||
import pyinputplus as pyip
|
import pyinputplus as pyip
|
||||||
from jinja2 import Environment, PackageLoader, select_autoescape
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import n_ssl
|
||||||
|
|
||||||
# Get clusters from json config
|
# Get clusters from json config
|
||||||
with open("clusters.json") as json_file:
|
with open("clusters.json") as json_file:
|
||||||
CLUSTERS = json.load(json_file)["clusters"]
|
CLUSTERS = json.load(json_file)["clusters"]
|
||||||
|
|
||||||
# Setup Jinja2
|
# 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!
|
load_dotenv()
|
||||||
CONF_ID = 1
|
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():
|
def get_domains():
|
||||||
new_domain = True
|
new_domain = True
|
||||||
domains = []
|
domains = []
|
||||||
|
@ -85,26 +101,59 @@ def input_check(domains, upstreams, port, proto):
|
||||||
exit()
|
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")
|
template = jin.get_template("nginx-site.conf")
|
||||||
return template.render(
|
return template.render(
|
||||||
id=id, domains=domains, upstreams=upstreams, port=port, proto=proto
|
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():
|
def main():
|
||||||
print("This script will generate nginx configuration and for new service.\n")
|
print("This script will generate nginx configuration and for new service.\n")
|
||||||
|
conf_id = get_conf_id(NGINX_DIR)
|
||||||
domains = get_domains()
|
domains = get_domains()
|
||||||
upstreams = get_upstreams(CLUSTERS)
|
upstreams = get_upstreams(CLUSTERS)
|
||||||
port = get_port()
|
port = get_port()
|
||||||
proto = get_proto()
|
proto = get_proto()
|
||||||
input_check(domains, upstreams, port, 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():
|
# 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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
# test()
|
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
|
import sysrsync
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# NGINX_DIR="/etc/nginx"
|
# NGINX_DIR="/etc/nginx"
|
||||||
# DOMAINS_TXT = "/etc/autossl/domains.txt"
|
# DOMAINS_TXT = "/etc/autossl/domains.txt"
|
||||||
# DEHYDRATED_LOC = "/etc/autossl/dehydrated.sh"
|
# DEHYDRATED_LOC = "/etc/autossl/dehydrated.sh"
|
||||||
|
|
||||||
NGINX_DIR = "./nginx"
|
load_dotenv()
|
||||||
DOMAINS_TXT = "./autossl/domains.txt"
|
NGINX_DIR = os.getenv('NGINX_DIR')
|
||||||
DEHYDRATED_LOC = "./autossl/dehydrated.sh"
|
DOMAINS_TXT = os.getenv('DOMAINS_TXT')
|
||||||
|
DEHYDRATED_LOC = os.getenv('DEHYDRATED_LOC')
|
||||||
REMOTE = "10.55.55.55" # make a .env variable or something like that. It will be different on each server
|
REMOTE = os.getenv('REMOTE')
|
||||||
|
REMOTE_SSH_KEY = os.getenv('REMOTE_SSH_KEY')
|
||||||
|
|
||||||
|
|
||||||
def create_domfile():
|
def create_domfile():
|
||||||
|
@ -70,22 +73,51 @@ def reload_local_nginx():
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
def remote_replication(remote):
|
def remote_replication(remote, ssh_key):
|
||||||
# Do RSYNC to second server
|
# Copy nginx config to second server
|
||||||
return True
|
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
|
# 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():
|
def main():
|
||||||
# create_domfile()
|
create_domfile()
|
||||||
request_cert()
|
request_cert()
|
||||||
reload_local_nginx()
|
reload_local_nginx()
|
||||||
remote_replication(REMOTE)
|
remote_replication(REMOTE, REMOTE_SSH_KEY)
|
||||||
remote_reload(REMOTE)
|
remote_reload(REMOTE, REMOTE_SSH_KEY)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
10
new_service.sh
Normal file
10
new_service.sh
Normal 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
|
|
@ -1,2 +1,4 @@
|
||||||
pyinputplus
|
pyinputplus
|
||||||
Jinja2
|
Jinja2
|
||||||
|
sysrsync
|
||||||
|
python-dotenv
|
|
@ -1,5 +1,5 @@
|
||||||
# ID: {{ id }}
|
# ID: {{ id }}
|
||||||
# Service configured by nxa.py
|
# Service configured by n_gen.py
|
||||||
|
|
||||||
upstream up_{{ id }} {
|
upstream up_{{ id }} {
|
||||||
{%- for upstream in upstreams %}
|
{%- for upstream in upstreams %}
|
||||||
|
|
Loading…
Reference in a new issue