I have the same issue on a fresh Mailcow deployment.
When using the default config in mailcow.conf, everything works fine:
HTTP_BIND=
HTTP_PORT=80
HTTPS_BIND=
HTTPS_PORT=443
Changing mailcow.conf to the below configuration results in an HTTP 301 endless loop when trying to access the web interface:
HTTP_BIND=127.0.0.1
HTTP_PORT=8080
HTTPS_BIND=127.0.0.1
HTTPS_PORT=8443
Nginx is installed directly on the host, i.e. non-containerized.
The config looks as follows:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name mail.mydomain.com autodiscover.* autoconfig.*;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name mail.mydomain.com autodiscover.* autoconfig.*;
ssl_certificate /opt/mailcow-dockerized/data/assets/ssl/cert.pem;
ssl_certificate_key /opt/mailcow-dockerized/data/assets/ssl/key.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# Siehe https://ssl-config.mozilla.org/#server=nginx für die neuesten Empfehlungen zu ssl-Einstellungen
# Ein Beispiel für eine Konfiguration ist unten angegeben
ssl_protocols TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_prefer_server_ciphers off;
location /Microsoft-Server-ActiveSync {
proxy_pass http://127.0.0.1:8080/Microsoft-Server-ActiveSync;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 75;
proxy_send_timeout 3650;
proxy_read_timeout 3650;
proxy_buffers 64 512k; # Seit dem 2022-04 Update nötig für SOGo
client_body_buffer_size 512k;
client_max_body_size 0;
}
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 0;
# Die folgenden Proxy-Buffer müssen gesetzt werden, wenn Sie SOGo nach dem Update 2022-04 (April 2022) verwenden wollen
# Andernfalls wird ein Login wie folgt fehlschlagen: https://github.com/mailcow/mailcow-dockerized/issues/4537
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
}
}
Running curl on the mailcow domain results in the HTTP 301:
curl https://mail.mydomain.com -v
* Host mail.mydomain.com:443 was resolved.
* IPv6: (none)
* IPv4: <redacted>
* Trying <redacted>:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=mail.mydomain.com
* start date: Dec 21 20:26:15 2025 GMT
* expire date: Mar 21 20:26:14 2026 GMT
* subjectAltName: host "mail.mydomain.com" matched cert's "mail.mydomain.com"
* issuer: C=US; O=Let's Encrypt; CN=R13
* SSL certificate verify ok.
* Certificate level 0: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* Connected to mail.mydomain.com (<redacted>) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://mail.mydomain.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: mail.mydomain.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: mail.mydomain.com
> User-Agent: curl/8.14.1
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Request completely sent off
< HTTP/2 301
< server: nginx
< date: Mon, 22 Dec 2025 22:41:04 GMT
< content-type: text/html
< content-length: 162
< location: https://mail.mydomain.com/
<
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host mail.mydomain.com left intact
Running curl directly on https://127.0.0.1:8080 yields the same HTTP 301:
curl http://127.0.0.1:8080 -v
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Server: nginx
< Date: Mon, 22 Dec 2025 22:43:35 GMT
< Content-Type: text/html
< Content-Length: 162
< Connection: keep-alive
< Location: https://127.0.0.1/
<
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact
Changing mailcow.conf back to the defaults and running docker compose down && docker compose up -d, everything begins to work again.
Any ideas?