Stalwart: Difference between revisions
Use stalwart-mail.credentials for secrets handling |
change references in nix configuration examples from `stalwart-mail` to `stalwart` |
||
| Line 4: | Line 4: | ||
The following example enables the Stalwart mail server for the domain ''example.org'', listening on mail delivery SMTP/Submission (<code>25, 465</code>), IMAPS (<code>993</code>) and JMAP ports (8080/443) for mail clients to connect to. Mailboxes for the accounts <code>postmaster@example.org</code> and <code>user1@example.org</code> get created if they don't exist yet. | The following example enables the Stalwart mail server for the domain ''example.org'', listening on mail delivery SMTP/Submission (<code>25, 465</code>), IMAPS (<code>993</code>) and JMAP ports (8080/443) for mail clients to connect to. Mailboxes for the accounts <code>postmaster@example.org</code> and <code>user1@example.org</code> get created if they don't exist yet. | ||
{{file| | {{file|||3=environment.etc = { | ||
"stalwart/mail-pw1".text = "foobar"; | "stalwart/mail-pw1".text = "foobar"; | ||
"stalwart/mail-pw2".text = "foobar"; | "stalwart/mail-pw2".text = "foobar"; | ||
| Line 11: | Line 11: | ||
}; | }; | ||
services.stalwart | services.stalwart = { | ||
enable = true; | enable = true; | ||
openFirewall = true; | openFirewall = true; | ||
| Line 62: | Line 62: | ||
domains = [ "example.org" "mx1.example.org" ]; | domains = [ "example.org" "mx1.example.org" ]; | ||
provider = "cloudflare"; | provider = "cloudflare"; | ||
secret = "%{file:/run/credentials/stalwart | secret = "%{file:/run/credentials/stalwart.service/acme-secret}%"; | ||
}; | }; | ||
session.auth = { | session.auth = { | ||
| Line 77: | Line 77: | ||
class = "individual"; | class = "individual"; | ||
name = "User 1"; | name = "User 1"; | ||
secret = "%{file:/run/credentials/stalwart | secret = "%{file:/run/credentials/stalwart.service/mail-pw1}%"; | ||
email = [ "user1@example.org" ]; | email = [ "user1@example.org" ]; | ||
} | } | ||
| Line 83: | Line 83: | ||
class = "individual"; | class = "individual"; | ||
name = "postmaster"; | name = "postmaster"; | ||
secret = "%{file:/run/credentials/stalwart | secret = "%{file:/run/credentials/stalwart.service/mail-pw1}%"; | ||
email = [ "postmaster@example.org" ]; | email = [ "postmaster@example.org" ]; | ||
} | } | ||
| Line 90: | Line 90: | ||
authentication.fallback-admin = { | authentication.fallback-admin = { | ||
user = "admin"; | user = "admin"; | ||
secret = "%{file:/run/credentials/stalwart | secret = "%{file:/run/credentials/stalwart.service/admin-pw}%"; | ||
}; | }; | ||
}; | }; | ||
| Line 110: | Line 110: | ||
}; | }; | ||
}; | }; | ||
};}} | };|name=/etc/nixos/configuration.nix|lang=nix}} | ||
TLS key generation is done using DNS-01 challenge through Cloudflare domain provider, see dns-update library for [https://github.com/stalwartlabs/dns-update further providers] or configure [https://stalw.art/docs/server/tls/certificates manual certificates]. | TLS key generation is done using DNS-01 challenge through Cloudflare domain provider, see dns-update library for [https://github.com/stalwartlabs/dns-update further providers] or configure [https://stalw.art/docs/server/tls/certificates manual certificates]. | ||
| Line 228: | Line 228: | ||
=== Running behind reverse proxy === | === Running behind reverse proxy === | ||
When running behind a load balancer or reverse proxy, Stalwart will not be able to see the "real" sender IP-addresses of incoming mails in case of simple port forwarding. [[HAProxy]] or Proxy Protocol solves this problem and should be used on the reverse proxy server to forward SMTP traffic. Stalwart will start parsing the Proxy Protocol packages if correctly configured on the listener.{{file|||3=services.stalwart | When running behind a load balancer or reverse proxy, Stalwart will not be able to see the "real" sender IP-addresses of incoming mails in case of simple port forwarding. [[HAProxy]] or Proxy Protocol solves this problem and should be used on the reverse proxy server to forward SMTP traffic. Stalwart will start parsing the Proxy Protocol packages if correctly configured on the listener.{{file|||3=services.stalwart = { | ||
settings = { | settings = { | ||
server = { | server = { | ||
| Line 252: | Line 252: | ||
Considering the configuration above, we could add a mail alias for <code>user1@example.org</code> by simply adding further addresses to the <code>email</code>-array such as <code>user1real@example.org</code> | Considering the configuration above, we could add a mail alias for <code>user1@example.org</code> by simply adding further addresses to the <code>email</code>-array such as <code>user1real@example.org</code> | ||
{{file| | {{file|||3=services.stalwart = { | ||
settings = { | settings = { | ||
[...] | [...] | ||
| Line 261: | Line 261: | ||
class = "individual"; | class = "individual"; | ||
name = "User 1"; | name = "User 1"; | ||
secret = "%{file:/run/credentials/stalwart | secret = "%{file:/run/credentials/stalwart.service/mail-pw1}%"; | ||
email = [ "user1@example.org" "user1real@example.org ]; | email = [ "user1@example.org" "user1real@example.org ]; | ||
} | } | ||
| Line 267: | Line 267: | ||
}; | }; | ||
}; | }; | ||
};}} | };|name=/etc/nixos/configuration.nix|lang=nix}} | ||
=== Blocking mail sender address === | === Blocking mail sender address === | ||
If you don't want to receive any mails from a specific address, even not into your spam folder, you can add it to the spam-trap array.{{file|||3=services.stalwart | If you don't want to receive any mails from a specific address, even not into your spam folder, you can add it to the spam-trap array.{{file|||3=services.stalwart = { | ||
settings = { | settings = { | ||
lookup = { | lookup = { | ||
| Line 287: | Line 287: | ||
Following script is a possible workaounrd. It extracts the ACME cert every five minute, calculates the TLSA hash and compares it with the upstream record. If it doesn't match, it uses [https://github.com/Stenstromen/gotlsaflare gotlsaflare] to update the TLSA record on Cloudflare. | Following script is a possible workaounrd. It extracts the ACME cert every five minute, calculates the TLSA hash and compares it with the upstream record. If it doesn't match, it uses [https://github.com/Stenstromen/gotlsaflare gotlsaflare] to update the TLSA record on Cloudflare. | ||
<syntaxhighlight lang="nixos"> | <syntaxhighlight lang="nixos">systemd.services.tlsa-cloudflare-update = { | ||
systemd.services.tlsa-cloudflare-update = { | |||
description = "Check and update TLSA/DANE record for mx1 from Stalwart ACME Cert"; | description = "Check and update TLSA/DANE record for mx1 from Stalwart ACME Cert"; | ||
after = [ | after = [ | ||
"network-online.target" | "network-online.target" | ||
"stalwart | "stalwart.service" | ||
]; | ]; | ||
wants = [ | wants = [ | ||
"network-online.target" | "network-online.target" | ||
"stalwart | "stalwart.service" | ||
]; | ]; | ||
serviceConfig = { | serviceConfig = { | ||
Type = "oneshot"; | Type = "oneshot"; | ||
User = "stalwart | User = "stalwart"; | ||
Group = "stalwart | Group = "stalwart"; | ||
EnvironmentFile = config.age.secrets.gotlsaflare-cloudflare-token.path; | EnvironmentFile = config.age.secrets.gotlsaflare-cloudflare-token.path; | ||
RuntimeDirectory = "stalwart-tlsa"; | RuntimeDirectory = "stalwart-tlsa"; | ||
| Line 327: | Line 326: | ||
TLSA_RECORD="_$PORT._tcp.$SUBDOMAIN.$DOMAIN" | TLSA_RECORD="_$PORT._tcp.$SUBDOMAIN.$DOMAIN" | ||
DB_PATH="/var/lib/stalwart | DB_PATH="/var/lib/stalwart/db" | ||
TEMP_RAW="/run/stalwart-tlsa/cert.bundle" | TEMP_RAW="/run/stalwart-tlsa/cert.bundle" | ||
TEMP_CRT="/run/stalwart-tlsa/cert.crt" | TEMP_CRT="/run/stalwart-tlsa/cert.crt" | ||
| Line 372: | Line 371: | ||
Unit = "tlsa-cloudflare-update.service"; | Unit = "tlsa-cloudflare-update.service"; | ||
}; | }; | ||
}; | };</syntaxhighlight> | ||
</syntaxhighlight> | |||
Adapt the variables <code>DOMAIN</code>, <code>SUBDOMAIN</code>, and <code>PORT</code> according to your needs. The variable <code>ACME_PROVIDER_ID</code> corresponds to the ACME profile name you've setup in the Stalwart webadmin interface. <code>EnvironmentFile</code> points to a file containing the secret Cloudflare api token in the format: TOKEN=12345678[...]. | Adapt the variables <code>DOMAIN</code>, <code>SUBDOMAIN</code>, and <code>PORT</code> according to your needs. The variable <code>ACME_PROVIDER_ID</code> corresponds to the ACME profile name you've setup in the Stalwart webadmin interface. <code>EnvironmentFile</code> points to a file containing the secret Cloudflare api token in the format: TOKEN=12345678[...]. | ||
| Line 400: | Line 398: | ||
Receiving mails to subaddresses like <code>john+secondary@example.org</code> is enabled by default. Sending from subaddresses will fail with "You are not allowed to send from this address" as long as they are not an configured alias address. You can disable this check but it will allow any authenticated user to send from any other address. | Receiving mails to subaddresses like <code>john+secondary@example.org</code> is enabled by default. Sending from subaddresses will fail with "You are not allowed to send from this address" as long as they are not an configured alias address. You can disable this check but it will allow any authenticated user to send from any other address. | ||
{{file| | {{file|||3=services.stalwart = { | ||
settings = { | settings = { | ||
[...] | [...] | ||
session.auth.must-match-sender = false; | session.auth.must-match-sender = false; | ||
}; | }; | ||
};}} | };|name=/etc/nixos/configuration.nix|lang=nix}} | ||
A configuration option to customize the pattern of authorized sender addresses is a [https://github.com/stalwartlabs/stalwart/issues/394#issuecomment-3705990056 planned feature]. | A configuration option to customize the pattern of authorized sender addresses is a [https://github.com/stalwartlabs/stalwart/issues/394#issuecomment-3705990056 planned feature]. | ||
| Line 417: | Line 415: | ||
=== Unsecure setup for testing environments === | === Unsecure setup for testing environments === | ||
The following minimal configuration example is unsecure and for testing purpose only. It will run the Stalwart mail server on <code>localhost</code>, listening on port <code>143</code> (IMAP) and <code>587</code> (Submission). Users <code>alice</code> and <code>bob</code> are configured with the password <code>foobar</code>.{{file| | The following minimal configuration example is unsecure and for testing purpose only. It will run the Stalwart mail server on <code>localhost</code>, listening on port <code>143</code> (IMAP) and <code>587</code> (Submission). Users <code>alice</code> and <code>bob</code> are configured with the password <code>foobar</code>.{{file|||3=services.stalwart = { | ||
enable = true; | enable = true; | ||
settings = { | settings = { | ||
| Line 460: | Line 458: | ||
}; | }; | ||
}; | }; | ||
};}} | };|name=/etc/nixos/configuration.nix|lang=nix}} | ||
== See also == | == See also == | ||