├── INSTALL.md ├── LICENSE ├── Makefile ├── README.md ├── UPGRADE.md └── src ├── etc ├── acme-client.conf ├── acme │ └── letsencrypt-privkey.pem ├── changelist.local ├── daily.local ├── dhclient.conf ├── dkimproxy_out.conf ├── doas.conf ├── dovecot │ ├── conf.d │ │ ├── 10-auth.conf │ │ ├── 10-mail.conf │ │ ├── 10-master.conf │ │ ├── 10-ssl.conf │ │ ├── 15-lda.conf │ │ ├── 15-mailboxes.conf │ │ ├── 20-imap.conf │ │ ├── 20-lmtp.conf │ │ ├── 20-managesieve.conf │ │ ├── 90-plugin.conf │ │ ├── 90-quota.conf │ │ ├── 90-replication.conf.optional │ │ ├── 90-sieve-extprograms.conf │ │ ├── 90-sieve.conf │ │ └── auth-passwdfile.conf.ext │ ├── dovecot-trash.conf.ext │ └── local.conf ├── group ├── hostname.vio0 ├── hosts ├── httpd.conf ├── login.conf ├── mail │ ├── aliases │ ├── blacklist │ ├── mailname │ ├── passwd │ ├── relays │ ├── smtpd.conf │ ├── vdomains │ ├── virtual │ └── whitelist ├── mtree │ └── special.local ├── mygate ├── myname ├── newsyslog.conf ├── pf.conf ├── pf.conf.anchor.block ├── pf.conf.anchor.icmp ├── pf.conf.table.ban ├── pf.conf.table.martians ├── rc.conf.local ├── resolv.conf ├── rspamd │ ├── local.d │ │ ├── antivirus.conf │ │ ├── classifier-bayes.conf │ │ ├── mime_types.conf │ │ ├── multimap.conf │ │ ├── options.inc │ │ ├── phishing.conf │ │ ├── rbl.conf.optional │ │ ├── replies.conf │ │ ├── surbl.conf │ │ ├── worker-controller.inc │ │ ├── worker-normal.inc │ │ └── worker-proxy.inc │ └── override.d │ │ ├── bad_emails.list │ │ └── emails.conf.optional ├── ssh │ ├── sshd_banner │ └── sshd_config ├── ssl │ ├── acme │ │ ├── letsencryptauthorityx3.pem │ │ ├── mercury.example.com.crt │ │ ├── mercury.example.com.fullchain.pem │ │ ├── mercury.example.com.ocsp.resp.der │ │ └── private │ │ │ └── mercury.example.com.key │ └── dkim │ │ ├── private │ │ └── private.key │ │ └── public.key └── sysctl.conf ├── home ├── dsync │ └── .ssh │ │ ├── authorized_keys │ │ ├── id_rsa │ │ └── id_rsa.pub └── puffy │ ├── .calendar │ ├── calendar │ ├── calendar.example.com │ └── calendar.host.1 │ └── .gnupg │ └── gpg.conf ├── root └── .ssh │ ├── config │ └── known_hosts ├── usr └── local │ ├── bin │ ├── dovecot-lda.sh │ ├── get-ocsp.sh │ ├── learn_all_spam.sh │ ├── learn_ham.sh │ ├── learn_spam.sh │ ├── quota-warning.sh │ ├── rmchangelist.sh │ └── wks-server.sh │ └── share │ └── doc │ └── caesonia │ └── OpenSSH_Principals.md └── var ├── cron ├── cron.allow └── tabs │ └── root ├── dovecot ├── imapsieve │ └── before │ │ ├── report-ham.sieve │ │ └── report-spam.sieve └── sieve │ └── before │ ├── 00-wks.sieve │ └── spamtest.sieve ├── lib └── gnupg │ └── wks │ └── .gitkeep ├── unbound └── etc │ └── unbound.conf └── www ├── htdocs └── mercury.example.com │ ├── Milonia_Caesonia-250x259.jpg │ ├── disklabel │ ├── disklabel.lax │ ├── disklabel.min │ ├── index.html │ ├── install.conf │ └── mail │ └── config-v1.1.xml ├── mta-sts └── mta-sts.txt └── openpgpkey ├── hu └── 54f6ry7x1qqtpor16txw5gdmdbbh6a73 ├── policy └── submission-address /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Horia Racoviceanu 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # $OpenBSD$ 2 | 3 | # Put overrides in "Makefile.local" 4 | 5 | PREFIX ?= /usr/local 6 | GH_PROJECT ?= caesonia 7 | BINDIR ?= ${PREFIX}/bin 8 | BASESYSCONFDIR ?= /etc 9 | VARBASE ?= /var 10 | DOCDIR ?= ${PREFIX}/share/doc/${GH_PROJECT} 11 | EXAMPLESDIR ?= ${PREFIX}/share/examples/${GH_PROJECT} 12 | 13 | # Server 14 | 15 | DOMAIN_NAME = example.com 16 | VHOSTS_NAME = example.net \ 17 | example.org 18 | 19 | PRIMARY = yes 20 | 21 | PRIMARY_HOST = mercury 22 | PRIMARY_IPv4 = 203.0.113.1 23 | PRIMARY_IPv6 = 2001:0db8::1 24 | 25 | BACKUP_HOST = hermes 26 | BACKUP_IPv4 = 203.0.113.2 27 | BACKUP_IPv6 = 2001:0db8::2 28 | 29 | DKIM_SELECTOR = obsd 30 | EGRESS = vio0 31 | 32 | WHEEL_USER = puffy 33 | REPLICATION_USER = dsync 34 | VIRTUAL_USER = ${WHEEL_USER} 35 | 36 | AUTOEXPUNGE = 30d 37 | MAIL_QUOTA = 15G 38 | MAX_MESSAGE_SIZE = 35M 39 | FULL_SYNC_INTERVAL = 1h 40 | 41 | UPGRADE = yes 42 | 43 | CAESONIA = ${SCRIPT} ${SYSCONF} ${PFCONF} ${MAILCONF} ${SSHCONF} \ 44 | ${MTREECONF} ${DKIMPROXYCONF} ${DOVECOTCONF} ${SIEVE} \ 45 | ${RSPAMDCONF} ${WKD} ${TLSRPT} ${WWW} ${UNBOUNDCONF} \ 46 | ${CRONALLOW} ${CRONTAB} 47 | 48 | # Caesonia 49 | 50 | SCRIPT = ${BINDIR:S|^/||}/dovecot-lda.sh \ 51 | ${BINDIR:S|^/||}/learn_all_spam.sh \ 52 | ${BINDIR:S|^/||}/learn_ham.sh \ 53 | ${BINDIR:S|^/||}/learn_spam.sh \ 54 | ${BINDIR:S|^/||}/quota-warning.sh \ 55 | ${BINDIR:S|^/||}/rmchangelist.sh \ 56 | ${BINDIR:S|^/||}/wks-server.sh 57 | 58 | SYSCONF = ${BASESYSCONFDIR:S|^/||}/acme-client.conf \ 59 | ${BASESYSCONFDIR:S|^/||}/changelist.local \ 60 | ${BASESYSCONFDIR:S|^/||}/daily.local \ 61 | ${BASESYSCONFDIR:S|^/||}/dhclient.conf \ 62 | ${BASESYSCONFDIR:S|^/||}/doas.conf \ 63 | ${BASESYSCONFDIR:S|^/||}/httpd.conf \ 64 | ${BASESYSCONFDIR:S|^/||}/login.conf \ 65 | ${BASESYSCONFDIR:S|^/||}/newsyslog.conf \ 66 | ${BASESYSCONFDIR:S|^/||}/resolv.conf \ 67 | ${BASESYSCONFDIR:S|^/||}/sysctl.conf 68 | 69 | PFCONF = ${BASESYSCONFDIR:S|^/||}/pf.conf \ 70 | ${BASESYSCONFDIR:S|^/||}/pf.conf.anchor.block \ 71 | ${BASESYSCONFDIR:S|^/||}/pf.conf.anchor.icmp \ 72 | ${BASESYSCONFDIR:S|^/||}/pf.conf.table.ban \ 73 | ${BASESYSCONFDIR:S|^/||}/pf.conf.table.martians 74 | 75 | MAILCONF = ${BASESYSCONFDIR:S|^/||}/mail/aliases \ 76 | ${BASESYSCONFDIR:S|^/||}/mail/blacklist \ 77 | ${BASESYSCONFDIR:S|^/||}/mail/mailname \ 78 | ${BASESYSCONFDIR:S|^/||}/mail/passwd \ 79 | ${BASESYSCONFDIR:S|^/||}/mail/relays \ 80 | ${BASESYSCONFDIR:S|^/||}/mail/smtpd.conf \ 81 | ${BASESYSCONFDIR:S|^/||}/mail/vdomains \ 82 | ${BASESYSCONFDIR:S|^/||}/mail/virtual \ 83 | ${BASESYSCONFDIR:S|^/||}/mail/whitelist 84 | 85 | SSHCONF = ${BASESYSCONFDIR:S|^/||}/ssh/sshd_banner \ 86 | ${BASESYSCONFDIR:S|^/||}/ssh/sshd_config 87 | 88 | MTREECONF = ${BASESYSCONFDIR:S|^/||}/mtree/special.local 89 | 90 | DKIMPROXYCONF = ${BASESYSCONFDIR:S|^/||}/dkimproxy_out.conf 91 | 92 | DOVECOTCONF = ${BASESYSCONFDIR:S|^/||}/dovecot/dovecot-trash.conf.ext \ 93 | ${BASESYSCONFDIR:S|^/||}/dovecot/local.conf \ 94 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/10-auth.conf \ 95 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/10-mail.conf \ 96 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/10-master.conf \ 97 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/10-ssl.conf \ 98 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/15-lda.conf \ 99 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/15-mailboxes.conf \ 100 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/20-imap.conf \ 101 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/20-lmtp.conf \ 102 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/20-managesieve.conf \ 103 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-plugin.conf \ 104 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-quota.conf \ 105 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-sieve-extprograms.conf \ 106 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-sieve.conf \ 107 | ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/auth-passwdfile.conf.ext 108 | 109 | SIEVE = ${VARBASE:S|^/||}/dovecot/imapsieve/before/report-ham.sieve \ 110 | ${VARBASE:S|^/||}/dovecot/imapsieve/before/report-spam.sieve \ 111 | ${VARBASE:S|^/||}/dovecot/sieve/before/00-wks.sieve \ 112 | ${VARBASE:S|^/||}/dovecot/sieve/before/spamtest.sieve 113 | 114 | RSPAMDCONF = ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/antivirus.conf \ 115 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/classifier-bayes.conf \ 116 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/mime_types.conf \ 117 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/multimap.conf \ 118 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/options.inc \ 119 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/phishing.conf \ 120 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/rbl.conf.optional \ 121 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/replies.conf \ 122 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/surbl.conf \ 123 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/worker-controller.inc \ 124 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/worker-normal.inc \ 125 | ${BASESYSCONFDIR:S|^/||}/rspamd/local.d/worker-proxy.inc \ 126 | ${BASESYSCONFDIR:S|^/||}/rspamd/override.d/bad_emails.list \ 127 | ${BASESYSCONFDIR:S|^/||}/rspamd/override.d/emails.conf.optional 128 | 129 | UNBOUNDCONF = ${VARBASE:S|^/||}/unbound/etc/unbound.conf 130 | 131 | WKD = ${VARBASE:S|^/||}/www/openpgpkey/policy \ 132 | ${VARBASE:S|^/||}/www/openpgpkey/submission-address 133 | 134 | TLSRPT = ${VARBASE:S|^/||}/www/mta-sts/mta-sts.txt 135 | 136 | WWW = ${VARBASE:S|^/||}/www/htdocs/${HOSTNAME}/index.html \ 137 | ${VARBASE:S|^/||}/www/htdocs/${HOSTNAME}/mail/config-v1.1.xml 138 | 139 | CRONALLOW = ${VARBASE:S|^/||}/cron/cron.allow 140 | CRONTAB = ${VARBASE:S|^/||}/cron/tabs/root 141 | 142 | WRKSRC ?= ${HOSTNAME:S|^|${.CURDIR}/|} 143 | RELEASE !!= uname -r 144 | QUEUE !!= openssl rand -hex 16 145 | 146 | PKG = dkimproxy \ 147 | dovecot \ 148 | dovecot-pigeonhole \ 149 | rspamd \ 150 | opensmtpd-extras \ 151 | gnupg-2.2.12 152 | 153 | #-8<----------- [ cut here ] --------------------------------------------------^ 154 | 155 | .if exists(Makefile.local) 156 | . include "Makefile.local" 157 | .endif 158 | 159 | .if empty(BACKUP_HOST) 160 | DOVECOTCONF += ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-replication.conf.optional 161 | PRIMARY = yes 162 | .else 163 | DOVECOTCONF += ${BASESYSCONFDIR:S|^/||}/dovecot/conf.d/90-replication.conf 164 | .endif 165 | 166 | .if ${PRIMARY} == "yes" 167 | HOSTNAME = ${PRIMARY_HOST}.${DOMAIN_NAME} 168 | .else 169 | HOSTNAME = ${BACKUP_HOST}.${DOMAIN_NAME} 170 | .endif 171 | 172 | # Specifications (target rules) 173 | 174 | .if ${UPGRADE} == "yes" 175 | upgrade: config .WAIT ${CAESONIA} 176 | @echo Upgrade 177 | .else 178 | upgrade: config 179 | @echo Fresh install 180 | .endif 181 | 182 | config: 183 | mkdir -m750 ${WRKSRC} 184 | (umask 077; cp -R ${.CURDIR}/src/* ${WRKSRC}) 185 | .if !empty(VHOSTS_NAME) 186 | . for _VHOSTS_NAME in ${VHOSTS_NAME} 187 | echo ${_VHOSTS_NAME} >> ${WRKSRC}/${MAILCONF:M*vdomains} 188 | sed -i \ 189 | -e '/autoconfig.example.net/{p;s|.*| autoconfig.${_VHOSTS_NAME} \\|;}' \ 190 | -e '/mta-sts.example.net/{p;s|.*| mta-sts.${_VHOSTS_NAME} \\|;}' \ 191 | -e '/wkd.example.net/{p;s|.*| wkd.${_VHOSTS_NAME} \\|;}' \ 192 | ${WRKSRC}/${SYSCONF:M*acme-client.conf} 193 | sed -i \ 194 | -e '/^puffy@example.net/{p;s|.*|${VIRTUAL_USER}@${_VHOSTS_NAME} \ 195 | ${VIRTUAL_USER}@${DOMAIN_NAME}|;}' \ 196 | ${WRKSRC}/${MAILCONF:M*virtual} 197 | echo @${_VHOSTS_NAME} >> ${WRKSRC}/${MAILCONF:M*whitelist} 198 | sed -i \ 199 | -e '/^domain/ s|$$|,${_VHOSTS_NAME}|' \ 200 | ${WRKSRC}/${DKIMPROXYCONF:M*dkimproxy_out.conf} 201 | . endfor 202 | .endif 203 | sed -i \ 204 | -e '/^domain/s|,example.net||' \ 205 | ${WRKSRC}/${DKIMPROXYCONF:M*dkimproxy_out.conf} 206 | sed -i \ 207 | -e '/example.net/d' \ 208 | ${WRKSRC}/${MAILCONF:M*vdomains} \ 209 | ${WRKSRC}/${MAILCONF:M*whitelist} \ 210 | ${WRKSRC}/${SYSCONF:M*acme-client.conf} 211 | sed -i \ 212 | -e '/^puffy@example.net/d' \ 213 | ${WRKSRC}/${MAILCONF:M*virtual} 214 | sed -i \ 215 | -e 's|^puffy|${WHEEL_USER}|' \ 216 | ${WRKSRC}/${MAILCONF:M*aliases} 217 | sed -i \ 218 | -e "s/5101bef20f4d02c826bffc243e15a7c0/${QUEUE}/" \ 219 | ${WRKSRC}/${MAILCONF:M*smtpd.conf} 220 | find ${WRKSRC} -type f -exec sed -i \ 221 | -e 's|vio0|${EGRESS}|' \ 222 | -e 's|obsd|${DKIM_SELECTOR}|' \ 223 | -e 's|puffy|${VIRTUAL_USER}|' \ 224 | -e 's|example.com|${DOMAIN_NAME}|' \ 225 | -e 's|203.0.113.1|${PRIMARY_IPv4}|' \ 226 | -e 's|2001:0db8::1|${PRIMARY_IPv6}|' \ 227 | -e '/autoexpunge /s|30d|${AUTOEXPUNGE}|' \ 228 | -e '/storage=/s|15G|${MAIL_QUOTA}|' \ 229 | -e 's|35M|${MAX_MESSAGE_SIZE}|' \ 230 | -e '/full_sync_interval/s|1h|${FULL_SYNC_INTERVAL}|' \ 231 | {} + 232 | .if empty(BACKUP_HOST) 233 | sed -i \ 234 | -e 's/dsync\ //g' \ 235 | ${WRKSRC}/${PFCONF:M*pf.conf} 236 | sed -i \ 237 | -e '/203.0.113.2/d' \ 238 | -e '/2001:0db8::2/d' \ 239 | ${WRKSRC}/${MAILCONF:M*relays} 240 | sed -i \ 241 | -e '/hermes/d' \ 242 | ${WRKSRC}/${TLSRPT:M*mta-sts.txt} \ 243 | ${WRKSRC}/${SYSCONF:M*acme-client.conf} 244 | find ${WRKSRC} -type f -exec sed -i \ 245 | -e 's|mercury|${PRIMARY_HOST}|' \ 246 | {} + 247 | .else 248 | find ${WRKSRC} -type f -exec sed -i \ 249 | -e 's|203.0.113.2|${BACKUP_IPv4}|' \ 250 | -e 's|2001:0db8::2|${BACKUP_IPv6}|' \ 251 | {} + 252 | cp -p ${WRKSRC}${BASESYSCONFDIR}/dovecot/conf.d/90-replication.conf.optional \ 253 | ${WRKSRC}${BASESYSCONFDIR}/dovecot/conf.d/90-replication.conf 254 | . if ${PRIMARY} == "yes" 255 | find ${WRKSRC} -type f -exec sed -i \ 256 | -e 's|mercury|${PRIMARY_HOST}|' \ 257 | -e 's|hermes|${BACKUP_HOST}|' \ 258 | {} + 259 | @echo Primary MX 260 | . else 261 | find ${WRKSRC} -type f -exec sed -i \ 262 | -e 's|mercury|${BACKUP_HOST}|' \ 263 | -e 's|hermes|${PRIMARY_HOST}|' \ 264 | {} + 265 | sed -i \ 266 | -e 's|action "mda"|action "backup"|' \ 267 | ${WRKSRC}/${MAILCONF:M*smtpd.conf} 268 | sed -i \ 269 | -e '/^[[:space:]]alternative/,/^[[:space:]]}/d' \ 270 | ${WRKSRC}/${SYSCONF:M*acme-client.conf} 271 | @echo Backup MX 272 | . endif 273 | .endif 274 | mv ${WRKSRC}${VARBASE}/www/htdocs/mercury.example.com \ 275 | ${WRKSRC}${VARBASE}/www/htdocs/${HOSTNAME} 276 | @echo Configured 277 | 278 | ${CAESONIA}: 279 | [[ -r ${DESTDIR}/$@ ]] \ 280 | && (umask 077; diff -u ${DESTDIR}/$@ ${WRKSRC}/$@ >/dev/null \ 281 | || sdiff -as -w $$(tput -T $${TERM:-vt100} cols) \ 282 | -o ${WRKSRC}/$@.merged \ 283 | ${DESTDIR}/$@ \ 284 | ${WRKSRC}/$@) \ 285 | || [[ "$$?" -eq 1 ]] 286 | 287 | clean: 288 | @rm -r ${WRKSRC} 289 | 290 | beforeinstall: upgrade 291 | -rcctl stop smtpd httpd dkimproxy_out rspamd dovecot 292 | .for _PKG in ${PKG} 293 | env PKG_PATH= pkg_info ${_PKG} > /dev/null || pkg_add ${_PKG} 294 | .endfor 295 | .if ${UPGRADE} == "yes" 296 | . for _CAESONIA in ${CAESONIA} 297 | [[ -r ${_CAESONIA:S|^|${WRKSRC}/|:S|$|.merged|} ]] \ 298 | && cp -p ${WRKSRC}/${_CAESONIA}.merged ${WRKSRC}/${_CAESONIA} \ 299 | || [[ "$$?" -eq 1 ]] 300 | . endfor 301 | .endif 302 | 303 | realinstall: 304 | ${INSTALL} -d ${VARBASE}/dovecot/imapsieve/{after,before} 305 | ${INSTALL} -d ${VARBASE}/dovecot/sieve/{after,before} 306 | ${INSTALL} -d ${BASESYSCONFDIR}/rspamd/{local.d,override.d} 307 | ${INSTALL} -d ${VARBASE}/www/openpgpkey/hu 308 | ${INSTALL} -d ${VARBASE}/www/mta-sts 309 | ${INSTALL} -d ${VARBASE}/www/htdocs/${HOSTNAME}/mail 310 | ${INSTALL} -d ${BASESYSCONFDIR}/ssl/dkim/private 311 | .for _NAME in ${DOMAIN_NAME} ${VHOSTS_NAME} 312 | ${INSTALL} -d ${VARBASE}/lib/gnupg/wks/${_NAME}/pending 313 | ln -sf ${VARBASE}/www/openpgpkey/hu \ 314 | ${VARBASE}/lib/gnupg/wks/${_NAME} 315 | ln -sf ${VARBASE}/www/openpgpkey/submission-address \ 316 | ${VARBASE}/lib/gnupg/wks/${_NAME} 317 | .endfor 318 | .for _CAESONIA in ${CAESONIA:N*cron/tabs*} 319 | ${INSTALL} -S -o ${LOCALEOWN} -g ${LOCALEGRP} -m 440 \ 320 | ${_CAESONIA:S|^|${WRKSRC}/|} \ 321 | ${_CAESONIA:S|^|${DESTDIR}/|} 322 | .endfor 323 | 324 | afterinstall: 325 | .if !empty(CRONTAB) 326 | crontab -u root ${WRKSRC}/${CRONTAB} 327 | .endif 328 | user info -e vmail \ 329 | || user add -u 2000 -g =uid -c "Virtual Mail" -s /sbin/nologin -b ${VARBASE} -m vmail 330 | .if !empty(BACKUP_HOST) 331 | user info -e dsync \ 332 | || user add -u 2001 -g =uid -c "Dsync Replication" -s /bin/ksh -m dsync 333 | .endif 334 | [[ -r ${BASESYSCONFDIR}/changelist-${RELEASE} ]] \ 335 | || cp ${BASESYSCONFDIR}/changelist ${BASESYSCONFDIR}/changelist-${RELEASE} 336 | sed -i '/changelist.local/,$$d' ${BASESYSCONFDIR}/changelist 337 | cat ${BASESYSCONFDIR}/changelist.local >> ${BASESYSCONFDIR}/changelist 338 | .for _SIEVE in ${SIEVE} 339 | sievec /${_SIEVE} 340 | .endfor 341 | doas -u vmail /usr/local/bin/gpg2 -K --with-wkd-hash key-submission@${DOMAIN_NAME} || \ 342 | doas -u vmail /usr/local/bin/gpg2 --batch --passphrase "" \ 343 | --quick-gen-key key-submission@${DOMAIN_NAME} 344 | chown vmail ${VARBASE}/www/openpgpkey/hu 345 | [[ -r ${VARBASE}/www/openpgpkey/hu/54f6ry7x1qqtpor16txw5gdmdbbh6a73 ]] || \ 346 | doas -u vmail /usr/local/bin/gpg2 \ 347 | -o ${VARBASE}/lib/gnupg/wks/${DOMAIN_NAME}/hu/54f6ry7x1qqtpor16txw5gdmdbbh6a73 \ 348 | --export-options export-minimal --export key-submission@${DOMAIN_NAME} 349 | [[ -r ${BASESYSCONFDIR}/ssl/dkim/private/private.key ]] || (umask 077; \ 350 | openssl genrsa -out ${BASESYSCONFDIR}/ssl/dkim/private/private.key 2048; \ 351 | openssl rsa -in ${BASESYSCONFDIR}/ssl/dkim/private/private.key \ 352 | -pubout -out ${BASESYSCONFDIR}/ssl/dkim/public.key) 353 | sed -i '/^console/s/ secure//' ${BASESYSCONFDIR}/ttys 354 | mtree -qef ${BASESYSCONFDIR}/mtree/special -p / -U 355 | mtree -qef ${BASESYSCONFDIR}/mtree/special.local -p / -U 356 | pfctl -f /etc/pf.conf 357 | rcctl disable check_quotas sndiod 358 | -rcctl check sndiod && rcctl stop sndiod 359 | rcctl enable unbound sshd httpd dkimproxy_out rspamd dovecot smtpd 360 | rcctl restart unbound sshd httpd 361 | ftp -o - https://${HOSTNAME}/index.html \ 362 | || acme-client -ADv ${HOSTNAME} 363 | ocspcheck -vNo ${BASESYSCONFDIR}/ssl/acme/${HOSTNAME}.ocsp.resp.der \ 364 | ${BASESYSCONFDIR}/ssl/acme/${HOSTNAME}.fullchain.pem 365 | rcctl restart httpd dkimproxy_out rspamd dovecot smtpd 366 | 367 | .PHONY: upgrade 368 | .USE: upgrade 369 | 370 | .include 371 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # caesonia (beta) 2 | [![Backers on Open Collective](https://opencollective.com/caesonia/backers/badge.svg)](#backers) 3 | [![Sponsors on Open Collective](https://opencollective.com/caesonia/sponsors/badge.svg)](#sponsors) 4 | 5 | *Open*BSD Email Service 6 | 7 | ![Public Domain](src/var/www/htdocs/mercury.example.com/Milonia_Caesonia-250x259.jpg) 8 | 9 | ## About 10 | > a free-email alternative 11 | 12 | Root your Inbox :mailbox_with_mail: 13 | 14 | ## Features 15 | - Efficient: configured to run on min. 512MB RAM and 20GB SSD, a KVM (cloud) VPS for around $2.50/mo 16 | - 15GB+ uncompressed Maildir, rivals top free-email providers (grow by upgrading SSD) 17 | - Email messages are gzip compressed, at least 1/3 more space with level 6 default 18 | - Server side full text search (headers and body) can be enabled (to use the extra space) 19 | - Mobile data friendly: IMAPS connections are compressed 20 | - Subaddress (+tag) support, to filter and monitor email addresses 21 | - Virtual domains, aliases, and credentials in files, Berkeley DB, or [SQLite3](https://github.com/OpenSMTPD/OpenSMTPD-extras/tree/master/extras/tables/table-sqlite) 22 | - Naive Bayes rspamd filtering with supervised learning: the lowest false positive spam detection rates 23 | - Carefree automated Spam/ and Trash/ cleaning service (default: older than 30 days) 24 | - Automated quota management, gently assists when over quota 25 | - Easy backup MX setup: using the same configuration, install in minutes on a different host 26 | - Worry-free automated master/master replication with backup MX, prevents accidental loss of email messages 27 | - Resilient: the backup MX can be used as primary, even when the primary is not down, both perfect replicas 28 | - Flexible: switching roles is easy, making the process of changing VPS hosts a breeze (no downtime) 29 | - DMARC (with DKIM and SPF) email-validation system, to detect and prevent email spoofing 30 | - Uncensored DNS validating resolver from root nameservers 31 | - OpenPGP Web Key Service with Web Key Directory, automatic key exchange protocol 32 | - MUA Autoconfiguration, for modern clients 33 | - Daily (spartan) stats, to keep track of things 34 | - Your sieve scripts and managesieve configuration, let's get started 35 | 36 | ## Considerations 37 | By design, email message headers need to be public, for exchanges to happen. The body of the message can be [encrypted](INSTALL.md#openpgp-web-key-service-wks) by the user, if desired. Moreover, there is no way to prevent the host from having access to the virtual machine. Therefore, [full disk encryption](https://www.openbsd.org/faq/faq14.html#softraidFDE) (at rest) may not be necessary. 38 | 39 | Given our low memory requirements, and the single-purpose concept of email service, Roundcube or other web-based IMAP email clients should be on a different VPS. 40 | 41 | Antivirus software users (usually) have the service running on their devices. ClamAV can easily be incorporated into this configuration, if affected by the [types of malware](https://www.shadowserver.org/wiki/pmwiki.php/AV/Virus180-DayStats) it protects against, but will require around 1GB additional RAM (or another VPS). 42 | 43 | Every email message is important, if properly delivered, for Bayes classification. At least 200 ham and 200 spam messages are required to learn what one considers junk (2000+ for best results). By default (change to use case), a rspamd score above 50% will send the message to Spam/. Moving messages in and out of Spam/ changes this score. After 95%, the message is flagged as "seen" and can be safely ignored. 44 | 45 | [spamd](https://man.openbsd.org/spamd) is effective at greylisting and stopping high volume spam, if it becomes a problem. It will be an option when IPv6 is supported, along with [bgp-spamd](https://bgp-spamd.net/). To build IP lists for greylisting, please use [spfwalk](https://github.com/akpoff/spfwalk) with [spf_fetch](https://github.com/akpoff/spf_fetch). 46 | 47 | System mail is delivered to an alias mapped to a virtual user served by the service. This way, messages are guaranteed to be delivered via encrypted connection. It is not possible for real users to alias, nor `mail` an external mail address with the default configuration. 48 | e.g. puffy@mercury.example.com is wheel, with an alias mapped to (virtual) puffy@example.com, and user (puffy) can be different for each. 49 | 50 | ## Getting started 51 | 52 | See [**Prerequisites**](#prerequisites) and the [**Installation Guide**](INSTALL.md) for details. 53 | 54 | Grab a copy of this repository, and put overrides in "[Makefile](Makefile).local" e.g.: 55 | ```console 56 | # Makefile.local 57 | 58 | DOMAIN_NAME = example.com 59 | VHOSTS_NAME = example.net \ 60 | example.org 61 | 62 | PRIMARY = yes 63 | 64 | PRIMARY_HOST = mercury 65 | PRIMARY_IPv4 = 203.0.113.1 66 | PRIMARY_IPv6 = 2001:0db8::1 67 | 68 | BACKUP_HOST = hermes 69 | BACKUP_IPv4 = 203.0.113.2 70 | BACKUP_IPv6 = 2001:0db8::2 71 | 72 | DKIM_SELECTOR = obsd 73 | EGRESS = vio0 74 | 75 | WHEEL_USER = puffy 76 | REPLICATION_USER = dsync 77 | VIRTUAL_USER = ${WHEEL_USER} 78 | 79 | AUTOEXPUNGE = 30d 80 | MAIL_QUOTA = 15G 81 | MAX_MESSAGE_SIZE = 35M 82 | FULL_SYNC_INTERVAL = 1h 83 | 84 | UPGRADE = yes 85 | ``` 86 | 87 | #### Install 88 | ```console 89 | make install 90 | ``` 91 | 92 | *n.b.* UPGRADE uses [`sdiff`](https://man.openbsd.org/sdiff) side-by-side diff (with *new* on the right side) 93 | 94 | #### Virtual Users 95 | Update virtual users [credentials table](https://man.openbsd.org/table.5#Credentials_tables) [`src/etc/mail/passwd`](src/etc/mail/passwd) using [`smtpctl encrypt`](https://man.openbsd.org/smtpctl#encrypt) 96 | ```console 97 | smtpctl encrypt 98 | > secret 99 | > $2b$...encrypted...passphrase... 100 | vi src/etc/mail/passwd 101 | > puffy@example.com:$2b$...encrypted...passphrase...:::::: 102 | smtpctl update table passwd 103 | ``` 104 | 105 | *n.b.*: user [quota](src/etc/dovecot/conf.d/90-quota.conf) limit can be [overriden](src/etc/dovecot/conf.d/auth-passwdfile.conf.ext) from [src/etc/mail/passwd](src/etc/mail/passwd) 106 | ```console 107 | puffy@example.com:$2b$...encrypted...passphrase...::::::userdb_quota_rule=*:storage=7G 108 | ``` 109 | 110 | Review [virtual domains](https://man.openbsd.org/makemap#VIRTUAL_DOMAINS) [aliasing table](https://man.openbsd.org/table.5#Aliasing_tables) [`src/etc/mail/virtual`](src/etc/mail/virtual) 111 | 112 | *n.b.* see [Administration](https://github.com/vedetta-com/caesonia/blob/master/INSTALL.md#administration) for virtual user and domain management 113 | 114 | #### Backup MX 115 | *n.b.* Without backup MX, leave BACKUP_HOST empty in "Makefile.local" 116 | 117 | Dovecot Replication user "dsync" [SSH](src/etc/ssh/sshd_config) limited to one "[command](src/home/dsync/.ssh/authorized_keys)" restricted in [`doas.conf`](src/etc/doas.conf) to match "[dsync_remote_cmd](src/etc/dovecot/conf.d/90-replication.conf.optional)". On primary and backup hosts 118 | 119 | ```console 120 | su - dsync 121 | ssh-keygen 122 | echo "command=\"doas -u vmail \${SSH_ORIGINAL_COMMAND#*}\" $(cat ~/.ssh/id_rsa.pub)" | \ 123 | ssh puffy@hermes.example.com "cat >> /home/dsync/.ssh/authorized_keys" 124 | exit 125 | ``` 126 | 127 | Alternatively, [OpenSSH certificates](https://github.com/vedetta-com/vedetta/blob/master/src/usr/local/share/doc/vedetta/OpenSSH_Principals.md) allow fine-grained control to local users and hosts. The `force-command` is passed to ssh-keygen as certificate option (-O) instead of using "authorized_keys". 128 | 129 | Update [/home/dsync](src/home/dsync), on primary and backup hosts 130 | ```console 131 | chown -R root:dsync /home/dsync 132 | chmod 750 /home/dsync/.ssh 133 | chmod 640 /home/dsync/.ssh/{authorized_keys,id_*.pub,known_hosts} 134 | chmod 400 /home/dsync/.ssh/{id_ecdsa,id_ed25519,id_rsa} 135 | chown dsync /home/dsync/.ssh/{id_ecdsa,id_ed25519,id_rsa} 136 | ``` 137 | 138 | Update [`/root/.ssh/known_hosts`](src/root/.ssh/known_hosts) on primary and backup hosts 139 | ```console 140 | ssh -4 -i/home/dsync/.ssh/id_rsa -ldsync hermes.example.com "exit" 141 | ssh -6 -i/home/dsync/.ssh/id_rsa -ldsync hermes.example.com "exit" 142 | ``` 143 | 144 | #### Client Configuration 145 | *n.b.*: MUA auto-configuration via [Autoconfiguration](README.md#mozilla-autoconfiguration) and SRV Records for 146 | [Locating Email Services](README.md#srv-records-for-locating-email-services) 147 | 148 | - IMAP server: mercury.example.com (or hermes.example.com) 149 | - Security: TLS 150 | - Port: 993 151 | - Username: puffy@example.com 152 | - Password: ******** 153 | - Autodetect IMAP namespace :ballot_box_with_check: 154 | - Use compression :ballot_box_with_check: 155 | - Poll when connecting for push :ballot_box_with_check: 156 | 157 | - SMTP server: mercury.example.com (or hermes.example.com) 158 | - Security: TLS 159 | - Port: 465 160 | - Require sign-in :ballot_box_with_check: 161 | - Username: puffy@example.com 162 | - Authentication: Normal password 163 | - Password: ******** 164 | 165 | - SMTP server: mercury.example.com (or hermes.example.com) 166 | - Security: STARTTLS 167 | - Port: 587 168 | - Require sign-in :ballot_box_with_check: 169 | - Username: puffy@example.com 170 | - Authentication: Normal password 171 | - Password: ******** 172 | 173 | ## Prerequisites 174 | A DNS name server (from a registrar, a free service, VPS host, or [self-hosted](https://github.com/vedetta-com/dithematic)) is required, which allows editing the following record types: [A](#forward-confirmed-reverse-dns-fcrdns), [AAAA](#forward-confirmed-reverse-dns-fcrdns), [MX](#mail-exchanger-mx), [CNAME](#mozilla-autoconfiguration), [SRV](#srv-records-for-locating-email-services), [CAA](#certification-authority-authorization-caa), [SSHFP](#secure-shell-fingerprint-sshfp), [TXT](#sender-policy-framework-spf) 175 | 176 | *n.b.* see [example zone](https://github.com/vedetta-com/dithematic/blob/master/src/usr/local/share/examples/dithematic/example.com.zone) 177 | 178 | **DNSSEC is [recommended](https://www.icann.org/news/announcement-2019-02-22-en)** 179 | 180 | #### Forward-confirmed reverse DNS ([FCrDNS](https://tools.ietf.org/html/draft-ietf-dnsop-reverse-mapping-considerations-06)) 181 | Primary domain has record types A, and AAAA for each MX subdomain with the relays' IPv4, and IPv6 182 | ```console 183 | mercury.example.com 86400 IN A 203.0.113.1 184 | mercury.example.com 86400 IN AAAA 2001:0db8::1 185 | ``` 186 | Each IPv4 and IPv6 has record type PTR with the MX subdomain (reverse DNS configured on VPS host) 187 | ```console 188 | ...6 IN PTR mercury.example.com 189 | ``` 190 | Verify: 191 | ```sh 192 | dig +short mercury.example.com a 193 | > 203.0.113.1 194 | dig +short -x 203.0.113.1 195 | > mercury.example.com. 196 | 197 | dig +short mercury.example.com aaaa 198 | > 2001:0db8::1 199 | dig +short -x 2001:0db8::1 200 | > mercury.example.com. 201 | ``` 202 | 203 | #### Mail eXchanger ([MX](https://tools.ietf.org/html/rfc5321)) 204 | Primary and *virtual* domains have identical records type MX with priority and relay hostnames 205 | ```console 206 | example.com 86400 IN MX 10 mercury.example.com 207 | example.com 86400 IN MX 20 hermes.example.com 208 | ``` 209 | 210 | #### Mozilla [Autoconfiguration](https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration) 211 | Primary and *virtual* domains have identical records type CNAME for *autoconfig* subdomain pointing to Autoconfiguration server 212 | ```console 213 | autoconfig.example.com 86400 IN CNAME mercury.example.com 214 | ``` 215 | 216 | #### OpenPGP Web Key Directory ([WKD](https://tools.ietf.org/html/draft-koch-openpgp-webkey-service-08)) 217 | Primary and *virtual* domains have identical records type CNAME for *wkd* subdomain pointing to Web Key Server 218 | ```console 219 | wkd.example.com 86400 IN CNAME mercury.example.com 220 | ``` 221 | 222 | #### SRV Records for OpenPGP [Web Key Directory](https://wiki.gnupg.org/WKD) 223 | Primary domain has record type SRV with primary WKD subdomain 224 | ```console 225 | _openpgpkey._tcp.example.com 86400 IN SRV 0 0 443 wkd.example.com 226 | ``` 227 | 228 | Each *virtual* domain has record type SRV with *virtual* WKD subdomain 229 | ```console 230 | _openpgpkey._tcp.example.net 86400 IN SRV 0 0 443 wkd.example.net 231 | ``` 232 | 233 | #### SRV Records for [Locating Email Services](https://tools.ietf.org/html/rfc6186) 234 | Primary and *virtual* domains have identical records type SRV for simple MUA auto-configuration 235 | ```console 236 | _submission._tcp.example.com 86400 IN SRV 0 1 465 mercury.example.com 237 | _submission._tcp.example.com 86400 IN SRV 5 1 587 mercury.example.com 238 | _imaps._tcp.example.com 86400 IN SRV 0 1 993 mercury.example.com 239 | _imap._tcp.example.com 86400 IN SRV 0 0 0 . 240 | _pop3s._tcp.example.com 86400 IN SRV 0 0 0 . 241 | _pop3._tcp.example.com 86400 IN SRV 0 0 0 . 242 | ``` 243 | 244 | #### Certification Authority Authorization ([CAA](https://tools.ietf.org/html/rfc6844)) 245 | Primary and *virtual* domains have identical records type CAA with *[letsencrypt.org](https://letsencrypt.org/)* as the only CA allowed to issue certificates 246 | ```console 247 | example.com 86400 IN CAA 128 issue "letsencrypt.org" 248 | example.com 86400 IN CAA 128 issuewild ";" 249 | ``` 250 | 251 | #### Secure Shell Fingerprint ([SSHFP](https://man.openbsd.org/ssh#VERIFYING_HOST_KEYS)) 252 | Print the SSHFP fingerprint resource record on each hostname 253 | ```sh 254 | ssh-keygen -r mercury.example.com 255 | ``` 256 | 257 | Primary domain has records type SSHFP for each MX subdomain with a fingerprint of the server's public key 258 | ```console 259 | mercury.example.com 86400 IN SSHFP 1 1 2... 260 | mercury.example.com 86400 IN SSHFP 1 2 5... 261 | mercury.example.com 86400 IN SSHFP 3 1 6... 262 | mercury.example.com 86400 IN SSHFP 3 2 8... 263 | mercury.example.com 86400 IN SSHFP 4 1 7... 264 | mercury.example.com 86400 IN SSHFP 4 2 a... 265 | ``` 266 | 267 | #### Sender Policy Framework ([SPF](https://tools.ietf.org/html/rfc7208)) 268 | Primary and *virtual* domains have identical records type TXT with primary domain SPF data 269 | ```console 270 | example.com 86400 IN TXT "v=spf1 mx:example.com -all" 271 | ``` 272 | 273 | Primary domain has record type TXT for each MX subdomain, to return receipt notifications (DSNs and MDNs), with relays' IP SPF data 274 | ```console 275 | mercury.example.com 86400 IN TXT "v=spf1 a -all" 276 | hermes.example.com 86400 IN TXT "v=spf1 a -all" 277 | ``` 278 | 279 | #### Domain Keys Identified Mail ([DKIM](http://www.dkim.org)) 280 | Generate a private and public key 281 | ```sh 282 | mkdir -p /etc/ssl/dkim/private 283 | chmod 750 /etc/ssl/dkim/private 284 | ``` 285 | > Signers SHOULD use RSA keys of at least 2048 bits. -- https://tools.ietf.org/html/rfc8301#section-3.2 286 | 287 | ```sh 288 | (umask 337; openssl genrsa -out /etc/ssl/dkim/private/private.key 2048) 289 | openssl rsa -in /etc/ssl/dkim/private/private.key -pubout -out /etc/ssl/dkim/public.key 290 | chown -R _rspamd:_dkimproxy /etc/ssl/dkim/private 291 | ``` 292 | 293 | > Widely used DNS configuration software places a practical limit on key sizes, because the software only handles a single 256-octet string in a TXT record, and RSA keys significantly longer than 1024 bits don't fit in 256 octets. -- https://tools.ietf.org/html/rfc8301#section-1 294 | 295 | > Multiple strings in a single DNS record are useful in constructing records that would exceed the 255-byte maximum length of a string within a single TXT RR record. -- https://tools.ietf.org/html/rfc4408#section-3.1.3 296 | 297 | Generate the TXT-DATA field for DKIM TXT record 298 | ```sh 299 | echo "v=DKIM1; k=rsa; p=$(sed -e '1d' -e '$d' /etc/ssl/dkim/public.key | tr -d '\n')" 300 | ``` 301 | 302 | Alternatively 303 | ```sh 304 | (umask 337; rspamadm dkim_keygen -d example.com -s 'obsd' -k /etc/ssl/dkim/private/private.key -b 2048 -t rsa) > /etc/ssl/dkim/public.key 305 | ``` 306 | 307 | Primary and *virtual* domains have identical records type TXT for *selector._domainkey* subdomain with DKIM public key 308 | ```console 309 | obsd._domainkey.example.com 86400 IN TXT ( "v=DKIM1; k=rsa; " 310 | "p=abcd" 311 | "ef" 312 | ) ; 313 | ``` 314 | 315 | #### Domain-based Message Authentication, Reporting & Conformance ([DMARC](https://dmarc.org/)) 316 | Primary and *virtual* domains have record type TXT for *_dmarc* subdomain with DMARC policy data 317 | ```console 318 | _dmarc.example.com 86400 IN TXT "v=DMARC1; p=reject; pct=100; rua=mailto:dmarcreports@example.com" 319 | ``` 320 | 321 | #### SMTP MTA Strict Transport Security ([MTA-STS](https://tools.ietf.org/html/rfc8461)) 322 | Primary domain has record type TXT for *_mta-sts* subdomain with MTA-STS reporting data 323 | ```console 324 | _mta-sts.example.com 86400 IN TXT "v=STSv1; id=20190515085700Z;" 325 | ``` 326 | 327 | Each *virtual* domain has record type CNAME for *_mta-sts* subdomain pointing to MTA-STS TXT record 328 | ```console 329 | _mta-sts.example.net 86400 IN CNAME _mta-sts.example.com 330 | ``` 331 | 332 | Primary and *virtual* domains have identical records type CNAME for *mta-sts* subdomain pointing to MTA-STS policy 333 | ```console 334 | mta-sts.example.com 86400 IN CNAME mercury.example.com 335 | ``` 336 | 337 | #### SMTP TLS Reporting ([SMTP TLSRPT](https://tools.ietf.org/html/rfc8460)) 338 | Primary and *virtual* domains have records type TXT for *_smtp._tls* subdomain with TLS reporting data 339 | ```console 340 | _smtp._tls.example.com 86400 IN TXT "v=TLSRPTv1;rua=mailto:tlsreports@example.com" 341 | ``` 342 | 343 | #### SMTP Security via Opportunistic DNS-Based Authentication of Named Entities ([DANE](https://tools.ietf.org/html/rfc7671)) Transport Layer Security ([TLS](https://tools.ietf.org/html/rfc7672)) 344 | **requires DNSSEC** and manual server key rotation using the procedure form rfc7671 345 | 346 | Print each relay's TLSA resource record 347 | ```sh 348 | pkg_add ldns-utils 349 | ldns-dane create mercury.example.com 443 3 1 1 350 | ldns-dane create hermes.example.com 443 3 1 1 351 | ``` 352 | 353 | Primary domain has records type TLSA for each *tlsa._dane* MX subdomain 354 | ```console 355 | tlsa._dane.mercury.example.com 86400 IN TLSA 3 1 1 e3b0c44298fc1c14... 356 | tlsa._dane.hermes.example.com 86400 IN TLSA 3 1 1 f2c0d55309cf2d25... 357 | ``` 358 | 359 | Primary domain has records type CNAME for each *_service._tcp* MX subdomain pointing to TLSA RR 360 | ```console 361 | _993._tcp.mercury.example.com 86400 IN CNAME tlsa._dane.mercury.example.com 362 | _587._tcp.mercury.example.com 86400 IN CNAME tlsa._dane.mercury.example.com 363 | _443._tcp.mercury.example.com 86400 IN CNAME tlsa._dane.mercury.example.com 364 | _25._tcp.mercury.example.com 86400 IN CNAME tlsa._dane.mercury.example.com 365 | 366 | _993._tcp.hermes.example.com 86400 IN CNAME tlsa._dane.hermes.example.com 367 | _587._tcp.hermes.example.com 86400 IN CNAME tlsa._dane.hermes.example.com 368 | _443._tcp.hermes.example.com 86400 IN CNAME tlsa._dane.hermes.example.com 369 | _25._tcp.hermes.example.com 86400 IN CNAME tlsa._dane.hermes.example.com 370 | ``` 371 | 372 | ## Support 373 | [Issues](https://github.com/vedetta-com/caesonia/issues) 374 | 375 | ## Social 376 | [#caesonia:matrix.org](https://riot.im/app/#/room/#caesonia:matrix.org) (deadish) 377 | 378 | [#caesonia@bsd.network](https://bsd.network/tags/caesonia) 379 | 380 | ## Contribute 381 | Contributions welcome, [fork](https://github.com/vedetta-com/caesonia/fork) 382 | 383 | Hosted by Open Source Collective 501c6, [contribute](https://opencollective.com/caesonia) 384 | 385 | 386 | ## Contributors 387 | 388 | This project exists thanks to all the people who contribute. 389 | 390 | 391 | 392 | ## Backers 393 | 394 | Thank you to all our backers! :pray: [[Become a backer](https://opencollective.com/caesonia#backer)] 395 | 396 | 397 | 398 | 399 | ## Sponsors 400 | 401 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/caesonia#sponsor)] 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # caesonia (beta) 2 | *Open*BSD Email Service - Upgrade an existing installation 3 | 4 | [`6.4.0-beta`](https://github.com/vedetta-com/caesonia/tree/v6.4.0-beta) to [`6.5.0-beta`](https://github.com/vedetta-com/caesonia/tree/v6.5.0-beta) 5 | 6 | > Upgrades are only supported from one release to the release immediately following it. Read through and understand this process before attempting it. For critical or physically remote machines, test it on an identical, local system first. -- [OpenBSD Upgrade Guide](https://www.openbsd.org/faq/index.html) 7 | 8 | ## Upgrade Guide 9 | 10 | Upgrade 11 | ```console 12 | cd /tmp 13 | ftp https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/bsd.rd 14 | ftp https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/SHA256.sig 15 | signify -C -p /etc/signify/openbsd-65-base.pub -x SHA256.sig bsd.rd && \ 16 | cp -p /bsd.rd /bsd.rd-6.4 && cp /tmp/bsd.rd / 17 | 18 | rm /usr/include/openssl/asn1_mac.h 19 | 20 | rm /usr/bin/c2ph \ 21 | /usr/bin/pstruct \ 22 | /usr/libdata/perl5/Locale/Codes/API.pod \ 23 | /usr/libdata/perl5/Module/CoreList/TieHashDelta.pm \ 24 | /usr/libdata/perl5/Unicode/Collate/Locale/bg.pl \ 25 | /usr/libdata/perl5/Unicode/Collate/Locale/fr.pl \ 26 | /usr/libdata/perl5/Unicode/Collate/Locale/ru.pl \ 27 | /usr/libdata/perl5/unicore/lib/Sc/Cham.pl \ 28 | /usr/libdata/perl5/unicore/lib/Sc/Ethi.pl \ 29 | /usr/libdata/perl5/unicore/lib/Sc/Hebr.pl \ 30 | /usr/libdata/perl5/unicore/lib/Sc/Hmng.pl \ 31 | /usr/libdata/perl5/unicore/lib/Sc/Khar.pl \ 32 | /usr/libdata/perl5/unicore/lib/Sc/Khmr.pl \ 33 | /usr/libdata/perl5/unicore/lib/Sc/Lana.pl \ 34 | /usr/libdata/perl5/unicore/lib/Sc/Lao.pl \ 35 | /usr/libdata/perl5/unicore/lib/Sc/Talu.pl \ 36 | /usr/libdata/perl5/unicore/lib/Sc/Tibt.pl \ 37 | /usr/libdata/perl5/unicore/lib/Sc/Xsux.pl \ 38 | /usr/libdata/perl5/unicore/lib/Sc/Zzzz.pl \ 39 | /usr/share/man/man1/c2ph.1 \ 40 | /usr/share/man/man1/pstruct.1 \ 41 | /usr/share/man/man3p/Locale::Codes::API.3p 42 | 43 | reboot 44 | boot: bsd.rd 45 | ... 46 | (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? U 47 | ... 48 | Set name(s) = -comp* -game* -x* 49 | 50 | reboot 51 | 52 | sysmerge 53 | ===> Displaying differences between ./etc/changelist and installed version: 54 | Use 'i' to install the temporary ./etc/changelist 55 | How should I deal with this? [Leave it for later] i 56 | 57 | pkg_add -u 58 | syspatch 59 | reboot 60 | ``` 61 | 62 | Upgrade caesonia (see [Makefile](https://github.com/vedetta-com/caesonia/blob/master/Makefile).local): 63 | ```console 64 | rm /usr/local/bin/get-ocsp.sh 65 | cd caesonia 66 | env UPGRADE=yes make install 67 | ``` 68 | 69 | OpenSSH 8.0 [new features](https://www.openbsd.org/65.html): 70 | > ssh(1), ssh-agent(1), ssh-add(1): Add support for ECDSA keys in PKCS#11 tokens. 71 | 72 | > ssh-keygen(1): Increase the default RSA key size to 3072 bits, following NIST Special Publication 800-57's guidance for a 128-bit equivalent symmetric security level. 73 | 74 | *n.b.*: Train rspamd with messages from all users' Spam folder (if installing new database) 75 | ```console 76 | /usr/local/bin/learn_all_spam.sh 77 | ``` 78 | 79 | Consider using [SSH certificates](https://github.com/vedetta-com/vedetta/blob/master/src/usr/local/share/doc/vedetta/OpenSSH_Principals.md) and manage access to local users with principals. 80 | 81 | -------------------------------------------------------------------------------- /src/etc/acme-client.conf: -------------------------------------------------------------------------------- 1 | # 2 | # $OpenBSD: acme-client.conf,v 1.7 2018/04/13 08:24:38 ajacoutot Exp $ 3 | # 4 | authority letsencrypt { 5 | api url "https://acme-v01.api.letsencrypt.org/directory" 6 | account key "/etc/acme/letsencrypt-privkey.pem" 7 | } 8 | 9 | authority letsencrypt-staging { 10 | api url "https://acme-staging.api.letsencrypt.org/directory" 11 | account key "/etc/acme/letsencrypt-staging-privkey.pem" 12 | } 13 | 14 | # (!) Add every service (virtual) subdomains as alternative names 15 | domain mercury.example.com { 16 | alternative names { \ 17 | autoconfig.example.com \ 18 | autoconfig.example.net \ 19 | mta-sts.example.com \ 20 | mta-sts.example.net \ 21 | wkd.example.com \ 22 | wkd.example.net \ 23 | } 24 | domain key "/etc/ssl/acme/private/mercury.example.com.key" 25 | domain certificate "/etc/ssl/acme/mercury.example.com.crt" 26 | domain full chain certificate "/etc/ssl/acme/mercury.example.com.fullchain.pem" 27 | sign with letsencrypt 28 | } 29 | -------------------------------------------------------------------------------- /src/etc/acme/letsencrypt-privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | -----END PRIVATE KEY----- 3 | -------------------------------------------------------------------------------- /src/etc/changelist.local: -------------------------------------------------------------------------------- 1 | # changelist.local 2 | # 3 | # Backup: `cp -p /etc/changelist /etc/changelist-6.4` 4 | # Install: `cat /etc/changelist.local >> /etc/changelist` 5 | # Uninstall: `sed -i '/changelist.local/,$d' /etc/changelist` 6 | # Remove: `/usr/local/bin/rmchangelist.sh` 7 | 8 | /etc/dkimproxy_out.conf 9 | /etc/dovecot/dovecot-trash.conf.ext 10 | /etc/dovecot/local.conf 11 | /etc/dovecot/conf.d/10-auth.conf 12 | /etc/dovecot/conf.d/10-mail.conf 13 | /etc/dovecot/conf.d/10-master.conf 14 | /etc/dovecot/conf.d/10-ssl.conf 15 | /etc/dovecot/conf.d/15-lda.conf 16 | /etc/dovecot/conf.d/15-mailboxes.conf 17 | /etc/dovecot/conf.d/20-imap.conf 18 | /etc/dovecot/conf.d/20-lmtp.conf 19 | /etc/dovecot/conf.d/20-managesieve.conf 20 | /etc/dovecot/conf.d/90-plugin.conf 21 | /etc/dovecot/conf.d/90-quota.conf 22 | /etc/dovecot/conf.d/90-replication.conf 23 | /etc/dovecot/conf.d/90-sieve-extprograms.conf 24 | /etc/dovecot/conf.d/90-sieve.conf 25 | /etc/dovecot/conf.d/auth-passwdfile.conf.ext 26 | /etc/mail/blacklist 27 | /etc/mail/mailname 28 | +/etc/mail/passwd 29 | /etc/mail/relays 30 | /etc/mail/vdomains 31 | /etc/mail/virtual 32 | /etc/mail/whitelist 33 | /etc/pf.conf.anchor.block 34 | /etc/pf.conf.anchor.icmp 35 | /etc/pf.conf.table.ban 36 | /etc/pf.conf.table.martians 37 | /etc/rspamd/local.d/antivirus.conf 38 | /etc/rspamd/local.d/classifier-bayes.conf 39 | /etc/rspamd/local.d/mime_types.conf 40 | /etc/rspamd/local.d/multimap.conf 41 | /etc/rspamd/local.d/options.inc 42 | /etc/rspamd/local.d/rbl.conf.optional 43 | /etc/rspamd/local.d/replies.conf 44 | /etc/rspamd/local.d/surbl.conf 45 | /etc/rspamd/local.d/worker-controller.inc 46 | /etc/rspamd/local.d/worker-normal.inc 47 | /etc/rspamd/local.d/worker-proxy.inc 48 | /etc/rspamd/override.d/bad_emails.list 49 | /etc/rspamd/override.d/emails.conf.optional 50 | /etc/ssh/sshd_banner 51 | /etc/ssl/acme/*.*.*.crt 52 | /etc/ssl/acme/*.*.*.fullchain.pem 53 | +/etc/ssl/acme/*.*.*.ocsp.resp.der 54 | /etc/ssl/acme/letsencryptauthorityx3.pem 55 | +/etc/ssl/acme/private/*.*.*.key 56 | /etc/ssl/dkim/public.key 57 | +/etc/ssl/dkim/private/private.key 58 | /var/dovecot/imapsieve/before/report-ham.sieve 59 | +/var/dovecot/imapsieve/before/report-ham.svbin 60 | /var/dovecot/imapsieve/before/report-spam.sieve 61 | +/var/dovecot/imapsieve/before/report-spam.svbin 62 | /var/dovecot/sieve/before/00-wks.sieve 63 | +/var/dovecot/sieve/before/00-wks.svbin 64 | /var/dovecot/sieve/before/spamtest.sieve 65 | +/var/dovecot/sieve/before/spamtest.svbin 66 | +/var/unbound/db/root.key 67 | +/var/unbound/db/root.zone 68 | /var/www/htdocs/*.*.*/index.html 69 | /var/www/htdocs/*.*.*/mail/config-v1.1.xml 70 | /var/www/mta-sts/mta-sts.txt 71 | /var/www/openpgpkey/hu/54f6ry7x1qqtpor16txw5gdmdbbh6a73 72 | /var/www/openpgpkey/policy 73 | /var/www/openpgpkey/submission-address 74 | /usr/local/bin/dovecot-lda.sh 75 | /usr/local/bin/learn_all_spam.sh 76 | /usr/local/bin/learn_ham.sh 77 | /usr/local/bin/learn_spam.sh 78 | /usr/local/bin/quota-warning.sh 79 | /usr/local/bin/rmchangelist.sh 80 | /usr/local/bin/wks-server.sh 81 | /root/.ssh/config 82 | /root/.ssh/known_hosts 83 | /home/dsync/.ssh/authorized_keys 84 | +/home/dsync/.ssh/id_rsa 85 | +/home/dsync/.ssh/id_ecdsa 86 | +/home/dsync/.ssh/id_ed25519 87 | /home/dsync/.ssh/id_*.pub 88 | /home/dsync/.ssh/known_hosts 89 | -------------------------------------------------------------------------------- /src/etc/daily.local: -------------------------------------------------------------------------------- 1 | next_part "Checking local special files and directories:" 2 | if [ -O /etc/mtree/special.local -a \ 3 | -G /etc/mtree/special.local -a \ 4 | ! -L /etc/mtree/special.local -a \ 5 | -r /etc/mtree/special.local -a \ 6 | -w /etc/mtree/special.local -a \ 7 | ! -x /etc/mtree/special.local ]; then 8 | echo "\tcriteria (shouldbe, reallyis)" 9 | mtree -e -p / -f /etc/mtree/special.local 10 | fi 11 | 12 | next_part "Checking packages:" 13 | pkg_add -su 14 | 15 | next_part "Let's Encrypt \"$(hostname)\":" 16 | acme-client -v $(hostname) && { 17 | rcctl reload httpd dovecot 18 | rcctl restart smtpd 19 | } 20 | ocspcheck -vNo /etc/ssl/acme/$(hostname).ocsp.resp.der \ 21 | /etc/ssl/acme/$(hostname).fullchain.pem && 22 | rcctl reload httpd 23 | 24 | next_part "Email service statistics:" 25 | smtpctl show stats 26 | printf '\n' 27 | /usr/local/bin/rspamc -h /var/run/rspamd/rspamd.sock stat 28 | /usr/local/bin/doveadm -f pager replicator status '*' | tr -d '\f' 29 | printf '\n' 30 | /usr/local/bin/doveadm -f pager quota get -A | tr -d '\f' 31 | -------------------------------------------------------------------------------- /src/etc/dhclient.conf: -------------------------------------------------------------------------------- 1 | # $OpenBSD: dhclient.conf,v 1.2 2017/10/16 23:43:41 krw Exp $ 2 | # 3 | # DHCP Client Configuration 4 | # 5 | # See dhclient.conf(5) for possible contents of this file. 6 | 7 | # rebound for unbound 8 | ignore domain-name; 9 | ignore domain-name-servers; 10 | # A ServerID is required by RFC2131 11 | require dhcp-server-identifier; 12 | -------------------------------------------------------------------------------- /src/etc/dkimproxy_out.conf: -------------------------------------------------------------------------------- 1 | # specify what address/port DKIMproxy should listen on 2 | listen 127.0.0.1:10027 3 | 4 | # specify what address/port DKIMproxy forwards mail to 5 | relay 127.0.0.1:10028 6 | 7 | # specify what domains DKIMproxy can sign for (comma-separated, no spaces) 8 | domain example.com,example.net 9 | 10 | # specify what signatures to add 11 | signature dkim(c=relaxed,a=rsa-sha256) 12 | signature domainkeys(c=nofws) 13 | 14 | # specify location of the private 1024 bits key 15 | # (!) one key for all virtual domains 16 | keyfile /etc/ssl/dkim/private/private.key 17 | 18 | # specify the selector (i.e. the name of the key record put in DNS) 19 | selector obsd 20 | 21 | # control how many processes DKIMproxy uses 22 | # - more information on these options (and others) can be found by 23 | # running `perldoc Net::Server::PreFork'. 24 | #min_servers 5 25 | #min_spare_servers 2 26 | min_servers 1 27 | min_spare_servers 1 28 | 29 | # try again later 30 | reject_error 31 | -------------------------------------------------------------------------------- /src/etc/doas.conf: -------------------------------------------------------------------------------- 1 | # $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $ 2 | # Configuration sample file for doas(1). 3 | # See doas.conf(5) for syntax and examples. 4 | 5 | # Non-exhaustive list of variables needed to build release(8) and ports(7) 6 | #permit nopass setenv { \ 7 | # FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \ 8 | # DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \ 9 | # MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \ 10 | # PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \ 11 | # SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc 12 | 13 | # Allow wheel by default 14 | permit keepenv :wheel 15 | 16 | # Allow dsync replication 17 | permit nopass dsync as vmail cmd /usr/local/bin/doveadm 18 | 19 | # WKS: expire non confirmed publication requests 20 | permit nopass setenv { HOME=/var/vmail } root as vmail cmd \ 21 | /usr/local/bin/gpg-wks-server args --cron 22 | 23 | # WKS: List the submission key 24 | permit nopass setenv { HOME=/var/vmail } root as vmail cmd \ 25 | /usr/local/bin/gpg2 args -K --with-wkd-hash key-submission@example.com 26 | 27 | # WKS: Create the submission key 28 | permit nopass setenv { HOME=/var/vmail } root as vmail cmd \ 29 | /usr/local/bin/gpg2 args \ 30 | --batch --passphrase "" --quick-gen-key key-submission@example.com 31 | 32 | # WKS: Publish the submission key 33 | permit nopass setenv { HOME=/var/vmail } root as vmail cmd \ 34 | /usr/local/bin/gpg2 args \ 35 | -o /var/lib/gnupg/wks/example.com/hu/54f6ry7x1qqtpor16txw5gdmdbbh6a73 \ 36 | --export-options export-minimal --export key-submission@example.com 37 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/10-auth.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Authentication processes 3 | ## 4 | 5 | # Disable LOGIN command and all other plaintext authentications unless 6 | # SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP 7 | # matches the local IP (ie. you're connecting from the same computer), the 8 | # connection is considered secure and plaintext authentication is allowed. 9 | # See also ssl=required setting. 10 | #disable_plaintext_auth = yes 11 | 12 | # Authentication cache size (e.g. 10M). 0 means it's disabled. Note that 13 | # bsdauth, PAM and vpopmail require cache_key to be set for caching to be used. 14 | auth_cache_size = 10M # default: 0 15 | # Time to live for cached data. After TTL expires the cached record is no 16 | # longer used, *except* if the main database lookup returns internal failure. 17 | # We also try to handle password changes automatically: If user's previous 18 | # authentication was successful, but this one wasn't, the cache isn't used. 19 | # For now this works only with plaintext authentication. 20 | auth_cache_ttl = 1 hour 21 | # TTL for negative hits (user not found, password mismatch). 22 | # 0 disables caching them completely. 23 | auth_cache_negative_ttl = 1 hour 24 | 25 | # Space separated list of realms for SASL authentication mechanisms that need 26 | # them. You can leave it empty if you don't want to support multiple realms. 27 | # Many clients simply use the first one listed here, so keep the default realm 28 | # first. 29 | #auth_realms = 30 | 31 | # Default realm/domain to use if none was specified. This is used for both 32 | # SASL realms and appending @domain to username in plaintext logins. 33 | #auth_default_realm = 34 | 35 | # List of allowed characters in username. If the user-given username contains 36 | # a character not listed in here, the login automatically fails. This is just 37 | # an extra check to make sure user can't exploit any potential quote escaping 38 | # vulnerabilities with SQL/LDAP databases. If you want to allow all characters, 39 | # set this value to empty. 40 | #auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@ 41 | 42 | # Username character translations before it's looked up from databases. The 43 | # value contains series of from -> to characters. For example "#@/@" means 44 | # that '#' and '/' characters are translated to '@'. 45 | #auth_username_translation = 46 | 47 | # Username formatting before it's looked up from databases. You can use 48 | # the standard variables here, eg. %Lu would lowercase the username, %n would 49 | # drop away the domain if it was given, or "%n-AT-%d" would change the '@' into 50 | # "-AT-". This translation is done after auth_username_translation changes. 51 | #auth_username_format = %Lu 52 | 53 | # If you want to allow master users to log in by specifying the master 54 | # username within the normal username string (ie. not using SASL mechanism's 55 | # support for it), you can specify the separator character here. The format 56 | # is then . UW-IMAP uses "*" as the 57 | # separator, so that could be a good choice. 58 | #auth_master_user_separator = 59 | 60 | # Username to use for users logging in with ANONYMOUS SASL mechanism 61 | #auth_anonymous_username = anonymous 62 | 63 | # Maximum number of dovecot-auth worker processes. They're used to execute 64 | # blocking passdb and userdb queries (eg. MySQL and PAM). They're 65 | # automatically created and destroyed as needed. 66 | #auth_worker_max_count = 30 67 | 68 | # Host name to use in GSSAPI principal names. The default is to use the 69 | # name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab 70 | # entries. 71 | #auth_gssapi_hostname = 72 | 73 | # Kerberos keytab to use for the GSSAPI mechanism. Will use the system 74 | # default (usually /etc/krb5.keytab) if not specified. You may need to change 75 | # the auth service to run as root to be able to read this file. 76 | #auth_krb5_keytab = 77 | 78 | # Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and 79 | # ntlm_auth helper. 80 | #auth_use_winbind = no 81 | 82 | # Path for Samba's ntlm_auth helper binary. 83 | #auth_winbind_helper_path = /usr/bin/ntlm_auth 84 | 85 | # Time to delay before replying to failed authentications. 86 | #auth_failure_delay = 2 secs 87 | 88 | # Require a valid SSL client certificate or the authentication fails. 89 | #auth_ssl_require_client_cert = no 90 | 91 | # Take the username from client's SSL certificate, using 92 | # X509_NAME_get_text_by_NID() which returns the subject's DN's 93 | # CommonName. 94 | #auth_ssl_username_from_cert = no 95 | 96 | # Space separated list of wanted authentication mechanisms: 97 | # plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey 98 | # gss-spnego 99 | # NOTE: See also disable_plaintext_auth setting. 100 | auth_mechanisms = plain 101 | 102 | ## 103 | ## Password and user databases 104 | ## 105 | 106 | # 107 | # Password database is used to verify user's password (and nothing more). 108 | # You can have multiple passdbs and userdbs. This is useful if you want to 109 | # allow both system users (/etc/passwd) and virtual users to login without 110 | # duplicating the system users into virtual database. 111 | # 112 | # 113 | # 114 | # User database specifies where mails are located and what user/group IDs 115 | # own them. For single-UID configuration use "static" userdb. 116 | # 117 | # 118 | 119 | #!include auth-deny.conf.ext 120 | #!include auth-master.conf.ext 121 | 122 | #!include auth-system.conf.ext 123 | #!include auth-sql.conf.ext 124 | #!include auth-ldap.conf.ext 125 | !include auth-passwdfile.conf.ext 126 | #!include auth-checkpassword.conf.ext 127 | #!include auth-vpopmail.conf.ext 128 | #!include auth-static.conf.ext 129 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/10-mail.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Mailbox locations and namespaces 3 | ## 4 | 5 | # Location for users' mailboxes. The default is empty, which means that Dovecot 6 | # tries to find the mailboxes automatically. This won't work if the user 7 | # doesn't yet have any mail, so you should explicitly tell Dovecot the full 8 | # location. 9 | # 10 | # If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u) 11 | # isn't enough. You'll also need to tell Dovecot where the other mailboxes are 12 | # kept. This is called the "root mail directory", and it must be the first 13 | # path given in the mail_location setting. 14 | # 15 | # There are a few special variables you can use, eg.: 16 | # 17 | # %u - username 18 | # %n - user part in user@domain, same as %u if there's no domain 19 | # %d - domain part in user@domain, empty if there's no domain 20 | # %h - home directory 21 | # 22 | # See doc/wiki/Variables.txt for full list. Some examples: 23 | # 24 | # mail_location = maildir:~/Maildir 25 | # mail_location = mbox:~/mail:INBOX=/var/mail/%u 26 | # mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n 27 | # 28 | # 29 | # 30 | # Mailbox autocreation 31 | mail_location = maildir:/var/vmail/%d/%n/Maildir:LAYOUT=fs # (default: ) 32 | 33 | # If you need to set multiple mailbox locations or want to change default 34 | # namespace settings, you can do it by defining namespace sections. 35 | # 36 | # You can have private, shared and public namespaces. Private namespaces 37 | # are for user's personal mails. Shared namespaces are for accessing other 38 | # users' mailboxes that have been shared. Public namespaces are for shared 39 | # mailboxes that are managed by sysadmin. If you create any shared or public 40 | # namespaces you'll typically want to enable ACL plugin also, otherwise all 41 | # users can access all the shared mailboxes, assuming they have permissions 42 | # on filesystem level to do so. 43 | namespace inbox { 44 | # Namespace type: private, shared or public 45 | #type = private 46 | 47 | # Hierarchy separator to use. You should use the same separator for all 48 | # namespaces or some clients get confused. '/' is usually a good one. 49 | # The default however depends on the underlying mail storage format. 50 | separator = / # allow illegal characters with Listescape plugin, default: 51 | 52 | # Prefix required to access this namespace. This needs to be different for 53 | # all namespaces. For example "Public/". 54 | #prefix = 55 | 56 | # Physical location of the mailbox. This is in same format as 57 | # mail_location, which is also the default for it. 58 | location = maildir:/var/vmail/%d/%n/Maildir:LAYOUT=fs # (default: ) 59 | 60 | # There can be only one INBOX, and this setting defines which namespace 61 | # has it. 62 | inbox = yes 63 | 64 | # If namespace is hidden, it's not advertised to clients via NAMESPACE 65 | # extension. You'll most likely also want to set list=no. This is mostly 66 | # useful when converting from another server with different namespaces which 67 | # you want to deprecate but still keep working. For example you can create 68 | # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". 69 | #hidden = no 70 | 71 | # Show the mailboxes under this namespace with LIST command. This makes the 72 | # namespace visible for clients that don't support NAMESPACE extension. 73 | # "children" value lists child mailboxes, but hides the namespace prefix. 74 | #list = yes 75 | 76 | # Namespace handles its own subscriptions. If set to "no", the parent 77 | # namespace handles them (empty prefix should always have this as "yes") 78 | #subscriptions = yes 79 | 80 | # See 15-mailboxes.conf for definitions of special mailboxes. 81 | } 82 | 83 | # Example shared namespace configuration 84 | #namespace { 85 | #type = shared 86 | #separator = / 87 | 88 | # Mailboxes are visible under "shared/user@domain/" 89 | # %%n, %%d and %%u are expanded to the destination user. 90 | #prefix = shared/%%u/ 91 | 92 | # Mail location for other users' mailboxes. Note that %variables and ~/ 93 | # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the 94 | # destination user's data. 95 | #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u 96 | 97 | # Use the default namespace for saving subscriptions. 98 | #subscriptions = no 99 | 100 | # List the shared/ namespace only if there are visible shared mailboxes. 101 | #list = children 102 | #} 103 | # Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"? 104 | #mail_shared_explicit_inbox = no 105 | 106 | # System user and group used to access mails. If you use multiple, userdb 107 | # can override these by returning uid or gid fields. You can use either numbers 108 | # or names. 109 | #mail_uid = 110 | #mail_gid = 111 | 112 | # Group to enable temporarily for privileged operations. Currently this is 113 | # used only with INBOX when either its initial creation or dotlocking fails. 114 | # Typically this is set to "mail" to give access to /var/mail. 115 | mail_privileged_group = vmail # (default: ) 116 | 117 | # Grant access to these supplementary groups for mail processes. Typically 118 | # these are used to set up access to shared mailboxes. Note that it may be 119 | # dangerous to set these if users can create symlinks (e.g. if "mail" group is 120 | # set here, ln -s /var/mail ~/mail/var could allow a user to delete others' 121 | # mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it). 122 | #mail_access_groups = 123 | 124 | # Allow full filesystem access to clients. There's no access checks other than 125 | # what the operating system does for the active UID/GID. It works with both 126 | # maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/ 127 | # or ~user/. 128 | #mail_full_filesystem_access = no 129 | 130 | # Dictionary for key=value mailbox attributes. This is used for example by 131 | # URLAUTH and METADATA extensions. 132 | #mail_attribute_dict = 133 | 134 | # A comment or note that is associated with the server. This value is 135 | # accessible for authenticated users through the IMAP METADATA server 136 | # entry "/shared/comment". 137 | #mail_server_comment = "" 138 | 139 | # Indicates a method for contacting the server administrator. According to 140 | # RFC 5464, this value MUST be a URI (e.g., a mailto: or tel: URL), but that 141 | # is currently not enforced. Use for example mailto:admin@example.com. This 142 | # value is accessible for authenticated users through the IMAP METADATA server 143 | # entry "/shared/admin". 144 | #mail_server_admin = 145 | 146 | ## 147 | ## Mail processes 148 | ## 149 | 150 | # Don't use mmap() at all. This is required if you store indexes to shared 151 | # filesystems (NFS or clustered filesystem) or for some operating systems 152 | # which use a separate cache for mmap, such as OpenBSD. 153 | mmap_disable = yes 154 | 155 | # Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL 156 | # since version 3, so this should be safe to use nowadays by default. 157 | #dotlock_use_excl = yes 158 | 159 | # When to use fsync() or fdatasync() calls: 160 | # optimized (default): Whenever necessary to avoid losing important data 161 | # always: Useful with e.g. NFS when write()s are delayed 162 | # never: Never use it (best performance, but crashes can lose data) 163 | #mail_fsync = optimized 164 | 165 | # Locking method for index files. Alternatives are fcntl, flock and dotlock. 166 | # Dotlocking uses some tricks which may create more disk I/O than other locking 167 | # methods. NFS users: flock doesn't work, remember to change mmap_disable. 168 | #lock_method = fcntl 169 | 170 | # Directory where mails can be temporarily stored. Usually it's used only for 171 | # mails larger than >= 128 kB. It's used by various parts of Dovecot, for 172 | # example LDA/LMTP while delivering large mails or zlib plugin for keeping 173 | # uncompressed mails. 174 | #mail_temp_dir = /tmp 175 | 176 | # Valid UID range for users, defaults to 500 and above. This is mostly 177 | # to make sure that users can't log in as daemons or other system users. 178 | # Note that denying root logins is hardcoded to dovecot binary and can't 179 | # be done even if first_valid_uid is set to 0. 180 | first_valid_uid = 2000 # vmail (default: 1000) 181 | last_valid_uid = 2000 # vmail (default: 0) 182 | 183 | # Valid GID range for users, defaults to non-root/wheel. Users having 184 | # non-valid GID as primary group ID aren't allowed to log in. If user 185 | # belongs to supplementary groups with non-valid GIDs, those groups are 186 | # not set. 187 | #first_valid_gid = 1 188 | #last_valid_gid = 0 189 | 190 | # Maximum allowed length for mail keyword name. It's only forced when trying 191 | # to create new keywords. 192 | #mail_max_keyword_length = 50 193 | 194 | # ':' separated list of directories under which chrooting is allowed for mail 195 | # processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too). 196 | # This setting doesn't affect login_chroot, mail_chroot or auth chroot 197 | # settings. If this setting is empty, "/./" in home dirs are ignored. 198 | # WARNING: Never add directories here which local users can modify, that 199 | # may lead to root exploit. Usually this should be done only if you don't 200 | # allow shell access for users. 201 | #valid_chroot_dirs = 202 | 203 | # Default chroot directory for mail processes. This can be overridden for 204 | # specific users in user database by giving /./ in user's home directory 205 | # (eg. /home/./user chroots into /home). Note that usually there is no real 206 | # need to do chrooting, Dovecot doesn't allow users to access files outside 207 | # their mail directory anyway. If your home directories are prefixed with 208 | # the chroot directory, append "/." to mail_chroot. 209 | #mail_chroot = 210 | 211 | # UNIX socket path to master authentication server to find users. 212 | # This is used by imap (for shared users) and lda. 213 | #auth_socket_path = /var/dovecot/auth-userdb 214 | 215 | # Directory where to look up mail plugins. 216 | mail_plugin_dir = /usr/local/lib/dovecot 217 | 218 | # Space separated list of plugins to load for all services. Plugins specific to 219 | # IMAP, LDA, etc. are added to this list in their own .conf files. 220 | mail_plugins = $mail_plugins quota trash zlib notify replication # fts fts_squat listescape 221 | 222 | ## 223 | ## Mailbox handling optimizations 224 | ## 225 | 226 | # Mailbox list indexes can be used to optimize IMAP STATUS commands. They are 227 | # also required for IMAP NOTIFY extension to be enabled. 228 | mailbox_list_index = yes 229 | 230 | # Trust mailbox list index to be up-to-date. This reduces disk I/O at the cost 231 | # of potentially returning out-of-date results after e.g. server crashes. 232 | # The results will be automatically fixed once the folders are opened. 233 | #mailbox_list_index_very_dirty_syncs = yes 234 | 235 | # Should INBOX be kept up-to-date in the mailbox list index? By default it's 236 | # not, because most of the mailbox accesses will open INBOX anyway. 237 | #mailbox_list_index_include_inbox = no 238 | 239 | # The minimum number of mails in a mailbox before updates are done to cache 240 | # file. This allows optimizing Dovecot's behavior to do less disk writes at 241 | # the cost of more disk reads. 242 | #mail_cache_min_mail_count = 0 243 | 244 | # When IDLE command is running, mailbox is checked once in a while to see if 245 | # there are any new mails or other changes. This setting defines the minimum 246 | # time to wait between those checks. Dovecot can also use inotify and 247 | # kqueue to find out immediately when changes occur. 248 | #mailbox_idle_check_interval = 30 secs 249 | 250 | # Save mails with CR+LF instead of plain LF. This makes sending those mails 251 | # take less CPU, especially with sendfile() syscall with Linux and FreeBSD. 252 | # But it also creates a bit more disk I/O which may just make it slower. 253 | # Also note that if other software reads the mboxes/maildirs, they may handle 254 | # the extra CRs wrong and cause problems. 255 | #mail_save_crlf = no 256 | 257 | # Max number of mails to keep open and prefetch to memory. This only works with 258 | # some mailbox formats and/or operating systems. 259 | #mail_prefetch_count = 0 260 | 261 | # How often to scan for stale temporary files and delete them (0 = never). 262 | # These should exist only after Dovecot dies in the middle of saving mails. 263 | #mail_temp_scan_interval = 1w 264 | 265 | # How many slow mail accesses sorting can perform before it returns failure. 266 | # With IMAP the reply is: NO [LIMIT] Requested sort would have taken too long. 267 | # The untagged SORT reply is still returned, but it's likely not correct. 268 | #mail_sort_max_read_count = 0 269 | 270 | protocol !indexer-worker { 271 | # If folder vsize calculation requires opening more than this many mails from 272 | # disk (i.e. mail sizes aren't in cache already), return failure and finish 273 | # the calculation via indexer process. Disabled by default. This setting must 274 | # be 0 for indexer-worker processes. 275 | #mail_vsize_bg_after_count = 0 276 | } 277 | 278 | ## 279 | ## Maildir-specific settings 280 | ## 281 | 282 | # By default LIST command returns all entries in maildir beginning with a dot. 283 | # Enabling this option makes Dovecot return only entries which are directories. 284 | # This is done by stat()ing each entry, so it causes more disk I/O. 285 | # (For systems setting struct dirent->d_type, this check is free and it's 286 | # done always regardless of this setting) 287 | #maildir_stat_dirs = no 288 | 289 | # When copying a message, do it with hard links whenever possible. This makes 290 | # the performance much better, and it's unlikely to have any side effects. 291 | #maildir_copy_with_hardlinks = yes 292 | 293 | # Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only 294 | # when its mtime changes unexpectedly or when we can't find the mail otherwise. 295 | #maildir_very_dirty_syncs = no 296 | 297 | # If enabled, Dovecot doesn't use the S= in the Maildir filenames for 298 | # getting the mail's physical size, except when recalculating Maildir++ quota. 299 | # This can be useful in systems where a lot of the Maildir filenames have a 300 | # broken size. The performance hit for enabling this is very small. 301 | #maildir_broken_filename_sizes = no 302 | 303 | # Always move mails from new/ directory to cur/, even when the \Recent flags 304 | # aren't being reset. 305 | #maildir_empty_new = no 306 | 307 | ## 308 | ## mbox-specific settings 309 | ## 310 | 311 | # Which locking methods to use for locking mbox. There are four available: 312 | # dotlock: Create .lock file. This is the oldest and most NFS-safe 313 | # solution. If you want to use /var/mail/ like directory, the users 314 | # will need write access to that directory. 315 | # dotlock_try: Same as dotlock, but if it fails because of permissions or 316 | # because there isn't enough disk space, just skip it. 317 | # fcntl : Use this if possible. Works with NFS too if lockd is used. 318 | # flock : May not exist in all systems. Doesn't work with NFS. 319 | # lockf : May not exist in all systems. Doesn't work with NFS. 320 | # 321 | # You can use multiple locking methods; if you do the order they're declared 322 | # in is important to avoid deadlocks if other MTAs/MUAs are using multiple 323 | # locking methods as well. Some operating systems don't allow using some of 324 | # them simultaneously. 325 | #mbox_read_locks = fcntl 326 | mbox_write_locks = fcntl 327 | 328 | # Maximum time to wait for lock (all of them) before aborting. 329 | #mbox_lock_timeout = 5 mins 330 | 331 | # If dotlock exists but the mailbox isn't modified in any way, override the 332 | # lock file after this much time. 333 | #mbox_dotlock_change_timeout = 2 mins 334 | 335 | # When mbox changes unexpectedly we have to fully read it to find out what 336 | # changed. If the mbox is large this can take a long time. Since the change 337 | # is usually just a newly appended mail, it'd be faster to simply read the 338 | # new mails. If this setting is enabled, Dovecot does this but still safely 339 | # fallbacks to re-reading the whole mbox file whenever something in mbox isn't 340 | # how it's expected to be. The only real downside to this setting is that if 341 | # some other MUA changes message flags, Dovecot doesn't notice it immediately. 342 | # Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK 343 | # commands. 344 | #mbox_dirty_syncs = yes 345 | 346 | # Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE, 347 | # EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored. 348 | #mbox_very_dirty_syncs = no 349 | 350 | # Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK 351 | # commands and when closing the mailbox). This is especially useful for POP3 352 | # where clients often delete all mails. The downside is that our changes 353 | # aren't immediately visible to other MUAs. 354 | #mbox_lazy_writes = yes 355 | 356 | # If mbox size is smaller than this (e.g. 100k), don't write index files. 357 | # If an index file already exists it's still read, just not updated. 358 | #mbox_min_index_size = 0 359 | 360 | # Mail header selection algorithm to use for MD5 POP3 UIDLs when 361 | # pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired 362 | # algorithm, but it fails if the first Received: header isn't unique in all 363 | # mails. An alternative algorithm is "all" that selects all headers. 364 | #mbox_md5 = apop3d 365 | 366 | ## 367 | ## mdbox-specific settings 368 | ## 369 | 370 | # Maximum dbox file size until it's rotated. 371 | #mdbox_rotate_size = 10M 372 | 373 | # Maximum dbox file age until it's rotated. Typically in days. Day begins 374 | # from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled. 375 | #mdbox_rotate_interval = 0 376 | 377 | # When creating new mdbox files, immediately preallocate their size to 378 | # mdbox_rotate_size. This setting currently works only in Linux with some 379 | # filesystems (ext4, xfs). 380 | #mdbox_preallocate_space = no 381 | 382 | ## 383 | ## Mail attachments 384 | ## 385 | 386 | # sdbox and mdbox support saving mail attachments to external files, which 387 | # also allows single instance storage for them. Other backends don't support 388 | # this for now. 389 | 390 | # Directory root where to store mail attachments. Disabled, if empty. 391 | #mail_attachment_dir = 392 | 393 | # Attachments smaller than this aren't saved externally. It's also possible to 394 | # write a plugin to disable saving specific attachments externally. 395 | #mail_attachment_min_size = 128k 396 | 397 | # Filesystem backend to use for saving attachments: 398 | # posix : No SiS done by Dovecot (but this might help FS's own deduplication) 399 | # sis posix : SiS with immediate byte-by-byte comparison during saving 400 | # sis-queue posix : SiS with delayed comparison and deduplication 401 | #mail_attachment_fs = sis posix 402 | 403 | # Hash format to use in attachment filenames. You can add any text and 404 | # variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}. 405 | # Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits 406 | #mail_attachment_hash = %{sha1} 407 | 408 | # Settings to control adding $HasAttachment or $HasNoAttachment keywords. 409 | # By default, all MIME parts with Content-Disposition=attachment, or inlines 410 | # with filename parameter are consired attachments. 411 | # add-flags-on-save - Add the keywords when saving new mails. 412 | # content-type=type or !type - Include/exclude content type. Excluding will 413 | # never consider the matched MIME part as attachment. Including will only 414 | # negate an exclusion (e.g. content-type=!foo/* content-type=foo/bar). 415 | # exclude-inlined - Exclude any Content-Disposition=inline MIME part. 416 | #mail_attachment_detection_options = 417 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/10-master.conf: -------------------------------------------------------------------------------- 1 | #default_process_limit = 100 2 | #default_client_limit = 1000 3 | 4 | # Default VSZ (virtual memory size) limit for service processes. This is mainly 5 | # intended to catch and kill processes that leak memory before they eat up 6 | # everything. 7 | default_vsz_limit = 128M # (default: 256M) 8 | 9 | # Login user is internally used by login processes. This is the most untrusted 10 | # user in Dovecot system. It shouldn't have access to anything at all. 11 | #default_login_user = _dovenull 12 | 13 | # Internal user is used by unprivileged processes. It should be separate from 14 | # login user, so that login processes can't disturb other processes. 15 | #default_internal_user = _dovecot 16 | 17 | service imap-login { 18 | inet_listener imap { 19 | port = 0 # (default: 143) 20 | address = 127.0.0.1, ::1 # plain-text IMAP 21 | } 22 | inet_listener imaps { 23 | #port = 993 24 | #ssl = yes 25 | } 26 | 27 | # Number of connections to handle before starting a new process. Typically 28 | # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0 29 | # is faster. 30 | #service_count = 1 31 | 32 | # Number of processes to always keep waiting for more connections. 33 | #process_min_avail = 0 34 | 35 | # If you set service_count=0, you probably need to grow this. 36 | #vsz_limit = $default_vsz_limit 37 | } 38 | 39 | service pop3-login { 40 | #inet_listener pop3 { 41 | # port = 0 # (default: 110) 42 | #} 43 | #inet_listener pop3s { 44 | # port = 0 # (default: 995) 45 | # #ssl = yes 46 | #} 47 | } 48 | 49 | service submission-login { 50 | #inet_listener submission { 51 | # port = 0 # (default: 587) 52 | #} 53 | } 54 | 55 | service lmtp { 56 | unix_listener lmtp { 57 | mode = 0660 # (default: 0666) 58 | user = vmail 59 | group = vmail 60 | } 61 | 62 | # Create inet listener only if you can't use the above UNIX socket 63 | #inet_listener lmtp { 64 | # Avoid making LMTP visible for the entire internet 65 | #address = 66 | #port = 67 | #} 68 | } 69 | 70 | service imap { 71 | # Most of the memory goes to mmap()ing files. You may need to increase this 72 | # limit if you have huge mailboxes. 73 | #vsz_limit = $default_vsz_limit 74 | 75 | # Max. number of IMAP processes (connections) 76 | #process_limit = 1024 77 | } 78 | 79 | service pop3 { 80 | # Max. number of POP3 processes (connections) 81 | #process_limit = 1024 82 | } 83 | 84 | service submission { 85 | # Max. number of SMTP Submission processes (connections) 86 | #process_limit = 1024 87 | } 88 | 89 | service auth { 90 | # auth_socket_path points to this userdb socket by default. It's typically 91 | # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have 92 | # full permissions to this socket are able to get a list of all usernames and 93 | # get the results of everyone's userdb lookups. 94 | # 95 | # The default 0666 mode allows anyone to connect to the socket, but the 96 | # userdb lookups will succeed only if the userdb returns an "uid" field that 97 | # matches the caller process's UID. Also if caller's uid or gid matches the 98 | # socket's uid or gid the lookup succeeds. Anything else causes a failure. 99 | # 100 | # To give the caller full permissions to lookup all users, set the mode to 101 | # something else than 0666 and Dovecot lets the kernel enforce the 102 | # permissions (e.g. 0777 allows everyone full permissions). 103 | unix_listener auth-userdb { 104 | mode = 0660 # (default: 0666) 105 | user = vmail # (default: ) 106 | group = vmail # (default: ) 107 | } 108 | 109 | # Postfix smtp-auth 110 | #unix_listener /var/spool/postfix/private/auth { 111 | # mode = 0666 112 | #} 113 | 114 | # Auth process is run as this user. 115 | #user = $default_internal_user 116 | } 117 | 118 | service auth-worker { 119 | # Auth worker process is run as root by default, so that it can access 120 | # /etc/shadow. If this isn't necessary, the user should be changed to 121 | # $default_internal_user. 122 | user = $default_internal_user # (default: root) 123 | } 124 | 125 | service dict { 126 | # If dict proxy is used, mail processes should have access to its socket. 127 | # For example: mode=0660, group=vmail and global mail_access_groups=vmail 128 | unix_listener dict { 129 | #mode = 0600 130 | #user = 131 | #group = 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/10-ssl.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## SSL settings 3 | ## 4 | 5 | # SSL/TLS support: yes, no, required. 6 | ssl = required # (default: yes) 7 | 8 | # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before 9 | # dropping root privileges, so keep the key file unreadable by anyone but 10 | # root. Included doc/mkcert.sh can be used to easily generate self-signed 11 | # certificate, just make sure to update the domains in dovecot-openssl.cnf 12 | ssl_cert = was automatically rejected:%n%r 30 | 31 | # Delimiter character between local-part and detail in email address. 32 | #recipient_delimiter = + 33 | 34 | # Header where the original recipient address (SMTP's RCPT TO: address) is taken 35 | # from if not available elsewhere. With dovecot-lda -a parameter overrides this. 36 | # A commonly used header for this is X-Original-To. 37 | #lda_original_recipient_header = 38 | 39 | # Should saving a mail to a nonexistent mailbox automatically create it? 40 | #lda_mailbox_autocreate = no 41 | 42 | # Should automatically created mailboxes be also automatically subscribed? 43 | #lda_mailbox_autosubscribe = no 44 | 45 | protocol lda { 46 | # Space separated list of plugins to load (default is global mail_plugins). 47 | mail_plugins = $mail_plugins sieve zlib # (default: $mail_plugins) 48 | } 49 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/15-mailboxes.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Mailbox definitions 3 | ## 4 | 5 | # Each mailbox is specified in a separate mailbox section. The section name 6 | # specifies the mailbox name. If it has spaces, you can put the name 7 | # "in quotes". These sections can contain the following mailbox settings: 8 | # 9 | # auto: 10 | # Indicates whether the mailbox with this name is automatically created 11 | # implicitly when it is first accessed. The user can also be automatically 12 | # subscribed to the mailbox after creation. The following values are 13 | # defined for this setting: 14 | # 15 | # no - Never created automatically. 16 | # create - Automatically created, but no automatic subscription. 17 | # subscribe - Automatically created and subscribed. 18 | # 19 | # special_use: 20 | # A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the 21 | # mailbox. There are no validity checks, so you could specify anything 22 | # you want in here, but it's not a good idea to use flags other than the 23 | # standard ones specified in the RFC: 24 | # 25 | # \All - This (virtual) mailbox presents all messages in the 26 | # user's message store. 27 | # \Archive - This mailbox is used to archive messages. 28 | # \Drafts - This mailbox is used to hold draft messages. 29 | # \Flagged - This (virtual) mailbox presents all messages in the 30 | # user's message store marked with the IMAP \Flagged flag. 31 | # \Junk - This mailbox is where messages deemed to be junk mail 32 | # are held. 33 | # \Sent - This mailbox is used to hold copies of messages that 34 | # have been sent. 35 | # \Trash - This mailbox is used to hold messages that have been 36 | # deleted. 37 | # 38 | # comment: 39 | # Defines a default comment or note associated with the mailbox. This 40 | # value is accessible through the IMAP METADATA mailbox entries 41 | # "/shared/comment" and "/private/comment". Users with sufficient 42 | # privileges can override the default value for entries with a custom 43 | # value. 44 | 45 | # https://wiki2.dovecot.org/MailboxSettings 46 | # NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf. 47 | namespace inbox { 48 | # These mailboxes are widely used and could perhaps be created automatically: 49 | mailbox Drafts { 50 | auto = create # some clients poll until it's created 51 | special_use = \Drafts 52 | } 53 | mailbox Junk { 54 | special_use = \Junk 55 | } 56 | mailbox Spam { 57 | auto = create # autocreate Spam, but don't autosubscribe 58 | autoexpunge = 30d 59 | special_use = \Junk 60 | } 61 | mailbox Trash { 62 | autoexpunge = 30d 63 | special_use = \Trash 64 | } 65 | 66 | # For \Sent mailboxes there are two widely used names. We'll mark both of 67 | # them as \Sent. User typically deletes one of them if duplicates are created. 68 | mailbox Sent { 69 | auto = subscribe # autocreate and autosubscribe the Sent mailbox 70 | special_use = \Sent 71 | } 72 | mailbox "Sent Messages" { 73 | special_use = \Sent 74 | } 75 | 76 | # If you have a virtual "All messages" mailbox: 77 | #mailbox virtual/All { 78 | # special_use = \All 79 | # comment = All my messages 80 | #} 81 | 82 | # If you have a virtual "Flagged" mailbox: 83 | #mailbox virtual/Flagged { 84 | # special_use = \Flagged 85 | # comment = All my flagged messages 86 | #} 87 | } 88 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/20-imap.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## IMAP specific settings 3 | ## 4 | 5 | # If nothing happens for this long while client is IDLEing, move the connection 6 | # to imap-hibernate process and close the old imap process. This saves memory, 7 | # because connections use very little memory in imap-hibernate process. The 8 | # downside is that recreating the imap process back uses some resources. 9 | #imap_hibernate_timeout = 0 10 | 11 | # Maximum IMAP command line length. Some clients generate very long command 12 | # lines with huge mailboxes, so you may need to raise this if you get 13 | # "Too long argument" or "IMAP command line too large" errors often. 14 | #imap_max_line_length = 64k 15 | 16 | # IMAP logout format string: 17 | # %i - total number of bytes read from client 18 | # %o - total number of bytes sent to client 19 | # %{fetch_hdr_count} - Number of mails with mail header data sent to client 20 | # %{fetch_hdr_bytes} - Number of bytes with mail header data sent to client 21 | # %{fetch_body_count} - Number of mails with mail body data sent to client 22 | # %{fetch_body_bytes} - Number of bytes with mail body data sent to client 23 | # %{deleted} - Number of mails where client added \Deleted flag 24 | # %{expunged} - Number of mails that client expunged, which does not 25 | # include automatically expunged mails 26 | # %{autoexpunged} - Number of mails that were automatically expunged after 27 | # client disconnected 28 | # %{trashed} - Number of mails that client copied/moved to the 29 | # special_use=\Trash mailbox. 30 | # %{appended} - Number of mails saved during the session 31 | #imap_logout_format = in=%i out=%o deleted=%{deleted} expunged=%{expunged} \ 32 | # trashed=%{trashed} hdr_count=%{fetch_hdr_count} \ 33 | # hdr_bytes=%{fetch_hdr_bytes} body_count=%{fetch_body_count} \ 34 | # body_bytes=%{fetch_body_bytes} 35 | 36 | # Override the IMAP CAPABILITY response. If the value begins with '+', 37 | # add the given capabilities on top of the defaults (e.g. +XFOO XBAR). 38 | imap_capability = +SPECIAL-USE # (default: ) 39 | 40 | # How long to wait between "OK Still here" notifications when client is 41 | # IDLEing. 42 | imap_idle_notify_interval = 4 mins # (default: 2 mins) 43 | 44 | # ID field names and values to send to clients. Using * as the value makes 45 | # Dovecot use the default value. The following fields have default values 46 | # currently: name, version, os, os-version, support-url, support-email. 47 | #imap_id_send = 48 | 49 | # ID fields sent by client to log. * means everything. 50 | #imap_id_log = 51 | 52 | # Workarounds for various client bugs: 53 | # delay-newmail: 54 | # Send EXISTS/RECENT new mail notifications only when replying to NOOP 55 | # and CHECK commands. Some clients ignore them otherwise, for example OSX 56 | # Mail ( 22 | #service_count = 1 23 | 24 | # Number of processes to always keep waiting for more connections. 25 | #process_min_avail = 0 26 | 27 | # If you set service_count=0, you probably need to grow this. 28 | #vsz_limit = 64M 29 | } 30 | 31 | #service managesieve { 32 | # Max. number of ManageSieve processes (connections) 33 | #process_limit = 1024 34 | #} 35 | 36 | # Service configuration 37 | 38 | protocol sieve { 39 | # Maximum ManageSieve command line length in bytes. ManageSieve usually does 40 | # not involve overly long command lines, so this setting will not normally 41 | # need adjustment 42 | #managesieve_max_line_length = 65536 43 | 44 | # Maximum number of ManageSieve connections allowed for a user from each IP 45 | # address. 46 | # NOTE: The username is compared case-sensitively. 47 | #mail_max_userip_connections = 10 48 | 49 | # Space separated list of plugins to load (none known to be useful so far). 50 | # Do NOT try to load IMAP plugins here. 51 | #mail_plugins = 52 | 53 | # MANAGESIEVE logout format string: 54 | # %i - total number of bytes read from client 55 | # %o - total number of bytes sent to client 56 | # %{put_bytes} - Number of bytes saved using PUTSCRIPT command 57 | # %{put_count} - Number of scripts saved using PUTSCRIPT command 58 | # %{get_bytes} - Number of bytes read using GETCRIPT command 59 | # %{get_count} - Number of scripts read using GETSCRIPT command 60 | # %{get_bytes} - Number of bytes processed using CHECKSCRIPT command 61 | # %{get_count} - Number of scripts checked using CHECKSCRIPT command 62 | # %{deleted_count} - Number of scripts deleted using DELETESCRIPT command 63 | # %{renamed_count} - Number of scripts renamed using RENAMESCRIPT command 64 | #managesieve_logout_format = bytes=%i/%o 65 | 66 | # To fool ManageSieve clients that are focused on CMU's timesieved you can 67 | # specify the IMPLEMENTATION capability that Dovecot reports to clients. 68 | # For example: 'Cyrus timsieved v2.2.13' 69 | #managesieve_implementation_string = Dovecot Pigeonhole 70 | 71 | # Explicitly specify the SIEVE and NOTIFY capability reported by the server 72 | # before login. If left unassigned these will be reported dynamically 73 | # according to what the Sieve interpreter supports by default (after login 74 | # this may differ depending on the user). 75 | #managesieve_sieve_capability = 76 | #managesieve_notify_capability = 77 | 78 | # The maximum number of compile errors that are returned to the client upon 79 | # script upload or script verification. 80 | #managesieve_max_compile_errors = 5 81 | 82 | # Refer to 90-sieve.conf for script quota configuration and configuration of 83 | # Sieve execution limits. 84 | } 85 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/90-plugin.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Plugin settings 3 | ## 4 | 5 | # All wanted plugins must be listed in mail_plugins setting before any of the 6 | # settings take effect. See for list of plugins and 7 | # their configuration. Note that %variable expansion is done for all values. 8 | 9 | plugin { 10 | #setting_name = value 11 | 12 | # Listescape plugin 13 | # The default escape character is '\', but you can change it. 14 | # Note that even here the expansion of % takes place, thus you need to 15 | # use "%%" if you want to have the % sign as the escape character. 16 | #listescape_char = "\\" 17 | 18 | # Trash Plugin 19 | trash = /etc/dovecot/dovecot-trash.conf.ext 20 | 21 | # Zlib plugin 22 | zlib_save_level = 6 # 1..9; default is 6 23 | zlib_save = gz # or bz2, xz or lz4 24 | 25 | # FTS Plugin 26 | #fts_autoindex = yes 27 | # Squat Full Text Search Indexing 28 | #fts = squat 29 | #fts_squat = partial=4 full=10 30 | # Lucene Full Text Search Indexing 31 | #fts = lucene 32 | # Lucene-specific settings, good ones are: 33 | #fts_lucene = whitespace_chars=@. 34 | 35 | # Pigeonhole IMAPSieve Plugins 36 | # (!) 37 | # 38 | # From elsewhere to Spam folder 39 | imapsieve_mailbox1_name = Spam 40 | imapsieve_mailbox1_causes = COPY FLAG 41 | imapsieve_mailbox1_before = file:/var/dovecot/imapsieve/before/report-spam.sieve 42 | # 43 | # From Spam folder to elsewhere 44 | imapsieve_mailbox2_name = * 45 | imapsieve_mailbox2_from = Spam 46 | imapsieve_mailbox2_causes = COPY 47 | imapsieve_mailbox2_before = file:/var/dovecot/imapsieve/before/report-ham.sieve 48 | } 49 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/90-quota.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Quota configuration. 3 | ## 4 | 5 | # Note that you also have to enable quota plugin in mail_plugins setting. 6 | # 7 | 8 | ## 9 | ## Quota limits 10 | ## 11 | 12 | # Quota limits are set using "quota_rule" parameters. To get per-user quota 13 | # limits, you can set/override them by returning "quota_rule" extra field 14 | # from userdb. It's also possible to give mailbox-specific limits, for example 15 | # to give additional 100 MB when saving to Trash: 16 | 17 | plugin { 18 | quota_rule = *:storage=15G 19 | # Use Trash to go under quota 20 | quota_rule2 = Trash:storage=+100M 21 | #quota_rule3 = Spam:ignore 22 | 23 | # LDA/LMTP allows saving the last mail to bring user from under quota to 24 | # over quota, if the quota doesn't grow too high. Default is to allow as 25 | # long as quota will stay under 10% above the limit. Also allowed e.g. 10M. 26 | #quota_grace = 10%% 27 | 28 | # Quota plugin can also limit the maximum accepted mail size. 29 | # (!) match "max-message-size" from smtpd.conf 30 | quota_max_mail_size = 35M # (default: 100M) 31 | } 32 | 33 | ## 34 | ## Quota warnings 35 | ## 36 | 37 | # You can execute a given command when user exceeds a specified quota limit. 38 | # Each quota root has separate limits. Only the command for the first 39 | # exceeded limit is executed, so put the highest limit first. 40 | # The commands are executed via script service by connecting to the named 41 | # UNIX socket (quota-warning below). 42 | # Note that % needs to be escaped as %%, otherwise "% " expands to empty. 43 | 44 | plugin { 45 | quota_warning = storage=95%% quota-warning 95 %u 46 | quota_warning2 = storage=80%% quota-warning 80 %u 47 | quota_warning3 = -storage=100%% quota-warning below %u # user is no longer over quota 48 | } 49 | 50 | # Example quota-warning service. The unix listener's permissions should be 51 | # set in a way that mail processes can connect to it. Below example assumes 52 | # that mail processes run as vmail user. If you use mode=0666, all system users 53 | # can generate quota warnings to anyone. 54 | service quota-warning { 55 | executable = script /usr/local/bin/quota-warning.sh 56 | user = vmail 57 | unix_listener quota-warning { 58 | user = vmail 59 | group = vmail 60 | mode = 0660 61 | } 62 | } 63 | 64 | ## 65 | ## Quota backends 66 | ## 67 | 68 | # Multiple backends are supported: 69 | # dirsize: Find and sum all the files found from mail directory. 70 | # Extremely SLOW with Maildir. It'll eat your CPU and disk I/O. 71 | # dict: Keep quota stored in dictionary (eg. SQL) 72 | # maildir: Maildir++ quota 73 | # fs: Read-only support for filesystem quota 74 | 75 | plugin { 76 | #quota = dirsize:User quota 77 | quota = maildir:User quota 78 | #quota = dict:User quota::proxy::quota 79 | #quota = fs:User quota 80 | } 81 | 82 | # Multiple quota roots are also possible, for example this gives each user 83 | # their own 100MB quota and one shared 1GB quota within the domain: 84 | plugin { 85 | #quota = dict:user::proxy::quota 86 | #quota2 = dict:domain:%d:proxy::quota_domain 87 | #quota_rule = *:storage=102400 88 | #quota2_rule = *:storage=1048576 89 | } 90 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/90-replication.conf.optional: -------------------------------------------------------------------------------- 1 | # https://wiki.dovecot.org/Replication 2 | 3 | # Replicator process should be started at startup, so it can start replicating users immediately 4 | service replicator { 5 | process_min_avail = 1 6 | # Enable doveadm replicator commands 7 | unix_listener replicator-doveadm { 8 | user = vmail 9 | group = vmail 10 | mode = 0660 11 | } 12 | } 13 | 14 | # Configure how and where to replicate 15 | dsync_remote_cmd = ssh -i/home/dsync/.ssh/id_rsa -l%{login} %{host} /usr/local/bin/doveadm dsync-server -u%u 16 | plugin { 17 | mail_replica = remote:dsync@hermes.example.com 18 | 19 | # When saving a new mail via IMAP or delivering a mail via LDA/LMTP, 20 | # wait for the mail to be synced to the remote site. If it doesn't finish 21 | # in 2 seconds, return success anyway. 22 | #replication_sync_timeout = 2s 23 | } 24 | 25 | # The mail processes need to have access to the replication-notify fifo and socket 26 | service aggregator { 27 | fifo_listener replication-notify-fifo { 28 | user = vmail 29 | group = vmail 30 | mode = 0660 31 | } 32 | unix_listener replication-notify { 33 | user = vmail 34 | group = vmail 35 | mode = 0660 36 | } 37 | } 38 | 39 | # The mail process statistics tracking needs access to the stats-writer socket 40 | service stats { 41 | unix_listener stats-writer { 42 | user = vmail 43 | group = vmail 44 | mode = 0660 45 | } 46 | } 47 | 48 | # How many dsyncs can be run in parallel 49 | replication_max_conns = 10 50 | 51 | # Parameters replicator uses for the doveadm sync command 52 | replication_dsync_parameters = -d -n inbox -l 30 -U # default: -d -N -l 30 -U 53 | 54 | # Periodic "full sync" 55 | replication_full_sync_interval = 1h 56 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/90-sieve-extprograms.conf: -------------------------------------------------------------------------------- 1 | # Sieve Extprograms plugin configuration 2 | 3 | # Don't forget to add the sieve_extprograms plugin to the sieve_plugins setting. 4 | # Also enable the extensions you need (one or more of vnd.dovecot.pipe, 5 | # vnd.dovecot.filter and vnd.dovecot.execute) by adding these to the 6 | # sieve_extensions or sieve_global_extensions settings. Restricting these 7 | # extensions to a global context using sieve_global_extensions is recommended. 8 | 9 | plugin { 10 | 11 | # The directory where the program sockets are located for the 12 | # vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension 13 | # respectively. The name of each unix socket contained in that directory 14 | # directly maps to a program-name referenced from the Sieve script. 15 | sieve_pipe_socket_dir = sieve-pipe 16 | #sieve_filter_socket_dir = sieve-filter 17 | #sieve_execute_socket_dir = sieve-execute 18 | 19 | # The directory where the scripts are located for direct execution by the 20 | # vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension 21 | # respectively. The name of each script contained in that directory 22 | # directly maps to a program-name referenced from the Sieve script. 23 | #sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe 24 | #sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter 25 | #sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute 26 | } 27 | 28 | # An example program service called 'do-something' to pipe messages to 29 | #service do-something { 30 | # Define the executed script as parameter to the sieve service 31 | #executable = script /usr/lib/dovecot/sieve-pipe/do-something.sh 32 | 33 | # Use some unprivileged user for executing the program 34 | #user = dovenull 35 | 36 | # The unix socket located in the sieve_pipe_socket_dir (as defined in the 37 | # plugin {} section above) 38 | #unix_listener sieve-pipe/do-something { 39 | # LDA/LMTP must have access 40 | # user = vmail 41 | # mode = 0600 42 | #} 43 | #} 44 | 45 | # https://wiki2.dovecot.org/Pigeonhole/Sieve/Plugins/Pipe 46 | 47 | service learn_ham { 48 | executable = script /usr/local/bin/learn_ham.sh 49 | user = vmail 50 | unix_listener sieve-pipe/learn_ham { 51 | user = vmail 52 | mode = 0600 53 | } 54 | } 55 | 56 | service learn_spam { 57 | executable = script /usr/local/bin/learn_spam.sh 58 | user = vmail 59 | unix_listener sieve-pipe/learn_spam { 60 | user = vmail 61 | mode = 0600 62 | } 63 | } 64 | 65 | service dovecot-lda { 66 | executable = script /usr/local/bin/dovecot-lda.sh 67 | user = vmail 68 | unix_listener sieve-pipe/dovecot-lda { 69 | user = vmail 70 | mode = 0600 71 | } 72 | } 73 | 74 | service wks-server { 75 | executable = script /usr/local/bin/wks-server.sh 76 | user = vmail 77 | unix_listener sieve-pipe/wks-server { 78 | user = vmail 79 | mode = 0600 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/etc/dovecot/conf.d/90-sieve.conf: -------------------------------------------------------------------------------- 1 | ## 2 | ## Settings for the Sieve interpreter 3 | ## 4 | 5 | # Do not forget to enable the Sieve plugin in 15-lda.conf and 20-lmtp.conf 6 | # by adding it to the respective mail_plugins= settings. 7 | 8 | # The Sieve interpreter can retrieve Sieve scripts from several types of 9 | # locations. The default `file' location type is a local filesystem path 10 | # pointing to a Sieve script file or a directory containing multiple Sieve 11 | # script files. More complex setups can use other location types such as 12 | # `ldap' or `dict' to fetch Sieve scripts from remote databases. 13 | # 14 | # All settings that specify the location of one ore more Sieve scripts accept 15 | # the following syntax: 16 | # 17 | # location = [:]path[;