diff --git a/data/Dockerfiles/bootstrap/main.py b/data/Dockerfiles/bootstrap/main.py index 05cf6d5ef..50d2bc011 100644 --- a/data/Dockerfiles/bootstrap/main.py +++ b/data/Dockerfiles/bootstrap/main.py @@ -6,6 +6,8 @@ def main(): if container_name == "sogo-mailcow": from modules.BootstrapSogo import Bootstrap + elif container_name == "nginx-mailcow": + from modules.BootstrapNginx import Bootstrap else: print(f"No bootstrap handler for container: {container_name}", file=sys.stderr) sys.exit(1) diff --git a/data/Dockerfiles/bootstrap/modules/BootstrapBase.py b/data/Dockerfiles/bootstrap/modules/BootstrapBase.py index b7e95abc8..6192e5505 100644 --- a/data/Dockerfiles/bootstrap/modules/BootstrapBase.py +++ b/data/Dockerfiles/bootstrap/modules/BootstrapBase.py @@ -347,7 +347,7 @@ class BootstrapBase: if self.mysql_conn.is_connected(): print("MySQL is up and ready!") break - except Error as e: + except mysql.connector.Error as e: print(f"Waiting for MySQL... ({e})") time.sleep(2) @@ -390,6 +390,30 @@ class BootstrapBase: print(f"Waiting for schema update... (DB: {current_version}, Expected: {expected_version})") time.sleep(check_interval) + def wait_for_host(self, host, retry_interval=1.0, count=1): + """ + Waits for a host to respond to ICMP ping. + + Args: + host (str): Hostname or IP to ping. + retry_interval (float): Seconds to wait between pings. + count (int): Number of ping packets to send per check (default 1). + """ + while True: + try: + result = subprocess.run( + ["ping", "-c", str(count), host], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL + ) + if result.returncode == 0: + print(f"{host} is reachable via ping.") + break + except Exception: + pass + print(f"Waiting for {host}...") + time.sleep(retry_interval) + def _get_current_db_version(self): """ Fetches the current schema version from the database. diff --git a/data/Dockerfiles/bootstrap/modules/BootstrapNginx.py b/data/Dockerfiles/bootstrap/modules/BootstrapNginx.py new file mode 100644 index 000000000..9733ff422 --- /dev/null +++ b/data/Dockerfiles/bootstrap/modules/BootstrapNginx.py @@ -0,0 +1,69 @@ +from jinja2 import Environment, FileSystemLoader +from modules.BootstrapBase import BootstrapBase +from pathlib import Path +import os +import sys +import time + +class Bootstrap(BootstrapBase): + def bootstrap(self): + # Connect to MySQL + self.connect_mysql() + + # wait for Hosts + php_service = os.getenv("PHPFPMHOST") or "php-fpm-mailcow" + rspamd_service = os.getenv("RSPAMDHOST") or "rspamd-mailcow" + sogo_service = os.getenv("SOGOHOST") or os.getenv("IPV4_NETWORK", "172.22.1") + ".248" + self.wait_for_host(php_service) + if not self.isYes(os.getenv("SKIP_RSPAMD", False)): + self.wait_for_host(rspamd_service) + if not self.isYes(os.getenv("SKIP_SOGO", False)): + self.wait_for_host(sogo_service) + + # Setup Jinja2 Environment and load vars + self.env = Environment( + loader=FileSystemLoader('./etc/nginx/conf.d/templates'), + keep_trailing_newline=True, + lstrip_blocks=False, + trim_blocks=False + ) + extra_vars = { + "VALID_CERT_DIRS": self.get_valid_cert_dirs(), + 'TRUSTED_PROXIES': [item.strip() for item in os.getenv("TRUSTED_PROXIES", "").split(",") if item.strip()], + 'ADDITIONAL_SERVER_NAMES': [item.strip() for item in os.getenv("ADDITIONAL_SERVER_NAMES", "").split(",") if item.strip()], + } + self.env_vars = self.prepare_template_vars('/overwrites.json', extra_vars) + + print("Set Timezone") + self.set_timezone() + + print("Render config") + self.render_config("nginx.conf.j2", "/etc/nginx/nginx.conf") + self.render_config("sites-default.conf.j2", "/etc/nginx/includes/sites-default.conf") + self.render_config("server_name.active.j2", "/etc/nginx/conf.d/server_name.active") + self.render_config("listen_plain.active.j2", "/etc/nginx/conf.d/listen_plain.active") + self.render_config("listen_ssl.active.j2", "/etc/nginx/conf.d/listen_ssl.active") + + def get_valid_cert_dirs(self): + ssl_dir = '/etc/ssl/mail/' + valid_cert_dirs = [] + for d in os.listdir(ssl_dir): + full_path = os.path.join(ssl_dir, d) + if not os.path.isdir(full_path): + continue + + cert_path = os.path.join(full_path, 'cert.pem') + key_path = os.path.join(full_path, 'key.pem') + domains_path = os.path.join(full_path, 'domains') + + if os.path.isfile(cert_path) and os.path.isfile(key_path) and os.path.isfile(domains_path): + with open(domains_path, 'r') as file: + domains = file.read().strip() + domains_list = domains.split() + if domains_list and os.getenv("MAILCOW_HOSTNAME", "") not in domains_list: + valid_cert_dirs.append({ + 'cert_path': full_path + '/', + 'domains': domains + }) + + return valid_cert_dirs diff --git a/data/Dockerfiles/nginx/Dockerfile b/data/Dockerfiles/nginx/Dockerfile index 7d2ce34f3..a07c30ae8 100644 --- a/data/Dockerfiles/nginx/Dockerfile +++ b/data/Dockerfiles/nginx/Dockerfile @@ -5,14 +5,20 @@ ENV PIP_BREAK_SYSTEM_PACKAGES=1 RUN apk add --no-cache nginx \ python3 \ + supervisor \ py3-pip && \ pip install --upgrade pip && \ - pip install Jinja2 + pip install Jinja2 \ + mysql-connector-python RUN mkdir -p /etc/nginx/includes -COPY ./bootstrap.py / -COPY ./docker-entrypoint.sh / +COPY data/Dockerfiles/bootstrap /bootstrap +COPY data/Dockerfiles/nginx/docker-entrypoint.sh / +COPY data/Dockerfiles/nginx/supervisord.conf /etc/supervisor/supervisord.conf +COPY data/Dockerfiles/nginx/stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["nginx", "-g", "daemon off;"] +RUN chmod +x /docker-entrypoint.sh +RUN chmod +x /usr/local/sbin/stop-supervisor.sh + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/data/Dockerfiles/nginx/bootstrap.py b/data/Dockerfiles/nginx/bootstrap.py deleted file mode 100644 index 11e6fc202..000000000 --- a/data/Dockerfiles/nginx/bootstrap.py +++ /dev/null @@ -1,100 +0,0 @@ -import os -import subprocess -from jinja2 import Environment, FileSystemLoader - -def includes_conf(env, template_vars): - server_name = "server_name.active" - listen_plain = "listen_plain.active" - listen_ssl = "listen_ssl.active" - - server_name_config = f"server_name {template_vars['MAILCOW_HOSTNAME']} autodiscover.* autoconfig.* {' '.join(template_vars['ADDITIONAL_SERVER_NAMES'])};" - listen_plain_config = f"listen {template_vars['HTTP_PORT']};" - listen_ssl_config = f"listen {template_vars['HTTPS_PORT']};" - if not template_vars['DISABLE_IPv6']: - listen_plain_config += f"\nlisten [::]:{template_vars['HTTP_PORT']};" - listen_ssl_config += f"\nlisten [::]:{template_vars['HTTPS_PORT']} ssl;" - listen_ssl_config += "\nhttp2 on;" - - with open(f"/etc/nginx/conf.d/{server_name}", "w") as f: - f.write(server_name_config) - - with open(f"/etc/nginx/conf.d/{listen_plain}", "w") as f: - f.write(listen_plain_config) - - with open(f"/etc/nginx/conf.d/{listen_ssl}", "w") as f: - f.write(listen_ssl_config) - -def sites_default_conf(env, template_vars): - config_name = "sites-default.conf" - template = env.get_template(f"{config_name}.j2") - config = template.render(template_vars) - - with open(f"/etc/nginx/includes/{config_name}", "w") as f: - f.write(config) - -def nginx_conf(env, template_vars): - config_name = "nginx.conf" - template = env.get_template(f"{config_name}.j2") - config = template.render(template_vars) - - with open(f"/etc/nginx/{config_name}", "w") as f: - f.write(config) - -def prepare_template_vars(): - ipv4_network = os.getenv("IPV4_NETWORK", "172.22.1") - additional_server_names = os.getenv("ADDITIONAL_SERVER_NAMES", "") - trusted_proxies = os.getenv("TRUSTED_PROXIES", "") - - template_vars = { - 'IPV4_NETWORK': ipv4_network, - 'TRUSTED_PROXIES': [item.strip() for item in trusted_proxies.split(",") if item.strip()], - 'SKIP_RSPAMD': os.getenv("SKIP_RSPAMD", "n").lower() in ("y", "yes"), - 'SKIP_SOGO': os.getenv("SKIP_SOGO", "n").lower() in ("y", "yes"), - 'NGINX_USE_PROXY_PROTOCOL': os.getenv("NGINX_USE_PROXY_PROTOCOL", "n").lower() in ("y", "yes"), - 'MAILCOW_HOSTNAME': os.getenv("MAILCOW_HOSTNAME", ""), - 'ADDITIONAL_SERVER_NAMES': [item.strip() for item in additional_server_names.split(",") if item.strip()], - 'HTTP_PORT': os.getenv("HTTP_PORT", "80"), - 'HTTPS_PORT': os.getenv("HTTPS_PORT", "443"), - 'SOGOHOST': os.getenv("SOGOHOST", ipv4_network + ".248"), - 'RSPAMDHOST': os.getenv("RSPAMDHOST", "rspamd-mailcow"), - 'PHPFPMHOST': os.getenv("PHPFPMHOST", "php-fpm-mailcow"), - 'DISABLE_IPv6': os.getenv("DISABLE_IPv6", "n").lower() in ("y", "yes"), - 'HTTP_REDIRECT': os.getenv("HTTP_REDIRECT", "n").lower() in ("y", "yes"), - } - - ssl_dir = '/etc/ssl/mail/' - template_vars['valid_cert_dirs'] = [] - for d in os.listdir(ssl_dir): - full_path = os.path.join(ssl_dir, d) - if not os.path.isdir(full_path): - continue - - cert_path = os.path.join(full_path, 'cert.pem') - key_path = os.path.join(full_path, 'key.pem') - domains_path = os.path.join(full_path, 'domains') - - if os.path.isfile(cert_path) and os.path.isfile(key_path) and os.path.isfile(domains_path): - with open(domains_path, 'r') as file: - domains = file.read().strip() - domains_list = domains.split() - if domains_list and template_vars["MAILCOW_HOSTNAME"] not in domains_list: - template_vars['valid_cert_dirs'].append({ - 'cert_path': full_path + '/', - 'domains': domains - }) - - return template_vars - -def main(): - env = Environment(loader=FileSystemLoader('./etc/nginx/conf.d/templates')) - - # Render config - print("Render config") - template_vars = prepare_template_vars() - sites_default_conf(env, template_vars) - nginx_conf(env, template_vars) - includes_conf(env, template_vars) - - -if __name__ == "__main__": - main() diff --git a/data/Dockerfiles/nginx/docker-entrypoint.sh b/data/Dockerfiles/nginx/docker-entrypoint.sh index 45e327ede..c739a9af1 100755 --- a/data/Dockerfiles/nginx/docker-entrypoint.sh +++ b/data/Dockerfiles/nginx/docker-entrypoint.sh @@ -1,26 +1,12 @@ #!/bin/sh -PHPFPMHOST=${PHPFPMHOST:-"php-fpm-mailcow"} -SOGOHOST=${SOGOHOST:-"$IPV4_NETWORK.248"} -RSPAMDHOST=${RSPAMDHOST:-"rspamd-mailcow"} +python3 -u /bootstrap/main.py +BOOTSTRAP_EXIT_CODE=$? -until ping ${PHPFPMHOST} -c1 > /dev/null; do - echo "Waiting for PHP..." - sleep 1 -done -if ! printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then - until ping ${SOGOHOST} -c1 > /dev/null; do - echo "Waiting for SOGo..." - sleep 1 - done -fi -if ! printf "%s\n" "${SKIP_RSPAMD}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then - until ping ${RSPAMDHOST} -c1 > /dev/null; do - echo "Waiting for Rspamd..." - sleep 1 - done +if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then + echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Nginx." + exit $BOOTSTRAP_EXIT_CODE fi -python3 /bootstrap.py - -exec "$@" +echo "Bootstrap succeeded. Starting Nginx..." +nginx -g "daemon off;" diff --git a/data/Dockerfiles/nginx/stop-supervisor.sh b/data/Dockerfiles/nginx/stop-supervisor.sh new file mode 100755 index 000000000..5394490ce --- /dev/null +++ b/data/Dockerfiles/nginx/stop-supervisor.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +printf "READY\n"; + +while read line; do + echo "Processing Event: $line" >&2; + kill -3 $(cat "/var/run/supervisord.pid") +done < /dev/stdin diff --git a/data/Dockerfiles/nginx/supervisord.conf b/data/Dockerfiles/nginx/supervisord.conf new file mode 100644 index 000000000..e6c3c89d5 --- /dev/null +++ b/data/Dockerfiles/nginx/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true +user=root + +[program:syslog-ng] +command=/usr/sbin/syslog-ng --foreground --no-caps +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autostart=true +priority=1 + +[program:bootstrap] +command=/docker-entrypoint.sh +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +priority=2 +startretries=10 +autorestart=true +stopwaitsecs=120 + +[eventlistener:processes] +command=/usr/local/sbin/stop-supervisor.sh +events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL diff --git a/data/Dockerfiles/sogo/supervisord.conf b/data/Dockerfiles/sogo/supervisord.conf index 63b4869cf..e6c3c89d5 100644 --- a/data/Dockerfiles/sogo/supervisord.conf +++ b/data/Dockerfiles/sogo/supervisord.conf @@ -11,7 +11,7 @@ stderr_logfile_maxbytes=0 autostart=true priority=1 -[program:bootstrap-sogo] +[program:bootstrap] command=/docker-entrypoint.sh stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 diff --git a/data/conf/nginx/templates/listen_plain.active.j2 b/data/conf/nginx/templates/listen_plain.active.j2 new file mode 100644 index 000000000..dada8eca8 --- /dev/null +++ b/data/conf/nginx/templates/listen_plain.active.j2 @@ -0,0 +1,2 @@ +listen {{ HTTP_PORT }}; +listen [::]:{{ HTTP_PORT }}; diff --git a/data/conf/nginx/templates/listen_ssl.active.j2 b/data/conf/nginx/templates/listen_ssl.active.j2 new file mode 100644 index 000000000..b38daafec --- /dev/null +++ b/data/conf/nginx/templates/listen_ssl.active.j2 @@ -0,0 +1,2 @@ +listen {{ HTTPS_PORT }} ssl http2; +listen [::]:{{ HTTPS_PORT }} ssl http2; diff --git a/data/conf/nginx/templates/nginx.conf.j2 b/data/conf/nginx/templates/nginx.conf.j2 index ff5f8f184..49b0ad579 100644 --- a/data/conf/nginx/templates/nginx.conf.j2 +++ b/data/conf/nginx/templates/nginx.conf.j2 @@ -41,7 +41,7 @@ http { https https; } - {% if HTTP_REDIRECT %} + {% if HTTP_REDIRECT|lower in ["y", "yes"] %} # HTTP to HTTPS redirect server { root /web; @@ -65,16 +65,16 @@ http { server { listen 127.0.0.1:65510; # sogo-auth verify internal - {% if not HTTP_REDIRECT %} - listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; - {% if not DISABLE_IPv6 %} - {% if not HTTP_REDIRECT %} - listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not DISABLE_IPv6|lower in ["y", "yes"] %} + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; {%endif%} http2 on; @@ -92,16 +92,16 @@ http { server { listen 127.0.0.1:65510; # sogo-auth verify internal - {% if not HTTP_REDIRECT %} - listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; - {% if not DISABLE_IPv6 %} - {% if not HTTP_REDIRECT %} - listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not DISABLE_IPv6|lower in ["y", "yes"] %} + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; {%endif%} http2 on; @@ -118,7 +118,7 @@ http { # rspamd dynmaps: server { listen 8081; - {% if not DISABLE_IPv6 %} + {% if not DISABLE_IPv6|lower in ["y", "yes"] %} listen [::]:8081; {%endif%} index index.php index.html; @@ -184,18 +184,18 @@ http { include /etc/nginx/conf.d/*.conf; - {% for cert in valid_cert_dirs %} + {% for cert in VALID_CERT_DIRS %} server { - {% if not HTTP_REDIRECT %} - listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; - {% if not DISABLE_IPv6 %} - {% if not HTTP_REDIRECT %} - listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%}; + {% if not DISABLE_IPv6|lower in ["y", "yes"] %} + {% if not HTTP_REDIRECT|lower in ["y", "yes"] %} + listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%}; {%endif%} - listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl; + listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} proxy_protocol{%endif%} ssl; {%endif%} http2 on; diff --git a/data/conf/nginx/templates/server_name.active.j2 b/data/conf/nginx/templates/server_name.active.j2 new file mode 100644 index 000000000..270334def --- /dev/null +++ b/data/conf/nginx/templates/server_name.active.j2 @@ -0,0 +1 @@ +server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }}; diff --git a/data/conf/nginx/templates/sites-default.conf.j2 b/data/conf/nginx/templates/sites-default.conf.j2 index 574bdb052..fcf3a2274 100644 --- a/data/conf/nginx/templates/sites-default.conf.j2 +++ b/data/conf/nginx/templates/sites-default.conf.j2 @@ -55,7 +55,7 @@ set_real_ip_from fc00::/7; {% for TRUSTED_PROXY in TRUSTED_PROXIES %} set_real_ip_from {{ TRUSTED_PROXY }}; {% endfor %} -{% if not NGINX_USE_PROXY_PROTOCOL %} +{% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %} real_ip_header X-Forwarded-For; {% else %} real_ip_header proxy_protocol; @@ -137,28 +137,28 @@ location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml { try_files /autoconfig.php =404; } -{% if not SKIP_RSPAMD %} +{% if not SKIP_RSPAMD|lower in ["y", "yes"] %} location /rspamd/ { location /rspamd/auth { # proxy_pass is not inherited proxy_pass http://{{ RSPAMDHOST }}:11334/auth; proxy_intercept_errors on; proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; - proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; proxy_redirect off; error_page 401 /_rspamderror.php; } proxy_pass http://{{ RSPAMDHOST }}:11334/; proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; - proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; proxy_redirect off; } {% endif %} -{% if not SKIP_SOGO %} +{% if not SKIP_SOGO|lower in ["y", "yes"] %} location ^~ /principals { return 301 /SOGo/dav; } @@ -184,8 +184,8 @@ location ^~ /Microsoft-Server-ActiveSync { proxy_pass http://{{ SOGOHOST }}:20000/SOGo/Microsoft-Server-ActiveSync; - proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; - proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; proxy_connect_timeout 75; proxy_send_timeout 3600; proxy_read_timeout 3600; @@ -209,8 +209,8 @@ location ^~ /SOGo { proxy_pass http://{{ SOGOHOST }}:20000; - proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; - proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; proxy_set_header Host $http_host; proxy_set_header x-webobjects-server-protocol HTTP/1.0; proxy_set_header x-webobjects-remote-host $remote_addr; @@ -231,8 +231,8 @@ location ^~ /SOGo { proxy_pass http://{{ SOGOHOST }}:20000; - proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; - proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%}; + proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL|lower in ["y", "yes"] %}$remote_addr{% else %}$proxy_protocol_addr{%endif%}; proxy_set_header Host $http_host; proxy_set_header x-webobjects-server-protocol HTTP/1.0; proxy_set_header x-webobjects-remote-host $remote_addr; diff --git a/docker-compose.yml b/docker-compose.yml index 8f31c69c8..d531083ce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -200,8 +200,9 @@ services: - phpfpm sogo-mailcow: - image: ghcr.io/mailcow/sogo:1.133 + image: ghcr.io/mailcow/sogo:nightly-16052025 environment: + - CONTAINER_NAME=sogo-mailcow - DBNAME=${DBNAME} - DBUSER=${DBUSER} - DBPASS=${DBPASS} @@ -394,10 +395,14 @@ services: - php-fpm-mailcow - sogo-mailcow - rspamd-mailcow - image: ghcr.io/mailcow/nginx:1.03 + image: ghcr.io/mailcow/nginx:nightly-19052025 dns: - ${IPV4_NETWORK:-172.22.1}.254 environment: + - CONTAINER_NAME=nginx-mailcow + - DBNAME=${DBNAME} + - DBUSER=${DBUSER} + - DBPASS=${DBPASS} - HTTPS_PORT=${HTTPS_PORT:-443} - HTTP_PORT=${HTTP_PORT:-80} - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} @@ -407,10 +412,10 @@ services: - SKIP_RSPAMD=${SKIP_RSPAMD:-n} - DISABLE_IPv6=${DISABLE_IPv6:-n} - HTTP_REDIRECT=${HTTP_REDIRECT:-n} - - PHPFPMHOST=${PHPFPMHOST:-} - - SOGOHOST=${SOGOHOST:-} - - RSPAMDHOST=${RSPAMDHOST:-} - - REDISHOST=${REDISHOST:-} + - PHPFPMHOST=${PHPFPMHOST:-php-fpm-mailcow} + - RSPAMDHOST=${RSPAMDHOST:-rspamd-mailcow} + - SOGOHOST=${SOGOHOST:-${IPV4_NETWORK:-172.22.1}.248} + - REDISHOST=${REDISHOST:-redis-mailcow} - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - NGINX_USE_PROXY_PROTOCOL=${NGINX_USE_PROXY_PROTOCOL:-n} - TRUSTED_PROXIES=${TRUSTED_PROXIES:-} @@ -424,6 +429,7 @@ services: - ./data/web/inc/functions.inc.php:/mailcowauth/functions.inc.php:z - ./data/web/inc/functions.auth.inc.php:/mailcowauth/functions.auth.inc.php:z - ./data/web/inc/sessions.inc.php:/mailcowauth/sessions.inc.php:z + - mysql-socket-vol-1:/var/run/mysqld/ - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/ ports: - "${HTTPS_BIND:-}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}"