Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Use TLS filenames same as certbot (see #350). * Put the Docker-specific maddy.conf in the repo (see #350). * Set OCI labels for the image in CI * Move Docker-specific documentation from Docker Hub into docs/ * Add .dockerignore
- Loading branch information
Showing
7 changed files
with
297 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
testdata/ | ||
cmd/maddy/maddy | ||
maddy | ||
tests/maddy.cover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,30 @@ | ||
FROM golang:1.17-alpine AS build-env | ||
|
||
RUN set -ex ;\ | ||
apk upgrade --no-cache --available ;\ | ||
apk add --no-cache bash git build-base | ||
RUN set -ex && \ | ||
apk upgrade --no-cache --available && \ | ||
apk add --no-cache build-base | ||
|
||
WORKDIR /maddy | ||
ADD go.mod go.sum ./ | ||
ENV LDFLAGS -static | ||
|
||
COPY go.mod go.sum ./ | ||
RUN go mod download | ||
ADD . ./ | ||
RUN mkdir -p /pkg/data | ||
COPY maddy.conf /pkg/data/maddy.conf | ||
# Monkey-patch config to use environment. | ||
RUN sed -Ei 's!\$\(hostname\) = .+!$(hostname) = {env:MADDY_HOSTNAME}!' /pkg/data/maddy.conf | ||
RUN sed -Ei 's!\$\(primary_domain\) = .+!$(primary_domain) = {env:MADDY_DOMAIN}!' /pkg/data/maddy.conf | ||
RUN sed -Ei 's!^tls .+!tls file /data/tls_cert.pem /data/tls_key.pem!' /pkg/data/maddy.conf | ||
|
||
RUN ./build.sh --builddir /tmp --destdir /pkg/ --tags docker build install | ||
COPY . ./ | ||
RUN mkdir -p /pkg/data && \ | ||
cp maddy.conf.docker /pkg/data/maddy.conf && \ | ||
./build.sh --builddir /tmp --destdir /pkg/ --tags docker build install | ||
|
||
FROM alpine:3.15.0 | ||
FROM alpine:3.16.0 | ||
LABEL maintainer="fox.cpp@disroot.org" | ||
LABEL org.opencontainers.image.source=https://github.com/foxcpp/maddy | ||
|
||
RUN set -ex ;\ | ||
apk upgrade --no-cache --available ;\ | ||
RUN set -ex && \ | ||
apk upgrade --no-cache --available && \ | ||
apk --no-cache add ca-certificates | ||
COPY --from=build-env /pkg/data/maddy.conf /data/maddy.conf | ||
COPY --from=build-env /pkg/usr/local/bin/maddy /pkg/usr/local/bin/maddyctl /bin/ | ||
|
||
EXPOSE 25 143 993 587 465 | ||
VOLUME ["/data"] | ||
ENTRYPOINT ["/bin/maddy", "-config", "/data/maddy.conf", "run"] | ||
ENTRYPOINT ["/bin/maddy", "-config", "/data/maddy.conf"] | ||
CMD ["run"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Docker | ||
|
||
Official Docker image is available from Docker Hub. | ||
|
||
It expects configuration file to be available at /data/maddy.conf. | ||
|
||
If /data is a Docker volume, then default configuration will be placed there | ||
automatically. If it is used, then MADDY_HOSTNAME, MADDY_DOMAIN environment | ||
variables control the host name and primary domain for the server. TLS | ||
certificate should be placed in /data/tls/fullchain.pem, private key in | ||
/data/tls/privkey.pem | ||
|
||
DKIM keys are generated in /data/dkim_keys directory. | ||
|
||
## Image tags | ||
|
||
- `latest` - A latest stable release. May contain breaking changes. | ||
- `X.Y` - A specific feature branch, it is recommended to use these tags to | ||
receive bugfixes without the risk of feature-related regressions or breaking | ||
changes. | ||
- `X.Y.Z` - A specific stable release | ||
|
||
## Ports | ||
|
||
All standard ports, as described in maddy docs. | ||
|
||
- `25` - SMTP inbound port. | ||
- `465`, `587` - SMTP Submission ports | ||
- `993`, `143` - IMAP4 ports | ||
|
||
## Volumes | ||
|
||
`/data` - maddy state directory. Databases, queues, etc are stored here. You | ||
might want to mount a named volume there. The main configuration file is stored | ||
here too (`/data/maddy.conf`). | ||
|
||
## Management utility | ||
|
||
To run management commands, create a temporary container with the same | ||
/data directory and put the command after the image name, like this: | ||
|
||
``` | ||
docker run --rm -it -v maddydata:/data foxcpp/maddy:0.6.0 creds create foxcpp@maddy.test | ||
docker run --rm -it -v maddydata:/data foxcpp/maddy:0.6.0 imap-acct create foxcpp@maddy.test | ||
``` | ||
|
||
Use the same image version as the running server. Things may break badly | ||
otherwise. | ||
|
||
Note that, if you modify messages using maddyctl while the server is running - | ||
you must ensure that /tmp from the server is accessible for the management | ||
command. One way to it is to run it using `docker exec` instead of `docker run`: | ||
``` | ||
docker exec -it container_name_here maddy creds create foxcpp@maddy.test | ||
``` | ||
|
||
## TL;DR | ||
|
||
``` | ||
docker volume create maddydata | ||
docker run \ | ||
--name maddy \ | ||
-e MADDY_HOSTNAME=mx.maddy.test \ | ||
-e MADDY_DOMAIN=maddy.test \ | ||
-v maddydata:/data \ | ||
-p 25:25 \ | ||
-p 143:143 \ | ||
-p 587:587 \ | ||
-p 993:993 \ | ||
foxcpp/maddy:0.6 | ||
``` | ||
|
||
It will fail on first startup. Copy TLS certificate to /data/tls/fullchain.pem | ||
and key to /data/tls/privkey.pem. Run the server again. Finish DNS configuration | ||
(DKIM keys, etc) as described in [tutorials/setting-up/](tutorials/setting-up/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
## Maddy Mail Server - default configuration file (2022-06-18) | ||
## This is the copy of maddy.conf with changes necessary to run it in Docker. | ||
# Suitable for small-scale deployments. Uses its own format for local users DB, | ||
# should be managed via maddyctl utility. | ||
# | ||
# See tutorials at https://maddy.email for guidance on typical | ||
# configuration changes. | ||
|
||
# ---------------------------------------------------------------------------- | ||
# Base variables | ||
|
||
$(hostname) = {env:MADDY_HOSTNAME} | ||
$(primary_domain) = {env:MADDY_DOMAIN} | ||
$(local_domains) = $(primary_domain) | ||
|
||
tls file /data/tls/fullchain.pem /data/tls/privkey.pem | ||
|
||
# ---------------------------------------------------------------------------- | ||
# Local storage & authentication | ||
|
||
# pass_table provides local hashed passwords storage for authentication of | ||
# users. It can be configured to use any "table" module, in default | ||
# configuration a table in SQLite DB is used. | ||
# Table can be replaced to use e.g. a file for passwords. Or pass_table module | ||
# can be replaced altogether to use some external source of credentials (e.g. | ||
# PAM, /etc/shadow file). | ||
# | ||
# If table module supports it (sql_table does) - credentials can be managed | ||
# using 'maddyctl creds' command. | ||
|
||
auth.pass_table local_authdb { | ||
table sql_table { | ||
driver sqlite3 | ||
dsn credentials.db | ||
table_name passwords | ||
} | ||
} | ||
|
||
# imapsql module stores all indexes and metadata necessary for IMAP using a | ||
# relational database. It is used by IMAP endpoint for mailbox access and | ||
# also by SMTP & Submission endpoints for delivery of local messages. | ||
# | ||
# IMAP accounts, mailboxes and all message metadata can be inspected using | ||
# imap-* subcommands of maddyctl utility. | ||
|
||
storage.imapsql local_mailboxes { | ||
driver sqlite3 | ||
dsn imapsql.db | ||
} | ||
|
||
# ---------------------------------------------------------------------------- | ||
# SMTP endpoints + message routing | ||
|
||
hostname $(hostname) | ||
|
||
table.chain local_rewrites { | ||
optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3" | ||
optional_step static { | ||
entry postmaster postmaster@$(primary_domain) | ||
} | ||
optional_step file /etc/maddy/aliases | ||
} | ||
|
||
msgpipeline local_routing { | ||
# Insert handling for special-purpose local domains here. | ||
# e.g. | ||
# destination lists.example.org { | ||
# deliver_to lmtp tcp://127.0.0.1:8024 | ||
# } | ||
|
||
destination postmaster $(local_domains) { | ||
modify { | ||
replace_rcpt &local_rewrites | ||
} | ||
|
||
deliver_to &local_mailboxes | ||
} | ||
|
||
default_destination { | ||
reject 550 5.1.1 "User doesn't exist" | ||
} | ||
} | ||
|
||
smtp tcp://0.0.0.0:25 { | ||
limits { | ||
# Up to 20 msgs/sec across max. 10 SMTP connections. | ||
all rate 20 1s | ||
all concurrency 10 | ||
} | ||
|
||
dmarc yes | ||
check { | ||
require_mx_record | ||
dkim | ||
spf | ||
} | ||
|
||
source $(local_domains) { | ||
reject 501 5.1.8 "Use Submission for outgoing SMTP" | ||
} | ||
default_source { | ||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
reject 550 5.1.1 "User doesn't exist" | ||
} | ||
} | ||
} | ||
|
||
submission tls://0.0.0.0:465 tcp://0.0.0.0:587 { | ||
limits { | ||
# Up to 50 msgs/sec across any amount of SMTP connections. | ||
all rate 50 1s | ||
} | ||
|
||
auth &local_authdb | ||
|
||
source $(local_domains) { | ||
check { | ||
authorize_sender { | ||
prepare_email &local_rewrites | ||
user_to_email identity | ||
} | ||
} | ||
|
||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
modify { | ||
dkim $(primary_domain) $(local_domains) default | ||
} | ||
deliver_to &remote_queue | ||
} | ||
} | ||
default_source { | ||
reject 501 5.1.8 "Non-local sender domain" | ||
} | ||
} | ||
|
||
target.remote outbound_delivery { | ||
limits { | ||
# Up to 20 msgs/sec across max. 10 SMTP connections | ||
# for each recipient domain. | ||
destination rate 20 1s | ||
destination concurrency 10 | ||
} | ||
mx_auth { | ||
dane | ||
mtasts { | ||
cache fs | ||
fs_dir mtasts_cache/ | ||
} | ||
local_policy { | ||
min_tls_level encrypted | ||
min_mx_level none | ||
} | ||
} | ||
} | ||
|
||
target.queue remote_queue { | ||
target &outbound_delivery | ||
|
||
autogenerated_msg_domain $(primary_domain) | ||
bounce { | ||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
reject 550 5.0.0 "Refusing to send DSNs to non-local addresses" | ||
} | ||
} | ||
} | ||
|
||
# ---------------------------------------------------------------------------- | ||
# IMAP endpoints | ||
|
||
imap tls://0.0.0.0:993 tcp://0.0.0.0:143 { | ||
auth &local_authdb | ||
storage &local_mailboxes | ||
} |