From d29b502369dc380b213f8a8ba2cb6a82048bb7d6 Mon Sep 17 00:00:00 2001 From: Justus Wingert Date: Mon, 14 Aug 2023 16:03:48 +0200 Subject: [PATCH 1/8] Added subfile generation for web_update.py --- management/web_update.py | 54 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/management/web_update.py b/management/web_update.py index e23bb2d88..2f26d86c1 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -82,7 +82,7 @@ def read_conf(conf_fn): return f.read() # Build an nginx configuration file. - nginx_conf = read_conf("nginx-top.conf") + nginx_conf = [("nginx-top", read_conf("nginx-top.conf")), ] # Load the templates. template0 = read_conf("nginx.conf") @@ -91,7 +91,7 @@ def read_conf(conf_fn): template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n" # Add the PRIMARY_HOST configuration first so it becomes nginx's default server. - nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env) + nginx_conf.append((env['PRIMARY_HOSTNAME'], make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env))) # Add configuration all other web domains. has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env) @@ -103,31 +103,37 @@ def read_conf(conf_fn): if domain in web_domains_not_redirect: # This is a regular domain. if domain not in has_root_proxy_or_redirect: - nginx_conf += make_domain_config(domain, [template0, template1], ssl_certificates, env) + nginx_conf.append((domain, make_domain_config(domain, [template0, template1], ssl_certificates, env))) else: - nginx_conf += make_domain_config(domain, [template0], ssl_certificates, env) + nginx_conf.append((domain, make_domain_config(domain, [template0], ssl_certificates, env))) else: # Add default 'www.' redirect. - nginx_conf += make_domain_config(domain, [template0, template3], ssl_certificates, env) - - # Did the file change? If not, don't bother writing & restarting nginx. - nginx_conf_fn = "/etc/nginx/conf.d/local.conf" - if os.path.exists(nginx_conf_fn): - with open(nginx_conf_fn) as f: - if f.read() == nginx_conf: - return "" - - # Save the file. - with open(nginx_conf_fn, "w") as f: - f.write(nginx_conf) - - # Kick nginx. Since this might be called from the web admin - # don't do a 'restart'. That would kill the connection before - # the API returns its response. A 'reload' should be good - # enough and doesn't break any open connections. - shell('check_call', ["/usr/sbin/service", "nginx", "reload"]) - - return "web updated\n" + nginx_conf.append((domain, make_domain_config(domain, [template0, template3], ssl_certificates, env))) + + # Did the files change? If not, don't bother writing & restarting nginx. + kick = False + for domain, conf in nginx_conf: + nginx_conf_fn = "/etc/nginx/sites-available/%s" % domain + if os.path.exists(nginx_conf_fn): + with open(nginx_conf_fn) as f: + if f.read() == conf: + continue + + # Save the file. + with open(nginx_conf_fn, "w") as f: + f.write(conf) + + kick = True + if kick: + # Kick nginx. Since this might be called from the web admin + # don't do a 'restart'. That would kill the connection before + # the API returns its response. A 'reload' should be good + # enough and doesn't break any open connections. + shell('check_call', ["/usr/sbin/service", "nginx", "reload"]) + + return "web updated\n" + + return "" def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES From 5aa23e34201d2d2f5baafe3a1c6aa85fbee5489d Mon Sep 17 00:00:00 2001 From: Justus Wingert Date: Mon, 14 Aug 2023 16:11:58 +0200 Subject: [PATCH 2/8] Adding symbolic links in tools/web_update --- tools/web_update | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/web_update b/tools/web_update index c4b096d93..34dbc6f74 100755 --- a/tools/web_update +++ b/tools/web_update @@ -1,2 +1,9 @@ #!/bin/bash curl -s -d POSTDATA --user $( Date: Mon, 14 Aug 2023 16:38:10 +0200 Subject: [PATCH 3/8] Added warning to web_update.py if symbolic links are missing --- management/web_update.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/management/web_update.py b/management/web_update.py index 2f26d86c1..56fba5ce1 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -110,10 +110,16 @@ def read_conf(conf_fn): # Add default 'www.' redirect. nginx_conf.append((domain, make_domain_config(domain, [template0, template3], ssl_certificates, env))) + # Load the currently enabled sites for nginx. + sites_enabled = shell('check_output', ["ls", "/etc/nginx/sites-enabled"]) + warnings = [] + # Did the files change? If not, don't bother writing & restarting nginx. kick = False for domain, conf in nginx_conf: - nginx_conf_fn = "/etc/nginx/sites-available/%s" % domain + if "miab_%s" % domain not in sites_enabled: + warnings.append("Missing miab_%s in /etc/nginx/sites-enabled/\nCheck your configuration!" % domain) + nginx_conf_fn = "/etc/nginx/sites-available/miab_%s" % domain if os.path.exists(nginx_conf_fn): with open(nginx_conf_fn) as f: if f.read() == conf: @@ -131,9 +137,9 @@ def read_conf(conf_fn): # enough and doesn't break any open connections. shell('check_call', ["/usr/sbin/service", "nginx", "reload"]) - return "web updated\n" + return "web updated\n" + "\n".join(warnings) - return "" + return "" + "\n".join(warnings) def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES From 2572d5041173403fa51d81b57eb64aee68dd5a55 Mon Sep 17 00:00:00 2001 From: Justus Wingert Date: Mon, 14 Aug 2023 16:38:49 +0200 Subject: [PATCH 4/8] Added miab_ prefix to individual config files --- tools/web_update | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/web_update b/tools/web_update index 34dbc6f74..0ea7b281b 100755 --- a/tools/web_update +++ b/tools/web_update @@ -1,9 +1,8 @@ #!/bin/bash curl -s -d POSTDATA --user $( Date: Mon, 14 Aug 2023 16:40:12 +0200 Subject: [PATCH 5/8] Using output from shell method correctly --- management/web_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/management/web_update.py b/management/web_update.py index 56fba5ce1..41d8ca0c6 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -111,7 +111,7 @@ def read_conf(conf_fn): nginx_conf.append((domain, make_domain_config(domain, [template0, template3], ssl_certificates, env))) # Load the currently enabled sites for nginx. - sites_enabled = shell('check_output', ["ls", "/etc/nginx/sites-enabled"]) + _, sites_enabled = shell('check_output', ["ls", "/etc/nginx/sites-enabled"]) warnings = [] # Did the files change? If not, don't bother writing & restarting nginx. From 1cdf1a0d29ef23523c7400fd411e3f62d9361c23 Mon Sep 17 00:00:00 2001 From: Justus Wingert Date: Tue, 15 Aug 2023 14:06:19 +0200 Subject: [PATCH 6/8] Tested and minor bugs fixed. Works like a charm. --- management/web_update.py | 21 ++++++++++----------- tools/web_update | 8 ++++++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/management/web_update.py b/management/web_update.py index 41d8ca0c6..754a6ce53 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -111,7 +111,7 @@ def read_conf(conf_fn): nginx_conf.append((domain, make_domain_config(domain, [template0, template3], ssl_certificates, env))) # Load the currently enabled sites for nginx. - _, sites_enabled = shell('check_output', ["ls", "/etc/nginx/sites-enabled"]) + sites_enabled = shell('check_output', ["ls", "/etc/nginx/sites-enabled"]) warnings = [] # Did the files change? If not, don't bother writing & restarting nginx. @@ -120,16 +120,15 @@ def read_conf(conf_fn): if "miab_%s" % domain not in sites_enabled: warnings.append("Missing miab_%s in /etc/nginx/sites-enabled/\nCheck your configuration!" % domain) nginx_conf_fn = "/etc/nginx/sites-available/miab_%s" % domain - if os.path.exists(nginx_conf_fn): - with open(nginx_conf_fn) as f: - if f.read() == conf: - continue - - # Save the file. - with open(nginx_conf_fn, "w") as f: - f.write(conf) - - kick = True + with open(nginx_conf_fn, "w+") as f: + if f.read() == conf: + continue + + # Save the file. + with open(nginx_conf_fn, "w") as f: + f.write(conf) + + kick = True if kick: # Kick nginx. Since this might be called from the web admin # don't do a 'restart'. That would kill the connection before diff --git a/tools/web_update b/tools/web_update index 0ea7b281b..09943b107 100755 --- a/tools/web_update +++ b/tools/web_update @@ -1,8 +1,12 @@ #!/bin/bash +rm -f /etc/nginx/conf.d/local.conf curl -s -d POSTDATA --user $( Date: Tue, 15 Aug 2023 14:28:46 +0200 Subject: [PATCH 7/8] Added status checks for the configuration files. --- management/status_checks.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/management/status_checks.py b/management/status_checks.py index b31a98183..6a25f0de5 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -333,6 +333,18 @@ def run_domain_checks(rounded_time, env, output, pool, domains_to_check=None): # Get the list of domains we serve HTTPS for. web_domains = set(get_web_domains(env)) + output.add_heading("nginx configuration files") + + # Check nginx configuration. + sites_enabled = shell("check_output", ["ls", "/etc/nginx/sites-enabled"]) + output.print_ok("Checking domain configuration files: %s" % sites_enabled) + for domain in web_domains: + prefixed_domain = "miab_%s" % domain + if prefixed_domain in sites_enabled: + output.print_ok("Domain checked. (%s)" % domain) + else: + output.print_error("A domain configuration file is not enabled in nginx (%s)" % domain) + if domains_to_check is None: domains_to_check = mail_domains | dns_domains | web_domains From 89d50b35ef5570ea32ce347c7ddfef89ec1e8297 Mon Sep 17 00:00:00 2001 From: Justus Wingert Date: Tue, 15 Aug 2023 14:33:50 +0200 Subject: [PATCH 8/8] Bugfix for the bug introduced while fixing the first bug. We now test config files again before writing! --- management/web_update.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/management/web_update.py b/management/web_update.py index 754a6ce53..734454fa7 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -119,13 +119,15 @@ def read_conf(conf_fn): for domain, conf in nginx_conf: if "miab_%s" % domain not in sites_enabled: warnings.append("Missing miab_%s in /etc/nginx/sites-enabled/\nCheck your configuration!" % domain) + nginx_conf_fn = "/etc/nginx/sites-available/miab_%s" % domain - with open(nginx_conf_fn, "w+") as f: - if f.read() == conf: - continue + if os.path.exists(nginx_conf_fn): + with open(nginx_conf_fn) as f: + if f.read() == conf: + continue # Save the file. - with open(nginx_conf_fn, "w") as f: + with open(nginx_conf_fn, "w+") as f: f.write(conf) kick = True @@ -138,7 +140,7 @@ def read_conf(conf_fn): return "web updated\n" + "\n".join(warnings) - return "" + "\n".join(warnings) + return "No changes.\n%s" % "\n".join(warnings) def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES