From 4150a3fb4d9199989c4013b55c03aedfbd76adc3 Mon Sep 17 00:00:00 2001
From: mwiegand <mwiegand@seibert-media.net>
Date: Wed, 7 Jul 2021 01:02:22 +0200
Subject: [PATCH] wip

---
 bundles/gitea/metadata.py            |   7 +-
 bundles/nextcloud/metadata.py        |   8 +--
 bundles/nginx/files/80.conf          |  12 ++++
 bundles/nginx/files/nginx.conf       |  18 +++++
 bundles/nginx/files/stub_status.conf |   5 ++
 bundles/nginx/items.py               |  41 ++++++-----
 bundles/nginx/metadata.py            |  29 +++-----
 bundles/roundcube/metadata.py        |   8 +--
 data/nextcloud/vhost.conf            | 100 +++++++++++++++++++++++++++
 data/nginx/php.conf                  |   6 ++
 data/nginx/proxy_pass.conf           |  16 +++++
 nodes/home.server.py                 |   2 +-
 nodes/htz.mails.py                   |  22 +++++-
 13 files changed, 219 insertions(+), 55 deletions(-)
 create mode 100644 bundles/nginx/files/80.conf
 create mode 100644 bundles/nginx/files/nginx.conf
 create mode 100644 bundles/nginx/files/stub_status.conf
 create mode 100644 data/nextcloud/vhost.conf
 create mode 100644 data/nginx/php.conf
 create mode 100644 data/nginx/proxy_pass.conf

diff --git a/bundles/gitea/metadata.py b/bundles/gitea/metadata.py
index a193b88..fcfad64 100644
--- a/bundles/gitea/metadata.py
+++ b/bundles/gitea/metadata.py
@@ -78,9 +78,10 @@ def nginx(metadata):
         'nginx': {
             'vhosts': {
                 metadata.get('gitea/domain'): {
-                    'location /': {
-                        'proxy_pass': 'http://127.0.0.1:3500',
-                    },
+                    'content': 'nginx/proxy_pass.conf',
+                    'context': {
+                        'target': 'http://127.0.0.1:3500',
+                    }
                 },
             },
         },
diff --git a/bundles/nextcloud/metadata.py b/bundles/nextcloud/metadata.py
index d4bfe11..c9b2440 100644
--- a/bundles/nextcloud/metadata.py
+++ b/bundles/nextcloud/metadata.py
@@ -73,10 +73,10 @@ def vhost(metadata):
         'nginx': {
             'vhosts': {
                 metadata.get('nextcloud/hostname'): {
-                    'root': '/opt/nextcloud',
-                    'include': [
-                        'php.conf',
-                    ],
+                    'content': 'nextcloud/vhost.conf',
+                    'context': {
+                        'root': '/opt/nextcloud',
+                    },
                 },
             },
         },
diff --git a/bundles/nginx/files/80.conf b/bundles/nginx/files/80.conf
new file mode 100644
index 0000000..ef380ce
--- /dev/null
+++ b/bundles/nginx/files/80.conf
@@ -0,0 +1,12 @@
+server {
+    listen 80;
+    listen [::]:80;
+
+    location / {
+        return 301 https://$host$request_uri;
+    }
+
+    location /.well-known/acme-challenge/ {
+        alias /var/lib/dehydrated/acme-challenges/;
+    }
+}
diff --git a/bundles/nginx/files/nginx.conf b/bundles/nginx/files/nginx.conf
new file mode 100644
index 0000000..fa5a94e
--- /dev/null
+++ b/bundles/nginx/files/nginx.conf
@@ -0,0 +1,18 @@
+pid /var/run/nginx.pid;
+user www-data;
+worker_processes 10;
+
+events {
+    worker_connections 768;
+}
+
+http {
+    access_log /var/log/nginx/access.log;
+    default_type application/octet-stream;
+    error_log /var/log/nginx/error.log;
+    include /etc/nginx/mime.types;
+    include /etc/nginx/sites/*;
+    sendfile on;
+    server_names_hash_bucket_size 128;
+    tcp_nopush on;
+}
diff --git a/bundles/nginx/files/stub_status.conf b/bundles/nginx/files/stub_status.conf
new file mode 100644
index 0000000..903faad
--- /dev/null
+++ b/bundles/nginx/files/stub_status.conf
@@ -0,0 +1,5 @@
+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 b8cc63c..a70cc5d 100644
--- a/bundles/nginx/items.py
+++ b/bundles/nginx/items.py
@@ -1,4 +1,6 @@
 from datetime import datetime, timedelta
+from mako.template import Template
+from os.path import join
 
 directories = {
     '/etc/nginx/sites': {
@@ -17,8 +19,7 @@ directories = {
 }
 
 files = {
-     '/etc/nginx/nginx.conf': {
-        'content': repo.libs.nginx.render_config(node.metadata.get('nginx/config')),
+    '/etc/nginx/nginx.conf': {
         'triggers': {
             'svc_systemd:nginx:restart',
         },
@@ -28,6 +29,16 @@ files = {
             'svc_systemd:nginx:restart',
         },
     }, 
+    '/etc/nginx/sites/80.conf': {
+        'triggers': {
+            'svc_systemd:nginx:restart',
+        },
+    }, 
+    '/etc/nginx/sites/stub_status.conf': {
+        'triggers': {
+            'svc_systemd:nginx:restart',
+        },
+    }, 
     '/etc/nginx/sites-available': {
         'delete': True,
     },
@@ -52,26 +63,14 @@ svc_systemd = {
     },
 }
 
-for name, config in node.metadata.get('nginx/includes').items():
-    files[f'/etc/nginx/{name}.conf'] = {
-        'content': repo.libs.nginx.render_config(config),
-        'needed_by': {
-            'svc_systemd:nginx',
-            'svc_systemd:nginx:restart',
-        },
-        'triggers': {
-            'svc_systemd:nginx:restart',
-        },
-    }
-    
-for name, config in {
-    **node.metadata.get('nginx/default_vhosts'),
-    **node.metadata.get('nginx/vhosts'),
-}.items():
+
+for name, config in node.metadata.get('nginx/vhosts').items():
+    print(name)
     files[f'/etc/nginx/sites/{name}'] = {
-        'content': repo.libs.nginx.render_config({
-            'server': config,
-        }),
+        'content': Template(filename=join(repo.path, 'data', config['content'])).render(
+            server_name=name,
+            **config.get('context', {}),
+        ),
         'needs': [],
         'needed_by': {
             'svc_systemd:nginx',
diff --git a/bundles/nginx/metadata.py b/bundles/nginx/metadata.py
index 4a60e7e..12c0df8 100644
--- a/bundles/nginx/metadata.py
+++ b/bundles/nginx/metadata.py
@@ -7,26 +7,6 @@ defaults = {
         },
     },
     'nginx': {
-        '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': [
@@ -46,7 +26,14 @@ defaults = {
                'stub_status': '',
             },
         },
-        'vhosts': {},
+        'vhosts': {
+            # '80': {
+            #     'content': 'nginx/80.conf',
+            # },
+            # 'stub_status': {
+            #     'content': 'nginx/stub_status.conf',
+            # },
+        },
         'includes': {},
     },
 }
diff --git a/bundles/roundcube/metadata.py b/bundles/roundcube/metadata.py
index 38612a6..f35a743 100644
--- a/bundles/roundcube/metadata.py
+++ b/bundles/roundcube/metadata.py
@@ -56,10 +56,10 @@ def vhost(metadata):
         'nginx': {
             'vhosts': {
                 metadata.get('mailserver/hostname'): {
-                    'root': '/opt/roundcube',
-                    'include': [
-                        'php.conf',
-                    ],
+                    'content': 'nginx/php.conf',
+                    'context': {
+                        'root': '/opt/roundcube',
+                    },
                 },
             },
         },
diff --git a/data/nextcloud/vhost.conf b/data/nextcloud/vhost.conf
new file mode 100644
index 0000000..9c0c663
--- /dev/null
+++ b/data/nextcloud/vhost.conf
@@ -0,0 +1,100 @@
+upstream php-handler {
+    server unix:/var/run/php/php7.3-fpm.sock;
+}
+
+server {
+    listen 443      ssl http2;
+    listen [::]:443 ssl http2;
+
+    server_name ${server_name};
+
+    ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
+    ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
+
+    client_max_body_size 512M;
+    fastcgi_buffers 64 4K;
+
+    gzip on;
+    gzip_vary on;
+    gzip_comp_level 4;
+    gzip_min_length 256;
+    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
+    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
+
+    add_header Referrer-Policy                      "no-referrer"   always;
+    add_header X-Content-Type-Options               "nosniff"       always;
+    add_header X-Download-Options                   "noopen"        always;
+    add_header X-Frame-Options                      "SAMEORIGIN"    always;
+    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
+    add_header X-Robots-Tag                         "none"          always;
+    add_header X-XSS-Protection                     "1; mode=block" always;
+
+    fastcgi_hide_header X-Powered-By;
+
+    root ${root};
+
+    index index.php index.html /index.php$request_uri;
+
+    location = / {
+        if ( $http_user_agent ~ ^DavClnt ) {
+            return 302 /remote.php/webdav/$is_args$args;
+        }
+    }
+
+    location = /robots.txt {
+        allow all;
+        log_not_found off;
+        access_log off;
+    }
+
+    location ^~ /.well-known {
+        location = /.well-known/carddav { return 301 /remote.php/dav/; }
+        location = /.well-known/caldav  { return 301 /remote.php/dav/; }
+        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
+        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }
+        return 301 /index.php$request_uri;
+    }
+
+    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
+    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }
+
+    location ~ \.php(?:$|/) {
+        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+        set $path_info $fastcgi_path_info;
+
+        try_files $fastcgi_script_name =404;
+
+        include fastcgi_params;
+        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+        fastcgi_param PATH_INFO $path_info;
+        fastcgi_param HTTPS on;
+
+        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
+        fastcgi_param front_controller_active true;     # Enable pretty urls
+        fastcgi_pass php-handler;
+
+        fastcgi_intercept_errors on;
+        fastcgi_request_buffering off;
+    }
+
+    location ~ \.(?:css|js|svg|gif)$ {
+        try_files $uri /index.php$request_uri;
+        expires 6M;         # Cache-Control policy borrowed from `.htaccess`
+        access_log off;     # Optional: Don't log access to assets
+    }
+
+    location ~ \.woff2?$ {
+        try_files $uri /index.php$request_uri;
+        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
+        access_log off;     # Optional: Don't log access to assets
+    }
+
+    # Rule borrowed from `.htaccess`
+    location /remote {
+        return 301 /remote.php$request_uri;
+    }
+
+    location / {
+        try_files $uri $uri/ /index.php$request_uri;
+    }
+}
diff --git a/data/nginx/php.conf b/data/nginx/php.conf
new file mode 100644
index 0000000..c360d7c
--- /dev/null
+++ b/data/nginx/php.conf
@@ -0,0 +1,6 @@
+server {
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+    server_name ${server_name};
+    root ${root};
+}
diff --git a/data/nginx/proxy_pass.conf b/data/nginx/proxy_pass.conf
new file mode 100644
index 0000000..906ad0c
--- /dev/null
+++ b/data/nginx/proxy_pass.conf
@@ -0,0 +1,16 @@
+server {
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+    server_name ${server_name};
+    
+    ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
+    ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
+
+    location / {
+        proxy_pass ${target};
+    }
+
+    location /.well-known/acme-challenge/ {
+        alias /var/lib/dehydrated/acme-challenges/;
+    }
+}
diff --git a/nodes/home.server.py b/nodes/home.server.py
index 2c578b2..ffc3659 100644
--- a/nodes/home.server.py
+++ b/nodes/home.server.py
@@ -4,7 +4,7 @@
         'archive',
         'backup',
         'debian-10',
-#        'nextcloud',
+        'nextcloud',
         'monitored',
         'webserver',
     ],
diff --git a/nodes/htz.mails.py b/nodes/htz.mails.py
index e6ab74f..ea209e8 100644
--- a/nodes/htz.mails.py
+++ b/nodes/htz.mails.py
@@ -11,7 +11,7 @@
         'dnsserver',
     ],
     'bundles': [
-        'nextcloud',
+#        'nextcloud',
         'wireguard',
         'zfs',
     ],
@@ -79,6 +79,26 @@
                 # 'woodpipe.de',
             ],
         },
+        'nginx': {
+            'vhosts': {
+                'cloud.sublimity.de': {
+                    'content': 'nginx/proxy_pass.conf',
+                    'context': {
+                        'target': 'https://cloud.sublimity.de:443',
+                    }
+                }
+            }
+        },
+        'nginx': {
+            'vhosts': {
+                'git.sublimity.de': {
+                    'content': 'nginx/proxy_pass.conf',
+                    'context': {
+                        'target': 'https://git.sublimity.de:443',
+                    }
+                }
+            }
+        },
         'roundcube': {
             'product_name': 'Sublimity Mail',
             'version': '1.4.11',