mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
initial commit, mostly copied from another repo
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
*.swp
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
|
|||||||
14
README.md
Normal file
14
README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Chat Mail server configuration
|
||||||
|
|
||||||
|
This package deploys Postfix and Dovecot servers, including OpenDKIM for DKIM signing.
|
||||||
|
|
||||||
|
Postfix uses Dovecot for authentication as described in <https://www.postfix.org/SASL_README.html#server_dovecot>
|
||||||
|
|
||||||
|
## Ports
|
||||||
|
|
||||||
|
Postfix listens on ports 25 (smtp) and 587 (submission) and 465 (submissions).
|
||||||
|
Dovecot listens on ports 143(imap) and 993 (imaps).
|
||||||
|
|
||||||
|
## DNS
|
||||||
|
|
||||||
|
For DKIM you must add a DNS entry as in /etc/opendkim/selector.txt (where selector is the opendkim_selector configured in the chatmail inventory).
|
||||||
42
deploy.py
Normal file
42
deploy.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import os
|
||||||
|
from pyinfra import host, facts
|
||||||
|
from chatmail import deploy_chatmail
|
||||||
|
|
||||||
|
|
||||||
|
# the following is to prevent rate-limits with querying letsencrypt
|
||||||
|
# servers during deploys. It probably makes more sense to check
|
||||||
|
# in acmetool if a cert exists and skip recreating it because
|
||||||
|
# the acmetool pyinfra will renew certs via its cronjob, anyway.
|
||||||
|
|
||||||
|
def unpack_acme_state():
|
||||||
|
from pyinfra.operations import files, server
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
local_acme_filename = "acme_state.tar.gz"
|
||||||
|
|
||||||
|
if os.path.exists(local_acme_filename):
|
||||||
|
with open(local_acme_filename, "rb") as f:
|
||||||
|
acme_state = f.read()
|
||||||
|
files.put(
|
||||||
|
name="Upload acme state tar",
|
||||||
|
src=BytesIO(acme_state),
|
||||||
|
dest="/root/acme_state.tar.gz",
|
||||||
|
mode="600",
|
||||||
|
)
|
||||||
|
server.shell(
|
||||||
|
name="Unpack acme state directory",
|
||||||
|
commands=[
|
||||||
|
"mkdir -p /var/lib/acme && tar -C /var/lib/acme -x -z < /root/acme_state.tar.gz"
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print("no cached acme state found, deploy will recreate letsencrypt certs")
|
||||||
|
print("use this command to create a cache file:")
|
||||||
|
ssh_host = f"{host.data.ssh_user}@{host.data.host.name}"
|
||||||
|
cmd = f"'tar -C /var/lib/acme -c . -z' > {local_acme_filename}"
|
||||||
|
print(f"ssh {ssh_host} {cmd}")
|
||||||
|
|
||||||
|
|
||||||
|
unpack_acme_state()
|
||||||
|
|
||||||
|
deploy_chatmail()
|
||||||
7
pyproject.toml
Normal file
7
pyproject.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=45"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "chatmail"
|
||||||
|
version = "0.1"
|
||||||
215
src/chatmail/__init__.py
Normal file
215
src/chatmail/__init__.py
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
"""
|
||||||
|
Chat Mail pyinfra deploy.
|
||||||
|
"""
|
||||||
|
import importlib.resources
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
from pyinfra import host, logger
|
||||||
|
from pyinfra.operations import apt, files, server, systemd, python
|
||||||
|
from .acmetool import deploy_acmetool
|
||||||
|
|
||||||
|
|
||||||
|
def _install_chatctl() -> None:
|
||||||
|
"""Setup chatctl."""
|
||||||
|
files.put(
|
||||||
|
src=importlib.resources.files(__package__)
|
||||||
|
.joinpath("chatctl/chatctl.py")
|
||||||
|
.open("rb"),
|
||||||
|
dest="/home/vmail/chatctl",
|
||||||
|
user="vmail",
|
||||||
|
group="vmail",
|
||||||
|
mode="755",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _configure_opendkim(
|
||||||
|
domain: str, dkim_selector: str, dkim_key: str, dkim_txt: str
|
||||||
|
) -> bool:
|
||||||
|
"""Configures OpenDKIM"""
|
||||||
|
need_restart = False
|
||||||
|
|
||||||
|
main_config = files.template(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("opendkim/opendkim.conf"),
|
||||||
|
dest="/etc/opendkim.conf",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
config={"domain_name": domain, "opendkim_selector": dkim_selector},
|
||||||
|
)
|
||||||
|
|
||||||
|
files.directory(
|
||||||
|
name="Add opendkim socket directory to /var/spool/postfix",
|
||||||
|
path="/var/spool/postfix/opendkim",
|
||||||
|
user="opendkim",
|
||||||
|
group="opendkim",
|
||||||
|
mode="750",
|
||||||
|
present=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if dkim_key:
|
||||||
|
files.put(
|
||||||
|
name="Put the DKIM key",
|
||||||
|
src=StringIO(dkim_key),
|
||||||
|
dest=f"/etc/dkimkeys/{dkim_selector}.private",
|
||||||
|
mode="600",
|
||||||
|
)
|
||||||
|
files.put(
|
||||||
|
name="Put the DKIM DNS textfile",
|
||||||
|
src=StringIO(dkim_txt),
|
||||||
|
dest=f"/etc/dkimkeys/{dkim_selector}.txt",
|
||||||
|
mode="600",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
server.shell(
|
||||||
|
name="Generate OpenDKIM domain keys",
|
||||||
|
commands=[
|
||||||
|
f"opendkim-genkey -D /etc/dkimkeys -d {domain} -s {dkim_selector}"
|
||||||
|
],
|
||||||
|
_sudo=True,
|
||||||
|
_sudo_user="opendkim",
|
||||||
|
)
|
||||||
|
|
||||||
|
need_restart |= main_config.changed
|
||||||
|
|
||||||
|
return need_restart
|
||||||
|
|
||||||
|
|
||||||
|
def _configure_postfix(domain: str) -> bool:
|
||||||
|
"""Configures Postfix SMTP server."""
|
||||||
|
need_restart = False
|
||||||
|
|
||||||
|
main_config = files.template(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("postfix/main.cf.j2"),
|
||||||
|
dest="/etc/postfix/main.cf",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
config={"domain_name": domain},
|
||||||
|
)
|
||||||
|
need_restart |= main_config.changed
|
||||||
|
|
||||||
|
master_config = files.put(
|
||||||
|
src=importlib.resources.files(__package__)
|
||||||
|
.joinpath("postfix/master.cf")
|
||||||
|
.open("rb"),
|
||||||
|
dest="/etc/postfix/master.cf",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
)
|
||||||
|
need_restart |= master_config.changed
|
||||||
|
|
||||||
|
return need_restart
|
||||||
|
|
||||||
|
|
||||||
|
def _configure_dovecot(domain: str) -> bool:
|
||||||
|
"""Configures Dovecot IMAP server."""
|
||||||
|
need_restart = False
|
||||||
|
|
||||||
|
main_config = files.template(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("dovecot/dovecot.conf.j2"),
|
||||||
|
dest="/etc/dovecot/dovecot.conf",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
config={"hostname": domain},
|
||||||
|
)
|
||||||
|
need_restart |= main_config.changed
|
||||||
|
|
||||||
|
# luarocks install http lpeg_patterns fifo
|
||||||
|
auth_script = files.put(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("dovecot/auth.lua"),
|
||||||
|
dest="/etc/dovecot/auth.lua",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
)
|
||||||
|
need_restart |= auth_script.changed
|
||||||
|
|
||||||
|
return need_restart
|
||||||
|
|
||||||
|
|
||||||
|
def deploy_chatmail() -> None:
|
||||||
|
domain = host.data.domain
|
||||||
|
dkim_selector = host.data.dkim_selector
|
||||||
|
dkim_key = host.data.dkim_key
|
||||||
|
dkim_txt = host.data.dkim_txt
|
||||||
|
|
||||||
|
apt.update(name="apt update")
|
||||||
|
server.group(name="Create vmail group", group="vmail", system=True)
|
||||||
|
server.user(name="Create vmail user", user="vmail", group="vmail", system=True)
|
||||||
|
|
||||||
|
server.group(name="Create opendkim group", group="opendkim", system=True)
|
||||||
|
server.user(
|
||||||
|
name="Add postfix user to opendkim group for socket access",
|
||||||
|
user="postfix",
|
||||||
|
groups=["opendkim"],
|
||||||
|
system=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Deploy acmetool to have TLS certificates.
|
||||||
|
deploy_acmetool(domains=[domain])
|
||||||
|
|
||||||
|
apt.packages(
|
||||||
|
name="Install Postfix",
|
||||||
|
packages="postfix",
|
||||||
|
)
|
||||||
|
|
||||||
|
apt.packages(
|
||||||
|
name="Install Dovecot",
|
||||||
|
packages=[
|
||||||
|
"dovecot-imapd",
|
||||||
|
"dovecot-lmtpd",
|
||||||
|
"dovecot-auth-lua",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
apt.packages(
|
||||||
|
name="Install OpenDKIM",
|
||||||
|
packages=[
|
||||||
|
"opendkim",
|
||||||
|
"opendkim-tools",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
_install_chatctl()
|
||||||
|
dovecot_need_restart = _configure_dovecot(domain)
|
||||||
|
postfix_need_restart = _configure_postfix(domain)
|
||||||
|
opendkim_need_restart = _configure_opendkim(
|
||||||
|
domain, dkim_selector, dkim_key, dkim_txt
|
||||||
|
)
|
||||||
|
|
||||||
|
systemd.service(
|
||||||
|
name="Start and enable OpenDKIM",
|
||||||
|
service="opendkim.service",
|
||||||
|
running=True,
|
||||||
|
enabled=True,
|
||||||
|
restarted=opendkim_need_restart,
|
||||||
|
)
|
||||||
|
|
||||||
|
systemd.service(
|
||||||
|
name="Start and enable Postfix",
|
||||||
|
service="postfix.service",
|
||||||
|
running=True,
|
||||||
|
enabled=True,
|
||||||
|
restarted=postfix_need_restart,
|
||||||
|
)
|
||||||
|
|
||||||
|
systemd.service(
|
||||||
|
name="Start and enable Dovecot",
|
||||||
|
service="dovecot.service",
|
||||||
|
running=True,
|
||||||
|
enabled=True,
|
||||||
|
restarted=dovecot_need_restart,
|
||||||
|
)
|
||||||
|
|
||||||
|
def callback():
|
||||||
|
result = server.shell(
|
||||||
|
commands=[
|
||||||
|
f"""sed 's/\tIN/ 600 IN/;s/\t(//;s/\"$//;s/^\t \"//g; s/ ).*//' """
|
||||||
|
f"""/etc/dkimkeys/{dkim_selector}.txt | tr --delete '\n'"""
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger.info(f"Add this TXT entry into DNS zone: {result.stdout}")
|
||||||
|
|
||||||
|
python.call(name="Print TXT entry for DKIM", function=callback)
|
||||||
62
src/chatmail/acmetool/__init__.py
Normal file
62
src/chatmail/acmetool/__init__.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import importlib.resources
|
||||||
|
|
||||||
|
from pyinfra.operations import apt, files, systemd, server
|
||||||
|
|
||||||
|
|
||||||
|
def deploy_acmetool(nginx_hook=False, email="", domains=[]):
|
||||||
|
"""Deploy acmetool."""
|
||||||
|
apt.packages(
|
||||||
|
name="Install acmetool",
|
||||||
|
packages=["acmetool"],
|
||||||
|
)
|
||||||
|
|
||||||
|
files.put(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("acmetool.cron").open("rb"),
|
||||||
|
dest="/etc/cron.d/acmetool",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
)
|
||||||
|
|
||||||
|
if nginx_hook:
|
||||||
|
files.put(
|
||||||
|
src=importlib.resources.files(__package__)
|
||||||
|
.joinpath("acmetool.hook")
|
||||||
|
.open("rb"),
|
||||||
|
dest="/usr/lib/acme/hooks/nginx",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="744",
|
||||||
|
)
|
||||||
|
|
||||||
|
files.template(
|
||||||
|
src=importlib.resources.files(__package__).joinpath("response-file.yaml.j2"),
|
||||||
|
dest="/var/lib/acme/conf/responses",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
email=email,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_file = files.put(
|
||||||
|
src=importlib.resources.files(__package__)
|
||||||
|
.joinpath("acmetool-redirector.service")
|
||||||
|
.open("rb"),
|
||||||
|
dest="/etc/systemd/system/acmetool-redirector.service",
|
||||||
|
user="root",
|
||||||
|
group="root",
|
||||||
|
mode="644",
|
||||||
|
)
|
||||||
|
systemd.service(
|
||||||
|
name="Setup acmetool-redirector service",
|
||||||
|
service="acmetool-redirector.service",
|
||||||
|
running=True,
|
||||||
|
enabled=True,
|
||||||
|
restarted=service_file.changed,
|
||||||
|
)
|
||||||
|
|
||||||
|
for domain in domains:
|
||||||
|
server.shell(
|
||||||
|
name=f"Request certificate for {domain}",
|
||||||
|
commands=[f"acmetool want {domain}"],
|
||||||
|
)
|
||||||
11
src/chatmail/acmetool/acmetool-redirector.service
Normal file
11
src/chatmail/acmetool/acmetool-redirector.service
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=acmetool HTTP redirector
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=notify
|
||||||
|
ExecStart=/usr/bin/acmetool redirector --service.uid=daemon
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
4
src/chatmail/acmetool/acmetool.cron
Normal file
4
src/chatmail/acmetool/acmetool.cron
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
SHELL=/bin/sh
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
|
||||||
|
MAILTO=root
|
||||||
|
20 16 * * * root /usr/bin/acmetool --batch reconcile
|
||||||
5
src/chatmail/acmetool/acmetool.hook
Normal file
5
src/chatmail/acmetool/acmetool.hook
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
EVENT_NAME="$1"
|
||||||
|
[ "$EVENT_NAME" = "live-updated" ] || exit 42
|
||||||
|
systemctl restart nginx.service
|
||||||
2
src/chatmail/acmetool/response-file.yaml.j2
Normal file
2
src/chatmail/acmetool/response-file.yaml.j2
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"acme-enter-email": "{{ email }}"
|
||||||
|
"acme-agreement:https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf": true
|
||||||
17
src/chatmail/chatctl/chatctl.py
Normal file
17
src/chatmail/chatctl/chatctl.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import base64
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.argv[1] == "hexauth":
|
||||||
|
login = base64.b16decode(sys.argv[2])
|
||||||
|
password = base64.b16decode(sys.argv[3])
|
||||||
|
if login == b"link2xt@instant2.testrun.org" and password == b"Ahyei6ie":
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
elif sys.argv[1] == "hexlookup":
|
||||||
|
login = base64.b16decode(sys.argv[2])
|
||||||
|
if login == b"link2xt@instant2.testrun.org":
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
35
src/chatmail/dovecot/auth.lua
Normal file
35
src/chatmail/dovecot/auth.lua
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
-- Lua based authentication script for Dovecot.
|
||||||
|
--
|
||||||
|
-- It calls external chatctl command to answer requests.
|
||||||
|
|
||||||
|
-- Hexadecimal aka base16 encoding.
|
||||||
|
function hex(data)
|
||||||
|
return (data:gsub(".", function(char) return string.format("%2X", char:byte()) end))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Escape shell argument by hex encoding it and wrapping in quotes.
|
||||||
|
function escape(data)
|
||||||
|
return ("'"..hex(data).."'")
|
||||||
|
end
|
||||||
|
|
||||||
|
function auth_password_verify(request, password)
|
||||||
|
if os.execute("/home/vmail/chatctl hexauth "..escape(request.user).." "..escape(password)) then
|
||||||
|
return dovecot.auth.PASSDB_RESULT_OK, {}
|
||||||
|
end
|
||||||
|
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, ""
|
||||||
|
end
|
||||||
|
|
||||||
|
function auth_passdb_lookup(request)
|
||||||
|
if os.execute("/home/vmail/chatctl hexlookup "..escape(request.user)) then
|
||||||
|
return dovecot.auth.PASSDB_RESULT_OK, {}
|
||||||
|
end
|
||||||
|
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "no such user"
|
||||||
|
end
|
||||||
|
|
||||||
|
function auth_userdb_lookup(request)
|
||||||
|
if os.execute("/home/vmail/chatctl hexlookup "..escape(request.user)) then
|
||||||
|
return dovecot.auth.USERDB_RESULT_OK, "uid=vmail gid=vmail"
|
||||||
|
end
|
||||||
|
|
||||||
|
return dovecot.auth.USERDB_RESULT_USER_UNKNOWN, "no such user"
|
||||||
|
end
|
||||||
94
src/chatmail/dovecot/dovecot.conf.j2
Normal file
94
src/chatmail/dovecot/dovecot.conf.j2
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
## Dovecot configuration file
|
||||||
|
|
||||||
|
protocols = imap lmtp
|
||||||
|
|
||||||
|
auth_mechanisms = plain
|
||||||
|
|
||||||
|
# Authentication for system users.
|
||||||
|
passdb {
|
||||||
|
driver = lua
|
||||||
|
args = file=/etc/dovecot/auth.lua
|
||||||
|
}
|
||||||
|
userdb {
|
||||||
|
driver = lua
|
||||||
|
args = file=/etc/dovecot/auth.lua
|
||||||
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
## Mailbox locations and namespaces
|
||||||
|
##
|
||||||
|
|
||||||
|
# Mailboxes are stored in the "mail" directory of the vmail user home.
|
||||||
|
mail_location = maildir:/home/vmail/mail/%d/%u
|
||||||
|
|
||||||
|
namespace inbox {
|
||||||
|
inbox = yes
|
||||||
|
|
||||||
|
mailbox Drafts {
|
||||||
|
special_use = \Drafts
|
||||||
|
}
|
||||||
|
mailbox Junk {
|
||||||
|
special_use = \Junk
|
||||||
|
}
|
||||||
|
mailbox Trash {
|
||||||
|
special_use = \Trash
|
||||||
|
}
|
||||||
|
|
||||||
|
# For \Sent mailboxes there are two widely used names. We'll mark both of
|
||||||
|
# them as \Sent. User typically deletes one of them if duplicates are created.
|
||||||
|
mailbox Sent {
|
||||||
|
special_use = \Sent
|
||||||
|
}
|
||||||
|
mailbox "Sent Messages" {
|
||||||
|
special_use = \Sent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mail_uid = vmail
|
||||||
|
mail_gid = vmail
|
||||||
|
mail_privileged_group = vmail
|
||||||
|
|
||||||
|
##
|
||||||
|
## Mail processes
|
||||||
|
##
|
||||||
|
|
||||||
|
# Enable IMAP COMPRESS (RFC 4978).
|
||||||
|
# <https://datatracker.ietf.org/doc/html/rfc4978.html>
|
||||||
|
protocol imap {
|
||||||
|
mail_plugins = $mail_plugins imap_zlib
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin {
|
||||||
|
imap_compress_deflate_level = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
service lmtp {
|
||||||
|
user=vmail
|
||||||
|
|
||||||
|
unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
||||||
|
group = postfix
|
||||||
|
mode = 0600
|
||||||
|
user = postfix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service auth {
|
||||||
|
unix_listener /var/spool/postfix/private/auth {
|
||||||
|
mode = 0660
|
||||||
|
user = postfix
|
||||||
|
group = postfix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service auth-worker {
|
||||||
|
# Default is root.
|
||||||
|
# Drop privileges we don't need.
|
||||||
|
user = $default_internal_user
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl = required
|
||||||
|
ssl_cert = </var/lib/acme/live/{{ config.hostname }}/fullchain
|
||||||
|
ssl_key = </var/lib/acme/live/{{ config.hostname }}/privkey
|
||||||
|
ssl_dh = </usr/share/dovecot/dh.pem
|
||||||
|
ssl_min_protocol = TLSv1.2
|
||||||
|
ssl_prefer_server_ciphers = yes
|
||||||
51
src/chatmail/opendkim/opendkim.conf
Normal file
51
src/chatmail/opendkim/opendkim.conf
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# This is a basic configuration for signing and verifying. It can easily be
|
||||||
|
# adapted to suit a basic installation. See opendkim.conf(5) and
|
||||||
|
# /usr/share/doc/opendkim/examples/opendkim.conf.sample for complete
|
||||||
|
# documentation of available configuration parameters.
|
||||||
|
|
||||||
|
Syslog yes
|
||||||
|
SyslogSuccess yes
|
||||||
|
#LogWhy no
|
||||||
|
|
||||||
|
# Common signing and verification parameters. In Debian, the "From" header is
|
||||||
|
# oversigned, because it is often the identity key used by reputation systems
|
||||||
|
# and thus somewhat security sensitive.
|
||||||
|
Canonicalization relaxed/simple
|
||||||
|
#Mode sv
|
||||||
|
#SubDomains no
|
||||||
|
OversignHeaders From
|
||||||
|
|
||||||
|
# Signing domain, selector, and key (required). For example, perform signing
|
||||||
|
# for domain "example.com" with selector "2020" (2020._domainkey.example.com),
|
||||||
|
# using the private key stored in /etc/dkimkeys/example.private. More granular
|
||||||
|
# setup options can be found in /usr/share/doc/opendkim/README.opendkim.
|
||||||
|
Domain {{ config.domain_name }}
|
||||||
|
Selector {{ config.opendkim_selector }}
|
||||||
|
KeyFile /etc/dkimkeys/{{ config.opendkim_selector }}.private
|
||||||
|
|
||||||
|
# In Debian, opendkim runs as user "opendkim". A umask of 007 is required when
|
||||||
|
# using a local socket with MTAs that access the socket as a non-privileged
|
||||||
|
# user (for example, Postfix). You may need to add user "postfix" to group
|
||||||
|
# "opendkim" in that case.
|
||||||
|
UserID opendkim
|
||||||
|
UMask 007
|
||||||
|
|
||||||
|
# Socket for the MTA connection (required). If the MTA is inside a chroot jail,
|
||||||
|
# it must be ensured that the socket is accessible. In Debian, Postfix runs in
|
||||||
|
# a chroot in /var/spool/postfix, therefore a Unix socket would have to be
|
||||||
|
# configured as shown on the last line below.
|
||||||
|
#Socket local:/run/opendkim/opendkim.sock
|
||||||
|
#Socket inet:8891@localhost
|
||||||
|
#Socket inet:8891
|
||||||
|
Socket local:/var/spool/postfix/opendkim/opendkim.sock
|
||||||
|
|
||||||
|
PidFile /run/opendkim/opendkim.pid
|
||||||
|
|
||||||
|
# Hosts for which to sign rather than verify, default is 127.0.0.1. See the
|
||||||
|
# OPERATION section of opendkim(8) for more information.
|
||||||
|
#InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12
|
||||||
|
|
||||||
|
# The trust anchor enables DNSSEC. In Debian, the trust anchor file is provided
|
||||||
|
# by the package dns-root-data.
|
||||||
|
TrustAnchorFile /usr/share/dns/root.key
|
||||||
|
#Nameservers 127.0.0.1
|
||||||
48
src/chatmail/postfix/main.cf.j2
Normal file
48
src/chatmail/postfix/main.cf.j2
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
myorigin = {{ config.domain_name }}
|
||||||
|
|
||||||
|
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
|
||||||
|
biff = no
|
||||||
|
|
||||||
|
# appending .domain is the MUA's job.
|
||||||
|
append_dot_mydomain = no
|
||||||
|
|
||||||
|
# Uncomment the next line to generate "delayed mail" warnings
|
||||||
|
#delay_warning_time = 4h
|
||||||
|
|
||||||
|
readme_directory = no
|
||||||
|
|
||||||
|
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
|
||||||
|
# fresh installs.
|
||||||
|
compatibility_level = 2
|
||||||
|
|
||||||
|
# TLS parameters
|
||||||
|
smtpd_tls_cert_file=/var/lib/acme/live/{{ config.domain_name }}/fullchain
|
||||||
|
smtpd_tls_key_file=/var/lib/acme/live/{{ config.domain_name }}/privkey
|
||||||
|
smtpd_tls_security_level=may
|
||||||
|
|
||||||
|
smtp_tls_CApath=/etc/ssl/certs
|
||||||
|
smtp_tls_security_level=may
|
||||||
|
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||||
|
|
||||||
|
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
|
||||||
|
myhostname = {{ config.domain_name }}
|
||||||
|
alias_maps = hash:/etc/aliases
|
||||||
|
alias_database = hash:/etc/aliases
|
||||||
|
|
||||||
|
# Postfix does not deliver mail for any domain by itself.
|
||||||
|
# Primary domain is listed in `virtual_mailbox_domains` instead
|
||||||
|
# and handed over to Dovecot.
|
||||||
|
mydestination =
|
||||||
|
|
||||||
|
relayhost =
|
||||||
|
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
|
||||||
|
mailbox_size_limit = 0
|
||||||
|
recipient_delimiter = +
|
||||||
|
inet_interfaces = all
|
||||||
|
inet_protocols = all
|
||||||
|
|
||||||
|
virtual_transport = lmtp:unix:private/dovecot-lmtp
|
||||||
|
virtual_mailbox_domains = {{ config.domain_name }}
|
||||||
|
|
||||||
|
smtpd_milters = unix:opendkim/opendkim.sock
|
||||||
|
non_smtpd_milters = $smtpd_milters
|
||||||
72
src/chatmail/postfix/master.cf
Normal file
72
src/chatmail/postfix/master.cf
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#
|
||||||
|
# Postfix master process configuration file. For details on the format
|
||||||
|
# of the file, see the master(5) manual page (command: "man 5 master" or
|
||||||
|
# on-line: http://www.postfix.org/master.5.html).
|
||||||
|
#
|
||||||
|
# Do not forget to execute "postfix reload" after editing this file.
|
||||||
|
#
|
||||||
|
# ==========================================================================
|
||||||
|
# service type private unpriv chroot wakeup maxproc command + args
|
||||||
|
# (yes) (yes) (no) (never) (100)
|
||||||
|
# ==========================================================================
|
||||||
|
smtp inet n - y - - smtpd
|
||||||
|
#smtp inet n - y - 1 postscreen
|
||||||
|
#smtpd pass - - y - - smtpd
|
||||||
|
#dnsblog unix - - y - 0 dnsblog
|
||||||
|
#tlsproxy unix - - y - 0 tlsproxy
|
||||||
|
submission inet n - y - - smtpd
|
||||||
|
-o syslog_name=postfix/submission
|
||||||
|
-o smtpd_tls_security_level=encrypt
|
||||||
|
-o smtpd_sasl_auth_enable=yes
|
||||||
|
-o smtpd_sasl_type=dovecot
|
||||||
|
-o smtpd_sasl_path=private/auth
|
||||||
|
-o smtpd_tls_auth_only=yes
|
||||||
|
-o smtpd_reject_unlisted_recipient=no
|
||||||
|
-o smtpd_client_restrictions=$mua_client_restrictions
|
||||||
|
-o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||||
|
-o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||||
|
-o smtpd_recipient_restrictions=
|
||||||
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o milter_macro_daemon_name=ORIGINATING
|
||||||
|
smtps inet n - y - - smtpd
|
||||||
|
-o syslog_name=postfix/smtps
|
||||||
|
-o smtpd_tls_wrappermode=yes
|
||||||
|
-o smtpd_tls_security_level=encrypt
|
||||||
|
-o smtpd_sasl_auth_enable=yes
|
||||||
|
-o smtpd_sasl_type=dovecot
|
||||||
|
-o smtpd_sasl_path=private/auth
|
||||||
|
-o smtpd_reject_unlisted_recipient=no
|
||||||
|
-o smtpd_client_restrictions=$mua_client_restrictions
|
||||||
|
-o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||||
|
-o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||||
|
-o smtpd_recipient_restrictions=
|
||||||
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o milter_macro_daemon_name=ORIGINATING
|
||||||
|
#628 inet n - y - - qmqpd
|
||||||
|
pickup unix n - y 60 1 pickup
|
||||||
|
cleanup unix n - y - 0 cleanup
|
||||||
|
qmgr unix n - n 300 1 qmgr
|
||||||
|
#qmgr unix n - n 300 1 oqmgr
|
||||||
|
tlsmgr unix - - y 1000? 1 tlsmgr
|
||||||
|
rewrite unix - - y - - trivial-rewrite
|
||||||
|
bounce unix - - y - 0 bounce
|
||||||
|
defer unix - - y - 0 bounce
|
||||||
|
trace unix - - y - 0 bounce
|
||||||
|
verify unix - - y - 1 verify
|
||||||
|
flush unix n - y 1000? 0 flush
|
||||||
|
proxymap unix - - n - - proxymap
|
||||||
|
proxywrite unix - - n - 1 proxymap
|
||||||
|
smtp unix - - y - - smtp
|
||||||
|
relay unix - - y - - smtp
|
||||||
|
-o syslog_name=postfix/$service_name
|
||||||
|
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
|
||||||
|
showq unix n - y - - showq
|
||||||
|
error unix - - y - - error
|
||||||
|
retry unix - - y - - error
|
||||||
|
discard unix - - y - - discard
|
||||||
|
local unix - n n - - local
|
||||||
|
virtual unix - n n - - virtual
|
||||||
|
lmtp unix - - y - - lmtp
|
||||||
|
anvil unix - - y - 1 anvil
|
||||||
|
scache unix - - y - 1 scache
|
||||||
|
postlog unix-dgram n - n - 1 postlogd
|
||||||
Reference in New Issue
Block a user