From a15bdfa95fa85e610e53b712842d6d1503e41155 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Mon, 5 Jul 2021 22:42:42 +0200 Subject: [PATCH] wip --- bundles/nginx/files/nginx.conf | 34 ---------- bundles/nginx/files/port80.conf | 13 ---- bundles/nginx/files/stub_status | 6 -- bundles/nginx/items.py | 87 +++++-------------------- bundles/nginx/metadata.py | 112 +++++++++++++++++++++----------- bundles/roundcube/metadata.py | 21 +++--- libs/nginx.py | 27 ++++++++ 7 files changed, 126 insertions(+), 174 deletions(-) delete mode 100644 bundles/nginx/files/nginx.conf delete mode 100644 bundles/nginx/files/port80.conf delete mode 100644 bundles/nginx/files/stub_status create mode 100644 libs/nginx.py diff --git a/bundles/nginx/files/nginx.conf b/bundles/nginx/files/nginx.conf deleted file mode 100644 index be51300..0000000 --- a/bundles/nginx/files/nginx.conf +++ /dev/null @@ -1,34 +0,0 @@ -user www-data; -worker_processes 10; - -pid /var/run/nginx.pid; - - -events { - worker_connections 500; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - charset UTF-8; - override_charset on; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 15; - client_body_timeout 12; - client_header_timeout 12; - send_timeout 10; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - client_body_buffer_size 10K; - client_header_buffer_size 1k; - client_max_body_size 1M; - large_client_header_buffers 2 1k; - - include /etc/nginx/sites/*; -} diff --git a/bundles/nginx/files/port80.conf b/bundles/nginx/files/port80.conf deleted file mode 100644 index 90bbd90..0000000 --- a/bundles/nginx/files/port80.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80 default_server; - listen [::]:80 default_server; - server_name _; - - location /.well-known/acme-challenge/ { - alias /var/lib/dehydrated/acme-challenges/; - } - - location / { - return 404; - } -} diff --git a/bundles/nginx/files/stub_status b/bundles/nginx/files/stub_status deleted file mode 100644 index 7cb9326..0000000 --- a/bundles/nginx/files/stub_status +++ /dev/null @@ -1,6 +0,0 @@ -server { - listen 127.0.0.1:22999 default_server; - server_name _; - - stub_status; -} diff --git a/bundles/nginx/items.py b/bundles/nginx/items.py index 26943fc..54d776c 100644 --- a/bundles/nginx/items.py +++ b/bundles/nginx/items.py @@ -18,26 +18,11 @@ directories = { files = { '/etc/nginx/nginx.conf': { - 'content_type': 'mako', - 'context': { - 'username': 'www-data', - **node.metadata['nginx'], - }, + 'content': repo.libs.nginx.render_config(node.metadata.get('nginx/config')), 'triggers': { 'svc_systemd:nginx:restart', }, }, - '/etc/nginx/sites/stub_status': { - 'triggers': { - 'svc_systemd:nginx:restart', - }, - }, - '/etc/nginx/sites/000-port80.conf': { - 'source': 'port80.conf', - 'triggers': { - 'svc_systemd:nginx:restart', - }, - }, '/etc/nginx/fastcgi.conf': { 'triggers': { 'svc_systemd:nginx:restart', @@ -61,18 +46,15 @@ svc_systemd = { }, } -for vhost, config in node.metadata.get('nginx/vhosts', {}).items(): - files[f'/etc/nginx/sites/{vhost}'] = { - 'source': 'site_template', - 'content_type': 'mako', - 'context': { - 'create_access_log': config.get('access_log', node.metadata.get('nginx/access_log', False)), - 'php_version': node.metadata.get('php/version', ''), - 'vhost': vhost, - 'nameservers': node.metadata.get('nameservers'), - **config, - }, - 'needs': set(), +for name, config in { + **node.metadata.get('nginx/default_vhosts'), + **node.metadata.get('nginx/vhosts'), +}.items(): + files[f'/etc/nginx/sites/{name}'] = { + 'content': repo.libs.nginx.render_config({ + 'server': config, + }), + 'needs': [], 'needed_by': { 'svc_systemd:nginx', 'svc_systemd:nginx:restart', @@ -81,47 +63,8 @@ for vhost, config in node.metadata.get('nginx/vhosts', {}).items(): 'svc_systemd:nginx:restart', }, } - - if not 'webroot' in config: - directories[f'/var/www/{vhost}'] = {} - - if node.has_bundle('zfs'): - directories[f'/var/www/{vhost}']['needs'] = { - 'bundle:zfs', - } - - directories[f'/var/www/{vhost}'].update(config.get('webroot_config', {})) - - if config.get('ssl', 'letsencrypt') == 'letsencrypt': - files[f'/etc/nginx/sites/{vhost}']['needs'].add('action:letsencrypt_ensure-some-certificate_{}'.format(config['domain'])) - files[f'/etc/nginx/sites/{vhost}']['needed_by'].add('action:letsencrypt_update_certificates') - - elif config.get('ssl', 'letsencrypt'): - files[f'/etc/nginx/ssl/{vhost}.crt'] = { - 'content_type': 'mako', - 'source': 'ssl_template', - 'context': { - 'domain': config['ssl'], - }, - 'needed_by': { - 'svc_systemd:nginx', - 'svc_systemd:nginx:restart', - }, - 'triggers': { - 'svc_systemd:nginx:reload', - }, - } - files[f'/etc/nginx/ssl/{vhost}.key'] = { - 'content': repo.vault.decrypt_file('ssl/{}.key.pem.vault'.format(config['ssl'])), - 'mode': '0600', - 'needed_by': { - 'svc_systemd:nginx', - 'svc_systemd:nginx:restart', - }, - 'triggers': { - 'svc_systemd:nginx:reload', - }, - } - - files[f'/etc/nginx/sites/{vhost}']['needs'].add(f'file:/etc/nginx/ssl/{vhost}.crt') - files[f'/etc/nginx/sites/{vhost}']['needs'].add(f'file:/etc/nginx/ssl/{vhost}.key') + + if name in node.metadata.get('letsencrypt/domains'): + files[f'/etc/nginx/sites/{name}']['needs'].append( + f'action:letsencrypt_ensure-some-certificate_{name}', + ) diff --git a/bundles/nginx/metadata.py b/bundles/nginx/metadata.py index 18051c2..4947b46 100644 --- a/bundles/nginx/metadata.py +++ b/bundles/nginx/metadata.py @@ -7,63 +7,101 @@ defaults = { }, }, 'nginx': { - 'worker_connections': 768, + 'config': { + 'user': 'www-data', + 'worker_processes': 10, + 'pid': '/var/run/nginx.pid', + 'events': { + 'worker_connections': 768, + }, + 'http': { + 'include': [ + '/etc/nginx/mime.types', + '/etc/nginx/sites/*', + ], + 'default_type': 'application/octet-stream', + 'sendfile': 'on', + 'tcp_nopush': 'on', + 'server_names_hash_bucket_size': 128, + 'access_log': '/var/log/nginx/access.log', + 'error_log': '/var/log/nginx/error.log', + }, + }, + 'default_vhosts': { + '80': { + 'listen': [ + '80', + '[::]:80', + ], + 'location /.well-known/acme-challenge/': { + 'alias': '/var/lib/dehydrated/acme-challenges/', + }, + 'location /': { + 'return': '301 https://$host$request_uri', + }, + }, + 'stub_status': { + 'listen': '127.0.0.1:22999 default_server', + 'server_name': '_', + 'stub_status': '', + }, + }, + 'vhosts': {}, }, } +@metadata_reactor.provides( + 'nginx/vhosts', +) +def vhosts(metadata): + vhosts = {} + + for name, config in metadata.get('nginx/vhosts').items(): + vhosts[name] = { + 'server_name': name, + 'listen': [ + '443 ssl http2', + '[::]:443 ssl http2', + ], + 'ssl_certificate': f'/var/lib/dehydrated/certs/{name}/fullchain.pem', + 'ssl_certificate_key': f'/var/lib/dehydrated/certs/{name}/privkey.pem', + 'location /.well-known/acme-challenge/': { + 'alias': '/var/lib/dehydrated/acme-challenges/', + }, + } + + return { + 'nginx': { + 'vhosts': vhosts, + } + } + + @metadata_reactor.provides( 'dns', ) def dns(metadata): - dns = {} - - for config in metadata.get('nginx/vhosts', {}).values(): - dns[config['domain']] = { - 'A': [ - str(ip_interface(network['ipv4']).ip) - for network in metadata.get('network').values() - if 'ipv4' in network - ], - 'AAAA': [ - str(ip_interface(network['ipv6']).ip) - for network in metadata.get('network').values() - if 'ipv6' in network - ], - } - return { - 'dns': dns, + 'dns': { + domain: repo.libs.dns.get_a_records(metadata) + for domain in metadata.get('nginx/vhosts') + }, } + @metadata_reactor.provides( 'letsencrypt/domains', 'letsencrypt/reload_after', - 'nginx/vhosts', ) def letsencrypt(metadata): - if not node.has_bundle('letsencrypt'): - raise DoNotRunAgain - - domains = {} - vhosts = {} - - for vhost, config in metadata.get('nginx/vhosts', {}).items(): - if config.get('ssl', 'letsencrypt') == 'letsencrypt': - domain = config.get('domain', vhost) - domains[domain] = config.get('domain_aliases', set()) - vhosts[vhost] = { - 'ssl': 'letsencrypt', - } - return { 'letsencrypt': { - 'domains': domains, + 'domains': { + domain: {} for domain in metadata.get('nginx/vhosts') + }, 'reload_after': { 'nginx', }, }, - 'nginx': { - 'vhosts': vhosts, - }, } diff --git a/bundles/roundcube/metadata.py b/bundles/roundcube/metadata.py index 0a29c1b..4ee9cca 100644 --- a/bundles/roundcube/metadata.py +++ b/bundles/roundcube/metadata.py @@ -20,14 +20,6 @@ defaults = { 'php-zip': {}, }, }, - 'nginx': { - 'vhosts': { - 'roundcube': { - 'webroot': '/opt/roundcube', - 'php': True, - }, - }, - }, 'roundcube': { 'database': { 'provider': 'pgsql', @@ -57,14 +49,19 @@ defaults = { } @metadata_reactor.provides( - 'nginx/vhosts/roundcube/domain' + 'nginx/vhosts' ) -def domain(metadata): +def vhost(metadata): return { 'nginx': { 'vhosts': { - 'roundcube': { - 'domain': metadata.get('mailserver/hostname'), + metadata.get('mailserver/hostname'): { + 'root': '/opt/roundcube', + 'location ~ \.php$': { + 'include': 'fastcgi.conf', + 'fastcgi_split_path_info': '^(.+\.php)(/.+)$', + 'fastcgi_pass': f"unix:/run/php/php{metadata.get('php/version')}-fpm.sock", + }, }, }, }, diff --git a/libs/nginx.py b/libs/nginx.py new file mode 100644 index 0000000..dc83e25 --- /dev/null +++ b/libs/nginx.py @@ -0,0 +1,27 @@ +def render_config(config): + return '\n'.join(render_lines(config)) + +def render_lines(config, indent=0): + lines = [] + blocks = [] + + for key, value in sorted(config.items()): + if isinstance(value, dict): + blocks.extend([ + '', + key+' {', + *render_lines(value, indent=4), + '}', + ]) + elif isinstance(value, list): + lines.extend([ + f'{key} {_value};' for _value in value + ]) + else: + lines.append( + f'{key} {value};' + ) + + return [ + f"{' '*indent}{line}" for line in lines+blocks + ]