aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCullum Smith <cullum@sacredheartsc.com>2024-10-04 21:59:59 -0400
committerCullum Smith <cullum@sacredheartsc.com>2024-10-04 21:59:59 -0400
commit1e088983f6a80b6fd47543d0b4989e9ddb3234d5 (patch)
tree16af4205d84c9194257887e5e54653f79e96f987
parenta1bddcb1de1053994fb445267ca5d1ffaecb0fb5 (diff)
downloadinfrastructure-1e088983f6a80b6fd47543d0b4989e9ddb3234d5.tar.gz
add imap stuff
-rw-r--r--files/etc/cron.d/acme.common2
-rw-r--r--files/etc/pf.conf.freebsd6
-rw-r--r--files/usr/local/etc/dovecot/conf.d/10-auth.conf.imap_server7
-rw-r--r--files/usr/local/etc/dovecot/conf.d/10-mail.conf.imap_server23
-rw-r--r--files/usr/local/etc/dovecot/conf.d/10-master.conf.imap_server32
-rw-r--r--files/usr/local/etc/dovecot/conf.d/10-ssl.conf.imap_server8
-rw-r--r--files/usr/local/etc/dovecot/conf.d/15-lda.conf.imap_server8
-rw-r--r--files/usr/local/etc/dovecot/conf.d/15-mailboxes.conf.imap_server31
-rw-r--r--files/usr/local/etc/dovecot/conf.d/20-imap.conf.imap_server3
-rw-r--r--files/usr/local/etc/dovecot/conf.d/20-lmtp.conf.imap_server3
-rw-r--r--files/usr/local/etc/dovecot/conf.d/20-managesieve.conf.imap_server11
-rw-r--r--files/usr/local/etc/dovecot/conf.d/90-fts.conf.imap_server6
-rw-r--r--files/usr/local/etc/dovecot/conf.d/90-quota.conf.imap_server32
-rw-r--r--files/usr/local/etc/dovecot/conf.d/90-sieve-extprograms.conf.imap_server3
-rw-r--r--files/usr/local/etc/dovecot/conf.d/90-sieve.conf.imap_server28
-rw-r--r--files/usr/local/etc/dovecot/conf.d/auth-ldap.conf.ext.imap_server8
-rw-r--r--files/usr/local/etc/dovecot/dovecot-ldap-passdb.conf.ext.imap_server11
-rw-r--r--files/usr/local/etc/dovecot/dovecot-ldap-userdb.conf.ext.imap_server17
-rw-r--r--files/usr/local/etc/dovecot/dovecot.conf.imap_server5
-rw-r--r--files/usr/local/etc/dovecot/report-ham.sieve.imap_server15
-rw-r--r--files/usr/local/etc/dovecot/report-spam.sieve.imap_server7
-rw-r--r--files/usr/local/etc/dovecot/sieve-before.d/10-rspamd.sieve.imap_server5
-rw-r--r--files/usr/local/etc/nginx/nginx.conf.common2
-rw-r--r--files/usr/local/etc/poudriere.d/make.conf.pkg_repository1
-rw-r--r--files/usr/local/etc/poudriere.d/pkglist.pkg_repository4
-rw-r--r--files/usr/local/etc/rc.d/solr.imap_server76
-rw-r--r--files/usr/local/etc/rc.d/tika.imap_server55
-rw-r--r--files/usr/local/etc/solr/log4j2.xml.imap_server17
-rw-r--r--files/usr/local/etc/solr/solrconfig.xml.imap_server280
-rw-r--r--files/usr/local/etc/sudoers.d/acme.smtp_server1
-rw-r--r--files/usr/local/etc/tika/config.xml.imap_server21
-rw-r--r--files/usr/local/etc/tika/log4j2.xml.imap_server17
-rw-r--r--files/usr/local/libexec/dovecot/quota-warning.sh.imap_server20
-rw-r--r--files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server7
-rw-r--r--files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server7
-rw-r--r--files/var/db/solr/dovecot/conf/schema.xml.imap_server48
-rw-r--r--files/var/db/solr/dovecot/conf/solrconfig.xml.imap_server91
-rw-r--r--files/var/db/solr/solr.xml.imap_server76
-rw-r--r--scripts/hostclass/imap_server/10-solr78
-rw-r--r--scripts/hostclass/imap_server/20-tika38
-rw-r--r--scripts/hostclass/imap_server/30-dovecot108
-rw-r--r--scripts/hostclass/smtp_server/20-postfix6
-rw-r--r--scripts/os/freebsd/60-acme75
-rw-r--r--vars/common2
-rw-r--r--vars/hostclass/imap_server3
-rw-r--r--vars/hostclass/smtp_server2
-rw-r--r--vars/hostname/imap13
-rw-r--r--vars/os/freebsd5
48 files changed, 1297 insertions, 17 deletions
diff --git a/files/etc/cron.d/acme.common b/files/etc/cron.d/acme.common
new file mode 100644
index 0000000..05bf064
--- /dev/null
+++ b/files/etc/cron.d/acme.common
@@ -0,0 +1,2 @@
+MAILTO=root
+00 15 * * * ${acme_user} lockf -t 0 /tmp/acme-cron.lock acme.sh --cron --home ${acme_home} --syslog 6 > /dev/null
diff --git a/files/etc/pf.conf.freebsd b/files/etc/pf.conf.freebsd
index e01f49d..881fcea 100644
--- a/files/etc/pf.conf.freebsd
+++ b/files/etc/pf.conf.freebsd
@@ -5,8 +5,12 @@ $(if [ -n "${pf_egress_interfaces:-}" ]; then
fi)
allowed_tcp_ports = "{ $(join ', ' ${allowed_tcp_ports:-}) }"
allowed_udp_ports = "{ $(join ', ' ${allowed_udp_ports:-}) }"
+
+$([ "${acme_standalone:-}" = true ] && cat <<EOF
acme_standalone_port = ${acme_standalone_port}
-acme_standalone_user = ${acme_uid}
+acme_standalone_user = $(id -u "$acme_user")
+EOF
+)
nfscbd_port = ${nfscbd_port}
set block-policy return
diff --git a/files/usr/local/etc/dovecot/conf.d/10-auth.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/10-auth.conf.imap_server
new file mode 100644
index 0000000..7a908e6
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/10-auth.conf.imap_server
@@ -0,0 +1,7 @@
+auth_default_realm = ${realm}
+auth_gssapi_hostname = "\$ALL"
+auth_username_format = %Ln
+auth_mechanisms = gssapi plain login
+auth_cache_size = 10M
+
+!include auth-ldap.conf.ext
diff --git a/files/usr/local/etc/dovecot/conf.d/10-mail.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/10-mail.conf.imap_server
new file mode 100644
index 0000000..0fa15ea
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/10-mail.conf.imap_server
@@ -0,0 +1,23 @@
+mail_location = mdbox:~/mdbox
+
+namespace inbox {
+ type = private
+ separator = /
+ inbox = yes
+ subscriptions = yes
+}
+
+mail_plugins = \$mail_plugins quota virtual fts fts_solr
+
+mail_privileged_group = ${dovecot_vmail_user}
+
+first_valid_uid = ${dovecot_vmail_uid}
+last_valid_uid = ${dovecot_vmail_uid}
+
+first_valid_gid = ${dovecot_vmail_uid}
+last_valid_gid = ${dovecot_vmail_uid}
+
+# recommended configuration for quota:count
+protocol !indexer-worker {
+ mail_vsize_bg_after_count = 100
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/10-master.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/10-master.conf.imap_server
new file mode 100644
index 0000000..1445cb6
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/10-master.conf.imap_server
@@ -0,0 +1,32 @@
+service imap-login {
+ inet_listener imap {
+ port = 0
+ }
+
+ inet_listener imaps {
+ port = 993
+ ssl = yes
+ }
+}
+
+service lmtp {
+ user = ${dovecot_vmail_user}
+ inet_listener lmtp {
+ port = ${lmtp_port}
+ ssl = yes
+ }
+}
+
+service auth-worker {
+ user = \$default_internal_user
+}
+
+# Allow the vmail user to write to stats. This isn't strictly necessary, but
+# prevents dovecot-lda from spamming the mail log with errors.
+service stats {
+ unix_listener stats-writer {
+ user = dovecot
+ group = ${dovecot_vmail_user}
+ mode = 0660
+ }
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/10-ssl.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/10-ssl.conf.imap_server
new file mode 100644
index 0000000..9f90a47
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/10-ssl.conf.imap_server
@@ -0,0 +1,8 @@
+ssl = required
+
+ssl_cert = <${dovecot_tls_cert}
+ssl_key = <${dovecot_tls_key}
+
+ssl_min_protocol = TLSv1.2
+ssl_cipher_list = ${dovecot_cipherlist}
+ssl_prefer_server_ciphers = no
diff --git a/files/usr/local/etc/dovecot/conf.d/15-lda.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/15-lda.conf.imap_server
new file mode 100644
index 0000000..557594b
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/15-lda.conf.imap_server
@@ -0,0 +1,8 @@
+recipient_delimiter = ${dovecot_recipient_delimiter}
+lda_original_recipient_header = X-Original-To
+
+lda_mailbox_autocreate = yes
+
+protocol lda {
+ mail_plugins = \$mail_plugins sieve
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/15-mailboxes.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/15-mailboxes.conf.imap_server
new file mode 100644
index 0000000..540947c
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/15-mailboxes.conf.imap_server
@@ -0,0 +1,31 @@
+namespace inbox {
+
+ mailbox INBOX {
+ auto = subscribe
+ }
+
+ mailbox Drafts {
+ auto = subscribe
+ special_use = \Drafts
+ }
+
+ mailbox Junk {
+ auto = subscribe
+ special_use = \Junk
+ }
+
+ mailbox Trash {
+ auto = subscribe
+ special_use = \Trash
+ }
+
+ mailbox Sent {
+ auto = subscribe
+ special_use = \Sent
+ }
+
+ mailbox Archive {
+ auto = subscribe
+ special_use = \Archive
+ }
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/20-imap.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/20-imap.conf.imap_server
new file mode 100644
index 0000000..ae67bae
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/20-imap.conf.imap_server
@@ -0,0 +1,3 @@
+protocol imap {
+ mail_plugins = $mail_plugins imap_quota imap_sieve
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/20-lmtp.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/20-lmtp.conf.imap_server
new file mode 100644
index 0000000..2619ce5
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/20-lmtp.conf.imap_server
@@ -0,0 +1,3 @@
+protocol lmtp {
+ mail_plugins = $mail_plugins sieve
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/20-managesieve.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/20-managesieve.conf.imap_server
new file mode 100644
index 0000000..f4adea9
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/20-managesieve.conf.imap_server
@@ -0,0 +1,11 @@
+protocols = $protocols sieve
+
+service managesieve-login {
+ inet_listener sieve {
+ port = 4190
+ }
+
+ inet_listener sieve_deprecated {
+ port = 0
+ }
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/90-fts.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/90-fts.conf.imap_server
new file mode 100644
index 0000000..fbe7e0f
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/90-fts.conf.imap_server
@@ -0,0 +1,6 @@
+plugin {
+ fts_autoindex = yes
+ fts = solr
+ fts_solr = url=http://127.0.0.1:${solr_port}/solr/dovecot/
+ fts_tika = http://127.0.0.1:${tika_port}/tika/
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/90-quota.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/90-quota.conf.imap_server
new file mode 100644
index 0000000..7bffe9f
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/90-quota.conf.imap_server
@@ -0,0 +1,32 @@
+plugin {
+ quota = count:User quota
+ quota_vsizes = yes
+ quota_rule = *:storage=${dovecot_default_quota}
+ quota_grace = ${dovecot_quota_grace_percent}%%
+
+ quota_status_success = DUNNO
+ quota_status_nouser = DUNNO
+ quota_status_overquota = "552 5.2.2 Mailbox is full"
+
+ quota_warning = storage=95%% quota-warning 95 %u ${dovecot_quota_mail_from}
+ quota_warning2 = storage=90%% quota-warning 90 %u ${dovecot_quota_mail_from}
+ quota_warning3 = storage=80%% quota-warning 80 %u ${dovecot_quota_mail_from}
+}
+
+service quota-warning {
+ executable = script ${dovecot_script_dir}/quota-warning.sh
+ user = ${dovecot_vmail_user}
+ unix_listener quota-warning {
+ user = dovecot
+ group = ${dovecot_vmail_user}
+ mode = 0660
+ }
+}
+
+service quota-status {
+ executable = quota-status -p postfix
+ inet_listener {
+ port = ${quota_status_port}
+ }
+ client_limit = 5
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/90-sieve-extprograms.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/90-sieve-extprograms.conf.imap_server
new file mode 100644
index 0000000..06250e9
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/90-sieve-extprograms.conf.imap_server
@@ -0,0 +1,3 @@
+plugin {
+ sieve_pipe_bin_dir = ${dovecot_sieve_pipe_bin_dir}
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/90-sieve.conf.imap_server b/files/usr/local/etc/dovecot/conf.d/90-sieve.conf.imap_server
new file mode 100644
index 0000000..cd67671
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/90-sieve.conf.imap_server
@@ -0,0 +1,28 @@
+plugin {
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+
+ sieve_before = ${dovecot_sieve_before_dir}
+
+ sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute
+
+ sieve_plugins = sieve_extprograms sieve_imapsieve
+
+ sieve_quota_max_scripts = 10
+ sieve_quota_max_storage = 2M
+
+ # The default value for this is "sender", but that will totally break SPF
+ sieve_redirect_envelope_from = orig_recipient
+
+ # From elsewhere to Junk folder
+ imapsieve_mailbox1_name = Junk
+ imapsieve_mailbox1_causes = COPY
+ imapsieve_mailbox1_before = file:${dovecot_conf_dir}/report-spam.sieve
+
+ # From Junk folder to elsewhere
+ imapsieve_mailbox2_name = *
+ imapsieve_mailbox2_from = Junk
+ imapsieve_mailbox2_causes = COPY
+ imapsieve_mailbox2_before = file:${dovecot_conf_dir}/report-ham.sieve
+
+ sieve_global_extensions = +vnd.dovecot.pipe
+}
diff --git a/files/usr/local/etc/dovecot/conf.d/auth-ldap.conf.ext.imap_server b/files/usr/local/etc/dovecot/conf.d/auth-ldap.conf.ext.imap_server
new file mode 100644
index 0000000..9237f1f
--- /dev/null
+++ b/files/usr/local/etc/dovecot/conf.d/auth-ldap.conf.ext.imap_server
@@ -0,0 +1,8 @@
+passdb {
+ driver = ldap
+ args = ${dovecot_conf_dir}/dovecot-ldap-passdb.conf.ext
+}
+userdb {
+ driver = ldap
+ args = ${dovecot_conf_dir}/dovecot-ldap-userdb.conf.ext
+}
diff --git a/files/usr/local/etc/dovecot/dovecot-ldap-passdb.conf.ext.imap_server b/files/usr/local/etc/dovecot/dovecot-ldap-passdb.conf.ext.imap_server
new file mode 100644
index 0000000..5158954
--- /dev/null
+++ b/files/usr/local/etc/dovecot/dovecot-ldap-passdb.conf.ext.imap_server
@@ -0,0 +1,11 @@
+uris = ${ldap_uri}
+
+sasl_bind = yes
+sasl_mech = gssapi
+sasl_realm = ${realm}
+
+base = ${users_basedn}
+
+auth_bind = yes
+pass_attrs = uid=user
+user_filter = (uid=%u)
diff --git a/files/usr/local/etc/dovecot/dovecot-ldap-userdb.conf.ext.imap_server b/files/usr/local/etc/dovecot/dovecot-ldap-userdb.conf.ext.imap_server
new file mode 100644
index 0000000..fc939a6
--- /dev/null
+++ b/files/usr/local/etc/dovecot/dovecot-ldap-userdb.conf.ext.imap_server
@@ -0,0 +1,17 @@
+uris = ${ldap_uri}
+
+sasl_bind = yes
+sasl_mech = gssapi
+sasl_realm = ${realm}
+
+base = ${users_basedn}
+user_filter = (|(mailAddress=%u)(uid=%u))
+user_attrs = \
+ =user=%{ldap:uid}, \
+ =uid=${dovecot_vmail_uid}, \
+ =gid=${dovecot_vmail_uid}, \
+ =home=${dovecot_vmail_dir}/%{ldap:uid} \
+ mailQuota=quota_rule=\*:storage=%{ldap:mailQuota}
+
+iterate_attrs = uid=user
+iterate_filter = (mailAddress=*)
diff --git a/files/usr/local/etc/dovecot/dovecot.conf.imap_server b/files/usr/local/etc/dovecot/dovecot.conf.imap_server
new file mode 100644
index 0000000..2045e76
--- /dev/null
+++ b/files/usr/local/etc/dovecot/dovecot.conf.imap_server
@@ -0,0 +1,5 @@
+protocols = imap lmtp
+
+import_environment = \$import_environment KRB5_KTNAME=${dovecot_keytab} KRB5_CLIENT_KTNAME=${dovecot_keytab}
+
+!include conf.d/*.conf
diff --git a/files/usr/local/etc/dovecot/report-ham.sieve.imap_server b/files/usr/local/etc/dovecot/report-ham.sieve.imap_server
new file mode 100644
index 0000000..578e7b2
--- /dev/null
+++ b/files/usr/local/etc/dovecot/report-ham.sieve.imap_server
@@ -0,0 +1,15 @@
+require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
+
+if environment :matches "imap.mailbox" "*" {
+ set "mailbox" "${1}";
+}
+
+if string "${mailbox}" "Trash" {
+ stop;
+}
+
+if environment :matches "imap.email" "*" {
+ set "email" "${1}";
+}
+
+pipe :copy "report-ham.sh" [ "${email}" ];
diff --git a/files/usr/local/etc/dovecot/report-spam.sieve.imap_server b/files/usr/local/etc/dovecot/report-spam.sieve.imap_server
new file mode 100644
index 0000000..d34c71b
--- /dev/null
+++ b/files/usr/local/etc/dovecot/report-spam.sieve.imap_server
@@ -0,0 +1,7 @@
+require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
+
+if environment :matches "imap.email" "*" {
+ set "email" "${1}";
+}
+
+pipe :copy "report-spam.sh" [ "${email}" ];
diff --git a/files/usr/local/etc/dovecot/sieve-before.d/10-rspamd.sieve.imap_server b/files/usr/local/etc/dovecot/sieve-before.d/10-rspamd.sieve.imap_server
new file mode 100644
index 0000000..7931a71
--- /dev/null
+++ b/files/usr/local/etc/dovecot/sieve-before.d/10-rspamd.sieve.imap_server
@@ -0,0 +1,5 @@
+require ["fileinto"];
+
+if header :is "X-Spam" "Yes" {
+ fileinto "Junk";
+}
diff --git a/files/usr/local/etc/nginx/nginx.conf.common b/files/usr/local/etc/nginx/nginx.conf.common
index 9ab993c..1da7c3c 100644
--- a/files/usr/local/etc/nginx/nginx.conf.common
+++ b/files/usr/local/etc/nginx/nginx.conf.common
@@ -47,7 +47,7 @@ $([ "${nginx_gssapi:-}" = true ] && cat <<EOF
EOF
)
-$([ "${nginx_acme:-}" = true ] && cat <<EOF
+$([ "${acme:-}" = true ] && [ "${acme_standalone:-}" != true ] && cat <<EOF
server {
listen 0.0.0.0:80 default_server;
listen [::]:80 default_server;
diff --git a/files/usr/local/etc/poudriere.d/make.conf.pkg_repository b/files/usr/local/etc/poudriere.d/make.conf.pkg_repository
index 6dbbafc..fd35928 100644
--- a/files/usr/local/etc/poudriere.d/make.conf.pkg_repository
+++ b/files/usr/local/etc/poudriere.d/make.conf.pkg_repository
@@ -74,7 +74,6 @@ sysutils_htop_SET=LSOF
sysutils_k3b_UNSET=EMOVIX VCDIMAGER
sysutils_rsyslog8_SET=GSSAPI RELP OPENSSL
sysutils_rsyslog8_UNSET=GCRYPT
-www_apache${apache_version}_SET=AUTHNZ_LDAP LDAP SUEXEC SUEXEC_SYSLOG
www_chromium_SET=WIDEVINE
www_firefox_UNSET=PROFILE JACK
www_nginx_SET=HTTPV3 HTTPV3_QTLS HTTP_AUTH_KRB5 HTTP_AUTH_LDAP
diff --git a/files/usr/local/etc/poudriere.d/pkglist.pkg_repository b/files/usr/local/etc/poudriere.d/pkglist.pkg_repository
index 5e95f8c..d24ce06 100644
--- a/files/usr/local/etc/poudriere.d/pkglist.pkg_repository
+++ b/files/usr/local/etc/poudriere.d/pkglist.pkg_repository
@@ -14,6 +14,7 @@ dns/unbound
editors/vim@console
editors/vim@tiny
ftp/php${php_version}-curl
+java/openjdk21
lang/python
lang/php${php_version}
mail/dovecot
@@ -50,9 +51,6 @@ sysutils/stow
sysutils/tmux
sysutils/tree
textproc/php${php_version}-xml
-www/apache${apache_version}
-www/mod_auth_gssapi
-www/mod_php${php_version}
www/nginx
www/php${php_version}-opcache
www/php${php_version}-session
diff --git a/files/usr/local/etc/rc.d/solr.imap_server b/files/usr/local/etc/rc.d/solr.imap_server
new file mode 100644
index 0000000..70cc324
--- /dev/null
+++ b/files/usr/local/etc/rc.d/solr.imap_server
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+# PROVIDE: solr
+# REQUIRE: LOGIN
+# BEFORE: dovecot
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name=solr
+rcvar=solr_enable
+
+load_rc_config "$name"
+
+: ${solr_enable:='NO'}
+: ${solr_host:='127.0.0.1'}
+: ${solr_port:='8983'}
+: ${solr_syslog_priority:='info'}
+: ${solr_syslog_facility:='daemon'}
+: ${solr_heap_size:='512m'}
+: ${solr_softcommit_ms:='60000'}
+
+solr_java_home=/usr/local/openjdk21
+solr_syslog_tag=solr
+solr_data_dir=/var/db/solr
+solr_install_dir=/usr/local/solr
+solr_conf_dir=/usr/local/etc/solr
+solr_config_file="${solr_conf_dir}/solrconfig.xml"
+solr_log4j_config_file="${solr_conf_dir}/log4j2.xml"
+solr_jar="${solr_install_dir}/server/start.jar"
+
+solr_user=solr
+solr_chdir="${solr_install_dir}/server"
+
+pidfile=/var/run/solr/solr.pid
+command=/usr/sbin/daemon
+
+command_args="-f \
+-s ${solr_syslog_priority} \
+-l ${solr_syslog_facility} \
+-T ${solr_syslog_tag} \
+-p ${pidfile} \
+-t solr \
+${solr_java_home}/bin/java \
+-server \
+-Xmx${solr_heap_size} \
+-XX:+UseG1GC \
+-XX:+PerfDisableSharedMem \
+-XX:+ParallelRefProcEnabled \
+-XX:MaxGCPauseMillis=250 \
+-XX:+AlwaysPreTouch \
+-XX:+ExplicitGCInvokesConcurrent \
+-XX:+CrashOnOutOfMemoryError \
+-Djava.awt.headless=true \
+-Dlog4j.configurationFile=${solr_log4j_config_file} \
+-Djetty.host=${solr_host} \
+-Djetty.port=${solr_port} \
+-Djetty.home=${solr_install_dir}/server \
+-Dsolr.autoSoftCommit.maxTime=${solr_softcommit_ms} \
+-Dsolr.solr.home=${solr_data_dir} \
+-Dsolr.data.home= \
+-Dsolr.install.dir=${solr_install_dir} \
+-Dsolr.default.confdir=${solr_conf_dir} \
+-jar ${solr_jar} \
+--module=http \
+--module=gzip"
+
+required_files="${solr_config_file} ${solr_log4j_config_file} ${solr_jar}"
+procname="${solr_java_home}/bin/java"
+start_precmd=solr_prestart
+
+solr_prestart(){
+ install -d -m 0755 -o ${solr_user} /var/run/solr
+}
+
+run_rc_command "$1"
diff --git a/files/usr/local/etc/rc.d/tika.imap_server b/files/usr/local/etc/rc.d/tika.imap_server
new file mode 100644
index 0000000..95f1c88
--- /dev/null
+++ b/files/usr/local/etc/rc.d/tika.imap_server
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# PROVIDE: tika
+# REQUIRE: LOGIN
+# BEFORE: dovecot
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name=tika
+rcvar=tika_enable
+
+load_rc_config "$name"
+
+: ${tika_enable:='NO'}
+: ${tika_host:='127.0.0.1'}
+: ${tika_port:='9998'}
+: ${tika_syslog_priority:='info'}
+: ${tika_syslog_facility:='daemon'}
+
+tika_user=tika
+tika_java_home=/usr/local/openjdk21
+tika_syslog_tag=tika
+tika_jar=/usr/local/tika/tika.jar
+tika_config_file=/usr/local/etc/tika/config.xml
+tika_log4j_config_file=/usr/local/etc/tika/log4j2.xml
+
+pidfile=/var/run/tika/tika.pid
+command=/usr/sbin/daemon
+
+command_args="-f \
+-s ${tika_syslog_priority} \
+-l ${tika_syslog_facility} \
+-T ${tika_syslog_tag} \
+-p ${pidfile} \
+-t tika \
+${tika_java_home}/bin/java \
+-server \
+-Xmx64m \
+-Djava.awt.headless=true \
+-Dlog4j.configurationFile=${tika_log4j_config_file} \
+-jar ${tika_jar} \
+-c ${tika_config_file} \
+-h ${tika_host} \
+-p ${tika_port}"
+
+required_files="${tika_config_file} ${tika_log4j_config_file} ${tika_jar}"
+procname="${tika_java_home}/bin/java"
+start_precmd=tika_prestart
+
+tika_prestart(){
+ install -d -m 0755 -o ${tika_user} /var/run/tika
+}
+
+run_rc_command "$1"
diff --git a/files/usr/local/etc/solr/log4j2.xml.imap_server b/files/usr/local/etc/solr/log4j2.xml.imap_server
new file mode 100644
index 0000000..cabde07
--- /dev/null
+++ b/files/usr/local/etc/solr/log4j2.xml.imap_server
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+ <Appenders>
+ <Console name="STDOUT" target="SYSTEM_OUT">
+ <PatternLayout>
+ <Pattern>
+ %maxLen{%-5p %c %m%notEmpty{ =>%ex{short}}}{10240}%n
+ </Pattern>
+ </PatternLayout>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="INFO">
+ <AppenderRef ref="STDOUT"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git a/files/usr/local/etc/solr/solrconfig.xml.imap_server b/files/usr/local/etc/solr/solrconfig.xml.imap_server
new file mode 100644
index 0000000..f7a9d7b
--- /dev/null
+++ b/files/usr/local/etc/solr/solrconfig.xml.imap_server
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<config>
+ <luceneMatchVersion>9.3.0</luceneMatchVersion>
+ <!-- the rest of this file is unchanged from the defaults -->
+ <dataDir>${solr.data.dir:}</dataDir>
+ <directoryFactory name="DirectoryFactory"
+ class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
+ <codecFactory class="solr.SchemaCodecFactory"/>
+ <indexConfig>
+ <lockType>${solr.lock.type:native}</lockType>
+ </indexConfig>
+ <jmx />
+ <updateHandler class="solr.DirectUpdateHandler2">
+ <updateLog>
+ <str name="dir">${solr.ulog.dir:}</str>
+ <int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int>
+ </updateLog>
+ <autoCommit>
+ <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
+ <openSearcher>false</openSearcher>
+ </autoCommit>
+ <autoSoftCommit>
+ <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
+ </autoSoftCommit>
+ </updateHandler>
+
+ <query>
+ <maxBooleanClauses>${solr.max.booleanClauses:1024}</maxBooleanClauses>
+ <filterCache size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+ <queryResultCache size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <documentCache size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <cache name="perSegFilter"
+ size="10"
+ initialSize="0"
+ autowarmCount="10"
+ regenerator="solr.NoOpRegenerator" />
+
+ <enableLazyFieldLoading>true</enableLazyFieldLoading>
+
+ <queryResultWindowSize>20</queryResultWindowSize>
+
+ <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
+
+ <listener event="newSearcher" class="solr.QuerySenderListener">
+ <arr name="queries">
+ </arr>
+ </listener>
+ <listener event="firstSearcher" class="solr.QuerySenderListener">
+ <arr name="queries">
+ </arr>
+ </listener>
+
+ <useColdSearcher>false</useColdSearcher>
+ </query>
+
+ <circuitBreakers enabled="true">
+ </circuitBreakers>
+
+
+ <requestDispatcher>
+ <httpCaching never304="true" />
+ </requestDispatcher>
+
+ <requestHandler name="/select" class="solr.SearchHandler">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <int name="rows">10</int>
+ <str name="df">hdr</str>
+ </lst>
+ </requestHandler>
+
+ <requestHandler name="/query" class="solr.SearchHandler">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <str name="wt">json</str>
+ <str name="indent">true</str>
+ </lst>
+ </requestHandler>
+
+ <initParams path="/update/**,/query,/select,/spell">
+ <lst name="defaults">
+ <str name="df">_text_</str>
+ </lst>
+ </initParams>
+
+ <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
+
+ <str name="queryAnalyzerFieldType">text_general</str>
+
+ <lst name="spellchecker">
+ <str name="name">default</str>
+ <str name="field">_text_</str>
+ <str name="classname">solr.DirectSolrSpellChecker</str>
+ <str name="distanceMeasure">internal</str>
+ <float name="accuracy">0.5</float>
+ <int name="maxEdits">2</int>
+ <int name="minPrefix">1</int>
+ <int name="maxInspections">5</int>
+ <int name="minQueryLength">4</int>
+ <float name="maxQueryFrequency">0.01</float>
+ </lst>
+ </searchComponent>
+
+ <requestHandler name="/spell" class="solr.SearchHandler" startup="lazy">
+ <lst name="defaults">
+ <str name="spellcheck.dictionary">default</str>
+ <str name="spellcheck">on</str>
+ <str name="spellcheck.extendedResults">true</str>
+ <str name="spellcheck.count">10</str>
+ <str name="spellcheck.alternativeTermCount">5</str>
+ <str name="spellcheck.maxResultsForSuggest">5</str>
+ <str name="spellcheck.collate">true</str>
+ <str name="spellcheck.collateExtendedResults">true</str>
+ <str name="spellcheck.maxCollationTries">10</str>
+ <str name="spellcheck.maxCollations">5</str>
+ </lst>
+ <arr name="last-components">
+ <str>spellcheck</str>
+ </arr>
+ </requestHandler>
+
+ <searchComponent name="terms" class="solr.TermsComponent"/>
+
+ <requestHandler name="/terms" class="solr.SearchHandler" startup="lazy">
+ <lst name="defaults">
+ <bool name="terms">true</bool>
+ <bool name="distrib">false</bool>
+ </lst>
+ <arr name="components">
+ <str>terms</str>
+ </arr>
+ </requestHandler>
+
+ <searchComponent class="solr.HighlightComponent" name="highlight">
+ <highlighting>
+ <fragmenter name="gap"
+ default="true"
+ class="solr.highlight.GapFragmenter">
+ <lst name="defaults">
+ <int name="hl.fragsize">100</int>
+ </lst>
+ </fragmenter>
+
+ <fragmenter name="regex"
+ class="solr.highlight.RegexFragmenter">
+ <lst name="defaults">
+ <int name="hl.fragsize">70</int>
+ <float name="hl.regex.slop">0.5</float>
+ <str name="hl.regex.pattern">[-\w ,/\n\&quot;&apos;]{20,200}</str>
+ </lst>
+ </fragmenter>
+
+ <formatter name="html"
+ default="true"
+ class="solr.highlight.HtmlFormatter">
+ <lst name="defaults">
+ <str name="hl.simple.pre"><![CDATA[<em>]]></str>
+ <str name="hl.simple.post"><![CDATA[</em>]]></str>
+ </lst>
+ </formatter>
+
+ <encoder name="html"
+ class="solr.highlight.HtmlEncoder" />
+
+ <fragListBuilder name="simple"
+ class="solr.highlight.SimpleFragListBuilder"/>
+
+ <fragListBuilder name="single"
+ class="solr.highlight.SingleFragListBuilder"/>
+
+ <fragListBuilder name="weighted"
+ default="true"
+ class="solr.highlight.WeightedFragListBuilder"/>
+
+ <fragmentsBuilder name="default"
+ default="true"
+ class="solr.highlight.ScoreOrderFragmentsBuilder">
+ </fragmentsBuilder>
+
+ <fragmentsBuilder name="colored"
+ class="solr.highlight.ScoreOrderFragmentsBuilder">
+ <lst name="defaults">
+ <str name="hl.tag.pre"><![CDATA[
+ <b style="background:yellow">,<b style="background:lawgreen">,
+ <b style="background:aquamarine">,<b style="background:magenta">,
+ <b style="background:palegreen">,<b style="background:coral">,
+ <b style="background:wheat">,<b style="background:khaki">,
+ <b style="background:lime">,<b style="background:deepskyblue">]]></str>
+ <str name="hl.tag.post"><![CDATA[</b>]]></str>
+ </lst>
+ </fragmentsBuilder>
+
+ <boundaryScanner name="default"
+ default="true"
+ class="solr.highlight.SimpleBoundaryScanner">
+ <lst name="defaults">
+ <str name="hl.bs.maxScan">10</str>
+ <str name="hl.bs.chars">.,!? &#9;&#10;&#13;</str>
+ </lst>
+ </boundaryScanner>
+
+ <boundaryScanner name="breakIterator"
+ class="solr.highlight.BreakIteratorBoundaryScanner">
+ <lst name="defaults">
+ <str name="hl.bs.type">WORD</str>
+ <str name="hl.bs.language">en</str>
+ <str name="hl.bs.country">US</str>
+ </lst>
+ </boundaryScanner>
+ </highlighting>
+ </searchComponent>
+
+ <updateProcessor class="solr.UUIDUpdateProcessorFactory" name="uuid"/>
+ <updateProcessor class="solr.RemoveBlankFieldUpdateProcessorFactory" name="remove-blank"/>
+ <updateProcessor class="solr.FieldNameMutatingUpdateProcessorFactory" name="field-name-mutating">
+ <str name="pattern">[^\w-\.]</str>
+ <str name="replacement">_</str>
+ </updateProcessor>
+ <updateProcessor class="solr.ParseBooleanFieldUpdateProcessorFactory" name="parse-boolean"/>
+ <updateProcessor class="solr.ParseLongFieldUpdateProcessorFactory" name="parse-long"/>
+ <updateProcessor class="solr.ParseDoubleFieldUpdateProcessorFactory" name="parse-double"/>
+ <updateProcessor class="solr.ParseDateFieldUpdateProcessorFactory" name="parse-date">
+ <arr name="format">
+ <str>yyyy-MM-dd['T'[HH:mm[:ss[.SSS]][z</str>
+ <str>yyyy-MM-dd['T'[HH:mm[:ss[,SSS]][z</str>
+ <str>yyyy-MM-dd HH:mm[:ss[.SSS]][z</str>
+ <str>yyyy-MM-dd HH:mm[:ss[,SSS]][z</str>
+ <str>[EEE, ]dd MMM yyyy HH:mm[:ss] z</str>
+ <str>EEEE, dd-MMM-yy HH:mm:ss z</str>
+ <str>EEE MMM ppd HH:mm:ss [z ]yyyy</str>
+ </arr>
+ </updateProcessor>
+ <updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields">
+ <lst name="typeMapping">
+ <str name="valueClass">java.lang.String</str>
+ <str name="fieldType">text_general</str>
+ <lst name="copyField">
+ <str name="dest">*_str</str>
+ <int name="maxChars">256</int>
+ </lst>
+ <bool name="default">true</bool>
+ </lst>
+ <lst name="typeMapping">
+ <str name="valueClass">java.lang.Boolean</str>
+ <str name="fieldType">booleans</str>
+ </lst>
+ <lst name="typeMapping">
+ <str name="valueClass">java.util.Date</str>
+ <str name="fieldType">pdates</str>
+ </lst>
+ <lst name="typeMapping">
+ <str name="valueClass">java.lang.Long</str>
+ <str name="valueClass">java.lang.Integer</str>
+ <str name="fieldType">plongs</str>
+ </lst>
+ <lst name="typeMapping">
+ <str name="valueClass">java.lang.Number</str>
+ <str name="fieldType">pdoubles</str>
+ </lst>
+ </updateProcessor>
+
+ <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}"
+ processor="uuid,remove-blank,field-name-mutating,parse-boolean,parse-long,parse-double,parse-date,add-schema-fields">
+ <processor class="solr.LogUpdateProcessorFactory"/>
+ <processor class="solr.DistributedUpdateProcessorFactory"/>
+ <processor class="solr.RunUpdateProcessorFactory"/>
+ </updateRequestProcessorChain>
+
+ <queryResponseWriter name="json" class="solr.JSONResponseWriter">
+ <str name="content-type">text/plain; charset=UTF-8</str>
+ </queryResponseWriter>
+</config>
diff --git a/files/usr/local/etc/sudoers.d/acme.smtp_server b/files/usr/local/etc/sudoers.d/acme.smtp_server
new file mode 100644
index 0000000..5180fdc
--- /dev/null
+++ b/files/usr/local/etc/sudoers.d/acme.smtp_server
@@ -0,0 +1 @@
+acme ALL=(root) NOPASSWD: /usr/sbin/service postfix reload
diff --git a/files/usr/local/etc/tika/config.xml.imap_server b/files/usr/local/etc/tika/config.xml.imap_server
new file mode 100644
index 0000000..22fe638
--- /dev/null
+++ b/files/usr/local/etc/tika/config.xml.imap_server
@@ -0,0 +1,21 @@
+<properties>
+ <server>
+ <params>
+ <javaPath>/usr/local/bin/java</javaPath>
+ <returnStackTrace>false</returnStackTrace>
+ <forkedJvmArgs>
+ <arg>-Xmx${tika_heap_size}</arg>
+ <arg>-XX:+UseG1GC</arg>
+ <arg>-XX:+PerfDisableSharedMem</arg>
+ <arg>-XX:+ParallelRefProcEnabled</arg>
+ <arg>-XX:MaxGCPauseMillis=250</arg>
+ <arg>-XX:+AlwaysPreTouch</arg>
+ <arg>-Dlog4j.configurationFile=${tika_conf_dir}/log4j2.xml</arg>
+ </forkedJvmArgs>
+ <endpoints>
+ <endpoint>tika</endpoint>
+ <endpoint>status</endpoint>
+ </endpoints>
+ </params>
+ </server>
+</properties>
diff --git a/files/usr/local/etc/tika/log4j2.xml.imap_server b/files/usr/local/etc/tika/log4j2.xml.imap_server
new file mode 100644
index 0000000..cabde07
--- /dev/null
+++ b/files/usr/local/etc/tika/log4j2.xml.imap_server
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+ <Appenders>
+ <Console name="STDOUT" target="SYSTEM_OUT">
+ <PatternLayout>
+ <Pattern>
+ %maxLen{%-5p %c %m%notEmpty{ =>%ex{short}}}{10240}%n
+ </Pattern>
+ </PatternLayout>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="INFO">
+ <AppenderRef ref="STDOUT"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git a/files/usr/local/libexec/dovecot/quota-warning.sh.imap_server b/files/usr/local/libexec/dovecot/quota-warning.sh.imap_server
new file mode 100644
index 0000000..96419f5
--- /dev/null
+++ b/files/usr/local/libexec/dovecot/quota-warning.sh.imap_server
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -eu -o pipefail
+
+PERCENT=$1
+USER=$2
+FROM=$3
+
+cat << EOF | /usr/libexec/dovecot/dovecot-lda -d "$USER" -o "plugin/quota=count:User quota:noenforcing"
+From: ${FROM}
+Subject: Mailbox quota warning
+
+This is an automatically generated message.
+
+Your mailbox is now ${PERCENT}% full.
+
+When your mailbox exceeds its quota, you will no longer receive new mail.
+
+Please delete some messages to free up space.
+EOF
diff --git a/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server b/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server
new file mode 100644
index 0000000..e09674a
--- /dev/null
+++ b/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+exec /usr/local/bin/rspamc \\
+ --connect="${rspamd_host}.${domain}" \\
+ --password="${rspamd_rw_password}" \\
+ --key="${rspamd_pubkey}" \\
+ learn_ham
diff --git a/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server b/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server
new file mode 100644
index 0000000..825113f
--- /dev/null
+++ b/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+exec /usr/local/bin/rspamc \\
+ --connect="${rspamd_host}.${domain}" \\
+ --password="${rspamd_rw_password}" \\
+ --key="${rspamd_pubkey}" \\
+ learn_spam
diff --git a/files/var/db/solr/dovecot/conf/schema.xml.imap_server b/files/var/db/solr/dovecot/conf/schema.xml.imap_server
new file mode 100644
index 0000000..601a290
--- /dev/null
+++ b/files/var/db/solr/dovecot/conf/schema.xml.imap_server
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<schema name="dovecot" version="2.0">
+ <fieldType name="string" class="solr.StrField" omitNorms="true" sortMissingLast="true"/>
+ <fieldType name="long" class="solr.LongPointField" positionIncrementGap="0"/>
+ <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
+
+ <fieldType name="text" class="solr.TextField" autoGeneratePhraseQueries="true" positionIncrementGap="100">
+ <analyzer type="index">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
+ <filter class="solr.WordDelimiterGraphFilterFactory" catenateNumbers="1" generateNumberParts="1" splitOnCaseChange="1" generateWordParts="1" splitOnNumerics="1" catenateAll="1" catenateWords="1"/>
+ <filter class="solr.FlattenGraphFilterFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+ <filter class="solr.PorterStemFilterFactory"/>
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.SynonymGraphFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt"/>
+ <filter class="solr.FlattenGraphFilterFactory"/>
+ <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
+ <filter class="solr.WordDelimiterGraphFilterFactory" catenateNumbers="1" generateNumberParts="1" splitOnCaseChange="1" generateWordParts="1" splitOnNumerics="1" catenateAll="1" catenateWords="1"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+ <filter class="solr.PorterStemFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <field name="id" type="string" indexed="true" required="true" stored="true"/>
+ <field name="uid" type="long" indexed="true" required="true" stored="true"/>
+ <field name="box" type="string" indexed="true" required="true" stored="true"/>
+ <field name="user" type="string" indexed="true" required="true" stored="true"/>
+
+ <field name="hdr" type="text" indexed="true" stored="false"/>
+ <field name="body" type="text" indexed="true" stored="false"/>
+
+ <field name="from" type="text" indexed="true" stored="false"/>
+ <field name="to" type="text" indexed="true" stored="false"/>
+ <field name="cc" type="text" indexed="true" stored="false"/>
+ <field name="bcc" type="text" indexed="true" stored="false"/>
+ <field name="subject" type="text" indexed="true" stored="false"/>
+
+ <!-- Used by Solr internally: -->
+ <field name="_version_" type="long" indexed="true" stored="true"/>
+
+ <uniqueKey>id</uniqueKey>
+</schema>
diff --git a/files/var/db/solr/dovecot/conf/solrconfig.xml.imap_server b/files/var/db/solr/dovecot/conf/solrconfig.xml.imap_server
new file mode 100644
index 0000000..918a755
--- /dev/null
+++ b/files/var/db/solr/dovecot/conf/solrconfig.xml.imap_server
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<config>
+ <luceneMatchVersion>9.3.0</luceneMatchVersion>
+
+ <lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
+ <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-\d.*\.jar" />
+
+ <lib dir="${solr.install.dir:../../../..}/contrib/clustering/lib/" regex=".*\.jar" />
+ <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-clustering-\d.*\.jar" />
+
+ <lib dir="${solr.install.dir:../../../..}/contrib/langid/lib/" regex=".*\.jar" />
+ <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-langid-\d.*\.jar" />
+
+ <lib dir="${solr.install.dir:../../../..}/contrib/velocity/lib" regex=".*\.jar" />
+ <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-velocity-\d.*\.jar" />
+
+ <dataDir>${solr.data.dir:}</dataDir>
+
+ <updateHandler class="solr.DirectUpdateHandler2">
+
+ <updateLog>
+ <str name="dir">${solr.ulog.dir:}</str>
+ <int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int>
+ </updateLog>
+
+ <autoCommit>
+ <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
+ <openSearcher>false</openSearcher>
+ </autoCommit>
+
+ <autoSoftCommit>
+ <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
+ </autoSoftCommit>
+
+ </updateHandler>
+
+ <query>
+ <filterCache class="solr.CaffeineCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <queryResultCache class="solr.CaffeineCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <documentCache class="solr.CaffeineCache"
+ size="512"
+ initialSize="512"
+ autowarmCount="0"/>
+
+ <cache name="perSegFilter"
+ class="solr.search.CaffeineCache"
+ size="10"
+ initialSize="0"
+ autowarmCount="10"
+ regenerator="solr.NoOpRegenerator" />
+
+ <enableLazyFieldLoading>true</enableLazyFieldLoading>
+
+ <queryResultWindowSize>20</queryResultWindowSize>
+
+ <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
+
+ <useColdSearcher>false</useColdSearcher>
+
+ </query>
+
+ <requestDispatcher>
+ <httpCaching never304="true" />
+ </requestDispatcher>
+
+ <requestHandler name="/select" class="solr.SearchHandler">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <int name="rows">10</int>
+ </lst>
+ </requestHandler>
+
+ <initParams path="/update/**,/select">
+ <lst name="defaults">
+ <str name="df">_text_</str>
+ </lst>
+ </initParams>
+
+ <queryResponseWriter name="xml"
+ default="true"
+ class="solr.XMLResponseWriter" />
+</config>
diff --git a/files/var/db/solr/solr.xml.imap_server b/files/var/db/solr/solr.xml.imap_server
new file mode 100644
index 0000000..1778390
--- /dev/null
+++ b/files/var/db/solr/solr.xml.imap_server
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ This is an example of a simple "solr.xml" file for configuring one or
+ more Solr Cores, as well as allowing Cores to be added, removed, and
+ reloaded via HTTP requests.
+
+ More information about options available in this configuration file,
+ and Solr Core administration can be found online:
+ https://solr.apache.org/guide/solr/latest/configuration-guide/configuring-solr-xml.html
+-->
+
+<solr>
+
+ <int name="maxBooleanClauses">${solr.max.booleanClauses:1024}</int>
+ <str name="sharedLib">${solr.sharedLib:}</str>
+ <str name="modules">${solr.modules:}</str>
+ <str name="allowPaths">${solr.allowPaths:}</str>
+ <str name="allowUrls">${solr.allowUrls:}</str>
+
+ <solrcloud>
+
+ <str name="host">${host:}</str>
+ <int name="hostPort">${solr.port.advertise:0}</int>
+ <str name="hostContext">${hostContext:solr}</str>
+
+ <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
+
+ <int name="zkClientTimeout">${zkClientTimeout:30000}</int>
+ <int name="distribUpdateSoTimeout">${distribUpdateSoTimeout:600000}</int>
+ <int name="distribUpdateConnTimeout">${distribUpdateConnTimeout:60000}</int>
+ <str name="zkCredentialsProvider">${zkCredentialsProvider:org.apache.solr.common.cloud.DefaultZkCredentialsProvider}</str>
+ <str name="zkACLProvider">${zkACLProvider:org.apache.solr.common.cloud.DefaultZkACLProvider}</str>
+ <str name="zkCredentialsInjector">${zkCredentialsInjector:org.apache.solr.common.cloud.DefaultZkCredentialsInjector}</str>
+ <bool name="distributedClusterStateUpdates">${distributedClusterStateUpdates:false}</bool>
+ <bool name="distributedCollectionConfigSetExecution">${distributedCollectionConfigSetExecution:false}</bool>
+ <int name="minStateByteLenForCompression">${minStateByteLenForCompression:-1}</int>
+ <str name="stateCompressor">${stateCompressor:org.apache.solr.common.util.ZLibCompressor}</str>
+
+ </solrcloud>
+
+ <shardHandlerFactory name="shardHandlerFactory"
+ class="HttpShardHandlerFactory">
+ <int name="socketTimeout">${socketTimeout:600000}</int>
+ <int name="connTimeout">${connTimeout:60000}</int>
+ </shardHandlerFactory>
+
+ <metrics enabled="${metricsEnabled:true}">
+ <!-- Solr computes JVM metrics for threads. Computing these metrics, esp. computing deadlocks etc.,
+ requires potentially expensive computations, and can be avoided for every metrics call by
+ setting a high caching expiration interval (in seconds).
+ <caching>
+ <int name="threadsIntervalSeconds">5</int>
+ </caching>
+ -->
+ <!--reporter name="jmx_metrics" group="core" class="org.apache.solr.metrics.reporters.SolrJmxReporter"/-->
+ </metrics>
+
+
+</solr>
diff --git a/scripts/hostclass/imap_server/10-solr b/scripts/hostclass/imap_server/10-solr
new file mode 100644
index 0000000..252a8c3
--- /dev/null
+++ b/scripts/hostclass/imap_server/10-solr
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+: ${solr_version:='9.7.0'}
+
+solr_uid=161
+solr_user=solr
+solr_data_dir=/var/db/solr
+solr_conf_dir=/usr/local/etc/solr
+solr_install_dir=/usr/local/solr
+solr_heap_size=2g
+solr_softcommit_ms=60000
+solr_url="https://dlcdn.apache.org/solr/solr/${solr_version}/solr-${solr_version}-slim.tgz"
+solr_port=8983
+
+# Install dependencies.
+pkg install -y \
+ curl \
+ openjdk21 \
+ bash
+
+# Add local solr user.
+add_user \
+ -u "$solr_uid" \
+ -c 'Apache Solr' \
+ -d "$solr_data_dir" \
+ -s /usr/sbin/nologin \
+ "$solr_user"
+
+# Create ZFS dataset for solr DB.
+create_dataset -o "mountpoint=${solr_data_dir}" "${state_dataset}/solr"
+
+# Set ownership on solr DB dir.
+install_directory -m 0770 -o "$solr_user" -g "$solr_user" "$solr_data_dir"
+
+# Create solr install/config directories.
+install_directory -m 0755 \
+ "$solr_install_dir" \
+ "$solr_conf_dir"
+
+# Download and extract the solr tarball.
+curl -fL "$solr_url" | tar xf - -C "$solr_install_dir" --strip-components 1
+
+# Copy solr rc script.
+install_file -m 0555 /usr/local/etc/rc.d/solr
+
+# Copy solr config files.
+install_file -m 0644 \
+ "${solr_conf_dir}/solrconfig.xml" \
+ "${solr_conf_dir}/log4j2.xml"
+
+# Copy the default solr config from the distribution.
+install -v -m 0644 -o "$solr_user" -g "$solr_user" \
+ "${solr_install_dir}/server/solr/solr.xml" \
+ "${solr_data_dir}/solr.xml"
+
+# Enable and start solr.
+sysrc -v \
+ solr_enable=YES \
+ solr_heap_size="$solr_heap_size"
+
+# Start solr.
+service solr restart
+
+# Create solr collection for dovecot.
+if ! [ -d "${solr_data_dir}/dovecot" ]; then
+ log "waiting a few seconds for solr to finish starting up"
+ sleep 3
+ JAVA_TOOL_OPTIONS='-Xmx64m' su -m "$solr_user" -c "${solr_install_dir}/bin/solr create --name dovecot --solr-url http://127.0.0.1:${solr_port}"
+fi
+
+# Copy solr configs for dovecot.
+install_file -m 0644 -o "$solr_user" -g "$solr_user" \
+ "${solr_data_dir}/dovecot/conf/schema.xml" \
+ "${solr_data_dir}/dovecot/conf/solrconfig.xml"
+rm -f "${solr_data_dir}/dovecot/conf/managed-schema.xml"
+
+# Restart solr.
+service solr restart
diff --git a/scripts/hostclass/imap_server/20-tika b/scripts/hostclass/imap_server/20-tika
new file mode 100644
index 0000000..3b4aa47
--- /dev/null
+++ b/scripts/hostclass/imap_server/20-tika
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+: ${tika_version:='2.9.2'}
+: ${tika_uid:='787'}
+
+tika_user=tika
+tika_conf_dir=/usr/local/etc/tika
+tika_install_dir=/usr/local/tika
+tika_heap_size=2g
+tika_port=9998
+tika_url="https://dlcdn.apache.org/tika/${tika_version}/tika-server-standard-${tika_version}.jar"
+
+# Add local tika user.
+add_user \
+ -u "$tika_uid" \
+ -c 'Apache Tika' \
+ -d /nonexistent \
+ -s /usr/sbin/nologin \
+ "$tika_user"
+
+# Create tika install/config directories.
+install_directory -m 0755 \
+ "$tika_install_dir" \
+ "$tika_conf_dir"
+
+# Download tika jar file.
+curl -fL -o "${tika_install_dir}/tika.jar" "$tika_url"
+
+# Copy tika rc script.
+install_file -m 0555 /usr/local/etc/rc.d/tika
+
+# Copy tika config files.
+install_template -m 0644 "${tika_conf_dir}/config.xml"
+install_file -m 0644 "${tika_conf_dir}/log4j2.xml"
+
+# Enable and start tika.
+sysrc -v tika_enable=YES
+service tika restart
diff --git a/scripts/hostclass/imap_server/30-dovecot b/scripts/hostclass/imap_server/30-dovecot
new file mode 100644
index 0000000..07c089e
--- /dev/null
+++ b/scripts/hostclass/imap_server/30-dovecot
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+: ${dovecot_recipient_delimiter:='+'}
+: ${dovecot_default_quota:='10G'}
+: ${dovecot_quota_grace_percent:='5'}
+: ${dovecot_quota_mail_from:="postmaster@${email_domain}"}
+: ${rspamd_host:='smtp'}
+
+dovecot_user=dovecot
+dovecot_login_user=dovenull
+dovecot_vmail_user=vmail
+dovecot_vmail_uid=793
+dovecot_vmail_dir=/var/db/vmail
+dovecot_conf_dir=/usr/local/etc/dovecot
+dovecot_script_dir=/usr/local/libexec/dovecot
+dovecot_sieve_before_dir="${dovecot_conf_dir}/sieve-before.d"
+dovecot_sieve_pipe_bin_dir="${dovecot_script_dir}/sieve-pipe"
+dovecot_keytab="${keytab_dir}/dovecot.keytab"
+dovecot_tls_cert="${dovecot_conf_dir}/dovecot.crt"
+dovecot_tls_key="${dovecot_conf_dir}/dovecot.key"
+dovecot_cipherlist='ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305'
+
+pkg install -y \
+ dovecot \
+ dovecot-pigeonhole \
+ rspamd
+
+# Add local vmail user.
+add_user \
+ -u "$dovecot_vmail_uid" \
+ -c 'Virtual Mail User' \
+ -d "$dovecot_vmail_dir" \
+ -s /usr/sbin/nologin \
+ "$dovecot_vmail_user"
+
+# Create ZFS dataset for virtual maildirs.
+create_dataset -o "mountpoint=${dovecot_vmail_dir}" "${state_dataset}/mailboxes"
+
+# Set ownership on vmail dir.
+install_directory -m 0770 -o "$dovecot_vmail_user" -g "$dovecot_vmail_user" "$dovecot_vmail_dir"
+
+# Create service principals and keytab.
+add_principal -nokey -x "containerdn=${services_basedn}" "imap/${fqdn}"
+add_principal -nokey -x "containerdn=${services_basedn}" "sieve/${fqdn}"
+
+ktadd -k "$dovecot_keytab" "imap/${fqdn}"
+ktadd -k "$dovecot_keytab" "sieve/${fqdn}"
+chgrp "$dovecot_user" "$dovecot_keytab"
+chmod 640 "$dovecot_keytab"
+
+dovecot_uid=$(id -u "$dovecot_user")
+install_directory -o "$dovecot_user" -m 0700 "/var/krb5/user/${dovecot_uid}"
+ln -snfv "$dovecot_keytab" "/var/krb5/user/${dovecot_uid}/keytab"
+ln -snfv "$dovecot_keytab" "/var/krb5/user/${dovecot_uid}/client.keytab"
+
+# Create dovecot directories.
+install_directory -m 0755 \
+ "${dovecot_conf_dir}/conf.d" \
+ "$dovecot_sieve_before_dir" \
+ "$dovecot_sieve_pipe_bin_dir"
+
+# Generate dovecot configuration.
+install_template -m 0644 \
+ "${dovecot_conf_dir}/dovecot.conf" \
+ "${dovecot_conf_dir}/dovecot-ldap-userdb.conf.ext" \
+ "${dovecot_conf_dir}/dovecot-ldap-passdb.conf.ext" \
+ "${dovecot_conf_dir}/conf.d/10-auth.conf" \
+ "${dovecot_conf_dir}/conf.d/10-mail.conf" \
+ "${dovecot_conf_dir}/conf.d/10-master.conf" \
+ "${dovecot_conf_dir}/conf.d/10-ssl.conf" \
+ "${dovecot_conf_dir}/conf.d/15-lda.conf" \
+ "${dovecot_conf_dir}/conf.d/90-fts.conf" \
+ "${dovecot_conf_dir}/conf.d/90-quota.conf" \
+ "${dovecot_conf_dir}/conf.d/90-sieve.conf" \
+ "${dovecot_conf_dir}/conf.d/90-sieve-extprograms.conf" \
+ "${dovecot_conf_dir}/conf.d/auth-ldap.conf.ext"
+
+install_template -m 0550 -o root -g "$dovecot_user" \
+ "${dovecot_sieve_pipe_bin_dir}/report-spam.sh" \
+ "${dovecot_sieve_pipe_bin_dir}/report-ham.sh" \
+
+install_file -m 0555 \
+ "${dovecot_script_dir}/quota-warning.sh"
+
+install_file -m 0644 \
+ "${dovecot_conf_dir}/conf.d/15-mailboxes.conf" \
+ "${dovecot_conf_dir}/conf.d/20-imap.conf" \
+ "${dovecot_conf_dir}/conf.d/20-lmtp.conf" \
+ "${dovecot_conf_dir}/conf.d/20-managesieve.conf" \
+ "${dovecot_conf_dir}/report-ham.sieve" \
+ "${dovecot_conf_dir}/report-spam.sieve" \
+ "${dovecot_sieve_before_dir}/10-rspamd.sieve"
+
+# Compile sieve scripts.
+sievec "${dovecot_conf_dir}/report-ham.sieve"
+sievec "${dovecot_conf_dir}/report-spam.sieve"
+sievec "${dovecot_sieve_before_dir}/10-rspamd.sieve"
+
+# Copy TLS certificate for dovecot.
+install_certificate -m 0644 -o root -g "$dovecot_user" dovecot "$dovecot_tls_cert"
+install_certificate_key -m 0640 -o root -g "$dovecot_user" dovecot "$dovecot_tls_key"
+
+# Enable and start dovecot and dependencies.
+sysrc -v dovecot_enable=YES
+service dovecot restart
+
+# Disable rspamd log rotation (we don't actually run rspamd here).
+echo '# intentionally empty' > /usr/local/etc/newsyslog.conf.d/rspamd.newsyslog.conf
diff --git a/scripts/hostclass/smtp_server/20-postfix b/scripts/hostclass/smtp_server/20-postfix
index 0d4830f..e224e9b 100644
--- a/scripts/hostclass/smtp_server/20-postfix
+++ b/scripts/hostclass/smtp_server/20-postfix
@@ -7,12 +7,8 @@
: ${postfix_recipient_delimiter:='+'}
: ${postfix_message_size_limit:='67108864'} # 64 MB
: ${postfix_virtual_domains:="$email_domain"}
-: ${postfix_lmtp_port:='24'}
-: ${postfix_quota_port:='10993'}
: ${imap_host='imap'}
-: ${lmtp_port='25'}
-: ${quota_status_port='10993'}
postfix_conf_dir=/usr/local/etc/postfix
postfix_user=postfix
@@ -57,7 +53,7 @@ install_certificate_key -m 0640 -o root -g "$postfix_user" postfix "$postfix_loc
if [ "$postfix_public_fqdn" != "$fqdn" ]; then
# Acquire public TLS certificate.
install_file /usr/local/etc/sudoers.d/acme
- get_acme_certificate \
+ acme_install_certificate \
-c "$postfix_public_tls_cert" \
-k "$postfix_public_tls_key" \
-g "$postfix_user" \
diff --git a/scripts/os/freebsd/60-acme b/scripts/os/freebsd/60-acme
new file mode 100644
index 0000000..902e674
--- /dev/null
+++ b/scripts/os/freebsd/60-acme
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+[ "${acme:-}" = true ] || return 0
+
+: ${acme_email:="root@${email_domain}"}
+: ${acme_keylength:='ec-256'}
+
+acme_cert_dir=/usr/local/etc/ssl/acme
+acme_standalone_port=9080
+acme_user=acme
+acme_home=/var/db/acme
+acme_webroot=/usr/local/www/acme
+
+pkg install -y acme.sh
+
+install_directory -m 0775 -o root -g "$acme_user" "$acme_cert_dir"
+install_template -m 0644 /etc/cron.d/acme
+
+if [ -n "${acme_eab_kid:-}" ]; then
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --register-account --eab-kid ${acme_eab_kid} --eab-hmac-key ${acme_eab_hmac_key}"
+else
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --register-account --email ${acme_email}"
+fi
+
+acme_install_certificate(){
+ _aic_group=0
+ _aic_cert_path=
+ _aic_key_path=
+ _aic_reload_cmd=
+
+ while getopts c:g:k:r: _aic_opt; do
+ case $_aic_opt in
+ c) _aic_cert_path=$OPTARG ;;
+ g) _aic_group=$OPTARG ;;
+ k) _aic_key_path=$OPTARG ;;
+ r) _aic_reload_cmd=$OPTARG ;;
+ esac
+ done
+
+ shift $((OPTIND - 1))
+ _aic_name=$1
+
+ # Acquire the certificate via HTTP ACME challenge.
+ _aic_domain_args=''
+ for _aic_domain; do
+ _aic_domain_args="${_aic_domain_args} -d ${_aic_domain}"
+ done
+
+ if [ -n "${acme_standalone:-}" ]; then
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --issue --keylength ${acme_keylength} --standalone --httport ${acme_standalone_port} ${_aic_domain_args}" && _aic_rc=$? || _aic_rc=$?
+ else
+ install_directory -o root -g "$acme_user" -m 0775 "$acme_webroot"
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --issue --keylength ${acme_keylength} -w ${acme_webroot} ${_aic_domain_args}" && _aic_rc=$? || _aic_rc=$?
+ fi
+
+ case $_aic_rc in
+ 0) ;; # New cert was issued.
+ 2) ;; # Cert was unchanged.
+ *) die "failed to issue ACME certificate for: $*" ;;
+ esac
+
+ # Install the certificate to the requested location.
+ if [ -f "$_aic_key_path" ]; then
+ chmod 640 "$_aic_key_path"
+ chown "${acme_user}:${_aic_group}" "$_aic_key_path"
+ else
+ install -o "$acme_user" -g "$_aic_group" -m 0640 /dev/null "$_aic_key_path"
+ fi
+
+ if [ -n "$_aic_reload_cmd" ]; then
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path} --reloadcmd '${_aic_reload_cmd}'"
+ else
+ su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path}"
+ fi
+}
diff --git a/vars/common b/vars/common
index 7c54673..18d0e52 100644
--- a/vars/common
+++ b/vars/common
@@ -39,6 +39,8 @@ graphics_type=intel
boxconf_username='s-boxconf'
host_keytab_groupname=hostkeytab
host_keytab_gid=788
+lmtp_port=25
+quota_status_port=10993
krb5_ticket_lifetime=24h
krb5_renew_lifetime=7d
nslcd_min_uid=1000
diff --git a/vars/hostclass/imap_server b/vars/hostclass/imap_server
new file mode 100644
index 0000000..c1467b2
--- /dev/null
+++ b/vars/hostclass/imap_server
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+allowed_tcp_ports="ssh imaps ${lmtp_port} ${quota_status_port}"
diff --git a/vars/hostclass/smtp_server b/vars/hostclass/smtp_server
index d68e28a..fd05469 100644
--- a/vars/hostclass/smtp_server
+++ b/vars/hostclass/smtp_server
@@ -2,5 +2,5 @@
allowed_tcp_ports="ssh smtp submission ${rspamd_port} http https"
postfix_mynetworks='127.0.0.1/8'
+acme=true
nginx_gssapi=true
-nginx_acme=true
diff --git a/vars/hostname/imap1 b/vars/hostname/imap1
new file mode 100644
index 0000000..09de713
--- /dev/null
+++ b/vars/hostname/imap1
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cnames=imap
diff --git a/vars/os/freebsd b/vars/os/freebsd
index 8b0afb3..12d3938 100644
--- a/vars/os/freebsd
+++ b/vars/os/freebsd
@@ -9,11 +9,6 @@ intel_epp=50
see_other_uids=0
export ASSUME_ALWAYS_YES=yes
-acme_cert_dir=/usr/local/etc/ssl/acme
-acme_standalone_port=9080
-acme_uid=169
-acme_webroot=/usr/local/www/acme
-apache_version=24
keytab_dir=/var/db/keytabs
nfscbd_port=7745
nginx_user=www