diff --git a/chatmaild/src/chatmaild/config.py b/chatmaild/src/chatmaild/config.py
index 591fd3e0..76b92a3d 100644
--- a/chatmaild/src/chatmaild/config.py
+++ b/chatmaild/src/chatmaild/config.py
@@ -1,5 +1,6 @@
import ipaddress
from pathlib import Path
+from random import randint
import iniconfig
@@ -41,6 +42,11 @@ class Config:
self.username_max_length = int(params.pop("username_max_length", 9))
self.password_min_length = int(params.pop("password_min_length", 9))
self.www_folder = params.pop("www_folder", "")
+
+ self.imap_port = int(params.pop("imap_port", 143))
+ self.imaps_port = int(params.pop("imaps_port", 993))
+ self.smtp_port = int(params.pop("smtp_port", 587))
+ self.smtps_port = int(params.pop("smtps_port", 465))
self.filtermail_smtp_port = int(params.pop("filtermail_smtp_port", "10080"))
self.filtermail_smtp_port_incoming = int(
params.pop("filtermail_smtp_port_incoming", "10081")
@@ -138,8 +144,15 @@ def parse_size_mb(limit):
def write_initial_config(inipath, mail_domain, overrides):
"""Write out default config file, using the specified config value overrides."""
- content = get_default_config_content(mail_domain, **overrides)
- inipath.write_text(content)
+ content = get_default_config_content(mail_domain, **overrides).splitlines()
+ used_ports = [25, 53, 80, 143, 402, 443, 465, 587, 993, 3340, 3903, 3904, 8443, 10080, 10081, 10082, 10083, 10025, 10026]
+ for config_key in ["smtp_port", "imap_port", "smtps_port", "imaps_port"]:
+ value = randint(1, 65536)
+ while value in used_ports:
+ value = randint(65535)
+ used_ports.append(value)
+ content.append(f"{config_key} = {value}")
+ inipath.write_text("\n".join(content))
def get_default_config_content(mail_domain, **overrides):
diff --git a/cmdeploy/src/cmdeploy/deployers.py b/cmdeploy/src/cmdeploy/deployers.py
index 88fdfd48..3417e5f8 100644
--- a/cmdeploy/src/cmdeploy/deployers.py
+++ b/cmdeploy/src/cmdeploy/deployers.py
@@ -495,15 +495,15 @@ def deploy_chatmail(config_path: Path, disable_mail: bool, website_only: bool) -
if config.tls_cert_mode == "acme":
port_services.append(("acmetool", 402))
port_services += [
- (["imap-login", "dovecot"], 143),
+ (["imap-login", "dovecot"], config.imap_port),
# acmetool previously listened on port 80,
# so don't complain during upgrade that moved it to port 402
# and gave the port to nginx.
(["acmetool", "nginx"], 80),
("nginx", 443),
- (["master", "smtpd"], 465),
- (["master", "smtpd"], 587),
- (["imap-login", "dovecot"], 993),
+ (["master", "smtpd"], config.smtp_port),
+ (["master", "smtpd"], config.smtps_port),
+ (["imap-login", "dovecot"], config.imaps_port),
("iroh-relay", 3340),
("mtail", 3903),
("stats", 3904),
diff --git a/cmdeploy/src/cmdeploy/nginx/autoconfig.xml.j2 b/cmdeploy/src/cmdeploy/nginx/autoconfig.xml.j2
index 6033347b..b3742c87 100644
--- a/cmdeploy/src/cmdeploy/nginx/autoconfig.xml.j2
+++ b/cmdeploy/src/cmdeploy/nginx/autoconfig.xml.j2
@@ -7,14 +7,14 @@
{{ config.mail_domain }}
{{ config.mail_domain }}
- 993
+ {{ config.imaps_port }}
SSL
password-cleartext
%EMAILADDRESS%
{{ config.mail_domain }}
- 143
+ {{ config.imap_port }}
STARTTLS
password-cleartext
%EMAILADDRESS%
@@ -28,14 +28,14 @@
{{ config.mail_domain }}
- 465
+ {{ config.smtps_port }}
SSL
password-cleartext
%EMAILADDRESS%
{{ config.mail_domain }}
- 587
+ {{ config.smtp_port }}
STARTTLS
password-cleartext
%EMAILADDRESS%
diff --git a/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 b/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2
index ac92662e..3b24ead6 100644
--- a/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2
+++ b/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2
@@ -31,6 +31,26 @@ stream {
~\bimap\b 127.0.0.1:993;
}
+ server {
+ listen {{ config.smtp_port }};
+ proxy_pass 127.0.0.1:587;
+ }
+
+ server {
+ listen {{ config.imap_port }};
+ proxy_pass 127.0.0.1:143;
+ }
+
+ server {
+ listen {{ config.smtps_port }};
+ proxy_pass 127.0.0.1:465;
+ }
+
+ server {
+ listen {{ config.imaps_port }};
+ proxy_pass 127.0.0.1:993;
+ }
+
server {
listen 443;
{% if not disable_ipv6 %}