Add mail setup and named configuration

This commit is contained in:
Adrian 2020-02-17 01:46:24 +01:00
parent 3200fc17e9
commit 694e6bf290
22 changed files with 258 additions and 0 deletions

49
mail/README.md Normal file
View file

@ -0,0 +1,49 @@
# Mail with SQLite
## Create User
```sh
sudo sed -i '$ a vmail:*:2000:2000::/data/mail:/usr/sbin/nologin' /etc/passwd
sudo sed -i '$ a vmail:x:2000:' /etc/group
sudo mkdir -p /data/mail/mail
sudo mkdir -p /data/mail/config
sudo chown vmail: /data/mail/*
cat schema.sql | sudo -u vmail sqlite3 /data/mail/config/vmail.db
sudo chmod 640 /data/mail/config/vmail.db
```
## Install Software
```sh
sudo apt install sqlite3 postfix postfix-sqlite dovecot-imapd dovecot-sqlite opendkim libopendbx1-sqlite3
```
## Apply Configuration
```sh
DOMAIN=example.com
sudo cp -r postfix dovecot /etc
sudo sed -i '$ r opendkim/local.conf' /etc/opendkim.conf
sudo sed -i s/example.com/$DOMAIN/ /etc/postfix/main.cf /etc/dovecot/local.conf
sudo sed -i '/include auth-system/ s/.*/#&/' /etc/dovecot/conf.d/10-auth.conf
sudo ln -s /data/mail/config/vmail.db /.opendkim-bug-241.db
sudo chown vmail:postfix /data/mail/config/vmail.db
opendkim-genkey -d $DOMAIN -s s
chmod +r s.private
cat dkim.sql | sed s/DOMAIN/$DOMAIN/ | sudo -u vmail sqlite3 /data/mail/config/vmail.db
cat s.txt
rm s.private s.txt
```
## Notes
* The `vmail.db` parent directory needs to be writeable by the user modifying the database
* The postfix process does not load the supplementary groups (`set_eugid` only sets one gid),
hence the vmail database needs to be readable by the postfix primary group
* The dovecot process runs as root and can access the database
* OpenDKIM's `dsn` parsing is broken and opens the database in the root directory

2
mail/dkim.sql Normal file
View file

@ -0,0 +1,2 @@
insert into dkim (match, key) values ("DOMAIN", "default");
insert into dkim_key (key, domain, selector, private_key) values ("default", "DOMAIN", "s", readfile("s.private"));

View file

@ -0,0 +1,9 @@
driver = sqlite
connect = /data/mail/config/vmail.db
user_query = SELECT \
REPLACE('/data/mail/mail/{dir}', '{dir}', maildir) AS home \
, REPLACE('maildir:/data/mail/mail/{dir}:LAYOUT=fs', '{dir}', maildir) AS mail \
FROM mailbox WHERE username = '%u' AND active = 1
password_query = SELECT password FROM mailbox WHERE username = '%u'

23
mail/dovecot/local.conf Normal file
View file

@ -0,0 +1,23 @@
protocols = imap
mail_uid = vmail
mail_gid = vmail
ssl = required
ssl_key = </data/ssl/certs/mail.example.com/privkey.pem
ssl_cert = </data/ssl/certs/mail.example.com/fullchain.pem
userdb {
driver = sql
args = /etc/dovecot/local-sql.conf.ext
}
passdb {
driver = sql
args = /etc/dovecot/local-sql.conf.ext
}
service auth {
unix_listener /var/spool/postfix/private/auth {
user = postfix
}
}

8
mail/opendkim/local.conf Normal file
View file

@ -0,0 +1,8 @@
Socket local:/var/spool/postfix/private/opendkim
UserID postfix
InternalHosts 0.0.0.0/0
Canonicalization relaxed/relaxed
KeyTable dsn:sqlite3://./opendkim-bug-241.db/table=dkim_key?keycol=key?datacol=domain,selector,private_key
SigningTable dsn:sqlite3://./opendkim-bug-241.db/table=dkim?keycol=match?datacol=key

2
mail/postfix/alias.cf Normal file
View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT goto FROM alias WHERE address = '%s' AND active = 1

2
mail/postfix/domains.cf Normal file
View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT domain FROM domain WHERE domain = '%s' AND active = 1 AND NOT (transport LIKE 'smtp%%' OR transport LIKE 'relay%%')

2
mail/postfix/login.cf Normal file
View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT username FROM mailbox WHERE username = '%s' AND active = 1

39
mail/postfix/main.cf Normal file
View file

@ -0,0 +1,39 @@
# System
biff = no
compatibility_level = 2
disable_vrfy_command = yes
mailbox_size_limit = 0
message_size_limit = 0
mydomain = local
mynetworks_style = subnet
# TLS
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtpd_tls_key_file = /data/ssl/certs/mail.example.com/privkey.pem
smtpd_tls_cert_file = /data/ssl/certs/mail.example.com/fullchain.pem
# Custom
relay_domains = sqlite:/etc/postfix/relay.cf
transport_maps = sqlite:/etc/postfix/transport.cf
recipient_delimiter = +
virtual_mailbox_base = /data/mail/mail
virtual_uid_maps = static:2000
virtual_gid_maps = static:2000
virtual_mailbox_domains = sqlite:/etc/postfix/domains.cf
virtual_mailbox_maps = sqlite:/etc/postfix/virtual.cf
virtual_alias_maps = sqlite:/etc/postfix/alias.cf
virtual_mailbox_limit = 0
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sender_restrictions = reject_sender_login_mismatch
smtpd_sender_login_maps = sqlite:/etc/postfix/login.cf, $virtual_alias_maps
smtpd_milters = unix:private/opendkim
non_smtpd_milters = $smtpd_milters

2
mail/postfix/relay.cf Normal file
View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT domain FROM domain WHERE domain = '%s' AND active = 1 AND (transport LIKE 'smtp%%' OR transport LIKE 'relay%%')

View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT transport FROM domain WHERE domain = '%s' AND active = 1

2
mail/postfix/virtual.cf Normal file
View file

@ -0,0 +1,2 @@
dbpath = /data/mail/config/vmail.db
query = SELECT maildir FROM mailbox WHERE username = '%s' AND active = 1

6
mail/schema.sql Normal file
View file

@ -0,0 +1,6 @@
create table alias (address varchar(255) not null primary key, goto varchar(255) not null, active int not null default 1);
create table domain (domain varchar(255) not null primary key, transport varchar(255) not null default 'virtual', active int not null default 1);
create table mailbox (username varchar(255) not null primary key, password varchar(255) not null default '', name varchar(255) not null default '', maildir varchar(255) not null, active int not null default 1);
create table dkim (match varchar(255) not null primary key, key varchar(255) not null);
create table dkim_key (key varchar(255) not null primary key, domain varchar(255) not null, selector varchar(255) not null, private_key varchar(65535) not null);