mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 08:23:48 +03:00
help run mox with docker
in the Dockerfile, allow running on privileged ports and expose those ports. add a docker-compose.yml with instructions for the quickstart. fix running imaptest somewhat. after a short while it will hit the rate limiter. in quickstart, recognize we are running under docker, and print slightly different commands to set permissions, and skip generating the systemd service file. als fix cleaning up the right paths during failure in quickstart. for issue #3
This commit is contained in:
parent
210fd34702
commit
b1dcd73ebe
8 changed files with 104 additions and 34 deletions
34
Dockerfile
34
Dockerfile
|
@ -1,11 +1,33 @@
|
||||||
FROM golang:1-alpine AS build
|
FROM golang:1-alpine AS build
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
RUN apk add make
|
|
||||||
COPY . .
|
COPY . .
|
||||||
env GOPROXY=off
|
RUN GOPROXY=off CGO_ENABLED=0 go build -trimpath
|
||||||
RUN make build
|
|
||||||
|
|
||||||
FROM alpine:3.17
|
# Using latest may break at some point, but will hopefully be convenient most of the time.
|
||||||
|
FROM alpine:latest
|
||||||
WORKDIR /mox
|
WORKDIR /mox
|
||||||
COPY --from=build /build/mox /mox/mox
|
COPY --from=build /build/mox /bin/mox
|
||||||
CMD ["/mox/mox", "serve"]
|
|
||||||
|
RUN apk add --no-cache libcap-utils
|
||||||
|
|
||||||
|
# Allow binding to privileged ports, <1024.
|
||||||
|
RUN setcap 'cap_net_bind_service=+ep' /bin/mox
|
||||||
|
|
||||||
|
# SMTP for incoming message delivery.
|
||||||
|
EXPOSE 25/tcp
|
||||||
|
# SMTP/submission with TLS.
|
||||||
|
EXPOSE 465/tcp
|
||||||
|
# SMTP/submission without initial TLS.
|
||||||
|
EXPOSE 587/tcp
|
||||||
|
# HTTP for internal account and admin pages.
|
||||||
|
EXPOSE 80/tcp
|
||||||
|
# HTTPS for ACME (Let's Encrypt), MTA-STS and autoconfig.
|
||||||
|
EXPOSE 443/tcp
|
||||||
|
# IMAP with TLS.
|
||||||
|
EXPOSE 993/tcp
|
||||||
|
# IMAP without initial TLS.
|
||||||
|
EXPOSE 143/tcp
|
||||||
|
# Prometheus metrics.
|
||||||
|
EXPOSE 8010/tcp
|
||||||
|
|
||||||
|
CMD ["/bin/mox", "serve"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:3.17
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk update && apk add wget build-base
|
RUN apk --no-cache add build-base
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
RUN wget http://dovecot.org/nightly/dovecot-latest.tar.gz && tar -zxvf dovecot-latest.tar.gz && cd dovecot-0.0.0-* && ./configure && make install && cd ..
|
RUN wget http://dovecot.org/nightly/dovecot-latest.tar.gz && tar -zxvf dovecot-latest.tar.gz && cd dovecot-0.0.0-* && ./configure && make install && cd ..
|
||||||
RUN wget http://dovecot.org/nightly/imaptest/imaptest-latest.tar.gz && tar -zxvf imaptest-latest.tar.gz && cd dovecot-0.0-imaptest-0.0.0-* && ./configure --with-dovecot=$(ls -d ../dovecot-0.0.0-*) && make install
|
RUN wget http://dovecot.org/nightly/imaptest/imaptest-latest.tar.gz && tar -zxvf imaptest-latest.tar.gz && cd dovecot-0.0-imaptest-0.0.0-* && ./configure --with-dovecot=$(ls -d ../dovecot-0.0.0-*) && make install
|
||||||
|
|
11
Dockerfile.moximaptest
Normal file
11
Dockerfile.moximaptest
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
FROM golang:1-alpine AS build
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN GOPROXY=off CGO_ENABLED=0 go build -trimpath
|
||||||
|
|
||||||
|
# Using latest may break at some point, but will hopefully be convenient most of the time.
|
||||||
|
FROM alpine:latest
|
||||||
|
WORKDIR /mox
|
||||||
|
COPY --from=build /build/mox /bin/mox
|
||||||
|
|
||||||
|
CMD ["/bin/mox", "serve"]
|
1
Makefile
1
Makefile
|
@ -50,7 +50,6 @@ integration-start:
|
||||||
# run from within "make integration-start"
|
# run from within "make integration-start"
|
||||||
integration-test:
|
integration-test:
|
||||||
CGO_ENABLED=0 go test -tags integration
|
CGO_ENABLED=0 go test -tags integration
|
||||||
go tool cover -html=cover.out -o cover.html
|
|
||||||
|
|
||||||
imaptest-build:
|
imaptest-build:
|
||||||
-MOX_UID=$$(id -u) MOX_GID=$$(id -g) docker-compose -f docker-compose-imaptest.yml build --no-cache mox
|
-MOX_UID=$$(id -u) MOX_GID=$$(id -g) docker-compose -f docker-compose-imaptest.yml build --no-cache mox
|
||||||
|
|
|
@ -85,6 +85,9 @@ Verify you have a working mox binary:
|
||||||
|
|
||||||
Note: Mox only compiles/works on unix systems, not on Plan 9 or Windows.
|
Note: Mox only compiles/works on unix systems, not on Plan 9 or Windows.
|
||||||
|
|
||||||
|
You can also run mox with docker image "moxmail/mox" on hub.docker.com, with
|
||||||
|
tags like "latest", "0.0.1", etc. See docker-compose.yml in this repository.
|
||||||
|
|
||||||
|
|
||||||
# Quickstart
|
# Quickstart
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
version: '3.7'
|
version: '3.7'
|
||||||
services:
|
services:
|
||||||
mox:
|
mox:
|
||||||
build: .
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.moximaptest
|
||||||
user: ${MOX_UID}:${MOX_GID}
|
user: ${MOX_UID}:${MOX_GID}
|
||||||
volumes:
|
volumes:
|
||||||
- ./testdata/imaptest/data:/mox/data
|
- ./testdata/imaptest/data:/mox/data
|
||||||
|
@ -9,7 +11,8 @@ services:
|
||||||
- ./testdata/imaptest/domains.conf:/mox/domains.conf
|
- ./testdata/imaptest/domains.conf:/mox/domains.conf
|
||||||
- ./testdata/imaptest/imaptest.mbox:/mox/imaptest.mbox
|
- ./testdata/imaptest/imaptest.mbox:/mox/imaptest.mbox
|
||||||
working_dir: /mox
|
working_dir: /mox
|
||||||
command: sh -c 'echo testtest | ./mox setaccountpassword mjl@mox.example && ./mox serve'
|
tty: true # For job control
|
||||||
|
command: sh -c 'export MOXCONF=mox.conf; set -m; mox serve & sleep 1; echo testtest | mox setaccountpassword mjl@mox.example; fg'
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: netstat -nlt | grep ':1143 '
|
test: netstat -nlt | grep ':1143 '
|
||||||
interval: 1s
|
interval: 1s
|
||||||
|
|
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Before launching mox, run the quickstart to create config files:
|
||||||
|
#
|
||||||
|
# MOX_UID=0 MOX_GID=0 docker-compose run mox mox quickstart you@yourdomain.example
|
||||||
|
#
|
||||||
|
# After following the instructions, start mox as the newly created mox user:
|
||||||
|
#
|
||||||
|
# MOX_UID=$(id -u mox) MOX_GID=$(id -g mox) docker-compose up
|
||||||
|
|
||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
mox:
|
||||||
|
# Replace latest with the version you want to run.
|
||||||
|
image: moxmail/mox:latest
|
||||||
|
user: ${MOX_UID}:${MOX_GID}
|
||||||
|
environment:
|
||||||
|
- MOX_DOCKER=... # Quickstart won't try to write systemd service file.
|
||||||
|
# Mox needs host networking because it needs access to the IPs of the
|
||||||
|
# machine, and the IPs of incoming connections for spam filtering.
|
||||||
|
network_mode: 'host'
|
||||||
|
command: sh -c "umask 007 && exec mox serve"
|
||||||
|
volumes:
|
||||||
|
- ./config:/mox/config
|
||||||
|
- ./data:/mox/data
|
||||||
|
working_dir: /mox
|
||||||
|
restart: on-failure
|
||||||
|
healthcheck:
|
||||||
|
test: netstat -nlt | grep ':25 '
|
||||||
|
interval: 1s
|
||||||
|
timeout: 1s
|
||||||
|
retries: 10
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -345,7 +344,8 @@ This likely means one of two things:
|
||||||
|
|
||||||
dc := config.Dynamic{}
|
dc := config.Dynamic{}
|
||||||
sc := config.Static{DataDir: "../data"}
|
sc := config.Static{DataDir: "../data"}
|
||||||
os.MkdirAll(sc.DataDir, 0770)
|
dataDir := "data" // ../data is relative to config/
|
||||||
|
os.MkdirAll(dataDir, 0770)
|
||||||
sc.LogLevel = "info"
|
sc.LogLevel = "info"
|
||||||
sc.Hostname = hostname.Name()
|
sc.Hostname = hostname.Name()
|
||||||
sc.ACME = map[string]config.ACME{
|
sc.ACME = map[string]config.ACME{
|
||||||
|
@ -491,7 +491,7 @@ This likely means one of two things:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("open account: %s", err)
|
fatalf("open account: %s", err)
|
||||||
}
|
}
|
||||||
cleanupPaths = append(cleanupPaths, sc.DataDir, filepath.Join(sc.DataDir, "accounts"), filepath.Join(sc.DataDir, "accounts", username), filepath.Join(sc.DataDir, "accounts", username, "index.db"))
|
cleanupPaths = append(cleanupPaths, dataDir, filepath.Join(dataDir, "accounts"), filepath.Join(dataDir, "accounts", username), filepath.Join(dataDir, "accounts", username, "index.db"))
|
||||||
|
|
||||||
password := pwgen()
|
password := pwgen()
|
||||||
if err := acc.SetPassword(password); err != nil {
|
if err := acc.SetPassword(password); err != nil {
|
||||||
|
@ -534,34 +534,36 @@ and permissions.
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
userName := "root"
|
if os.Getenv("MOX_DOCKER") == "" {
|
||||||
groupName := "root"
|
|
||||||
if u, err := user.Current(); err != nil {
|
|
||||||
log.Printf("get current user: %v", err)
|
|
||||||
} else {
|
|
||||||
userName = u.Username
|
|
||||||
if g, err := user.LookupGroupId(u.Gid); err != nil {
|
|
||||||
log.Printf("get current group: %v", err)
|
|
||||||
} else {
|
|
||||||
groupName = g.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Printf(`Assuming the mox binary is in the current directory, and you will run mox under
|
fmt.Printf(`Assuming the mox binary is in the current directory, and you will run mox under
|
||||||
user name "mox", and the admin user is the current user, the following command
|
user name "mox", and the admin user is the current user, the following commands
|
||||||
sets the correct permissions:
|
set the correct permissions:
|
||||||
|
|
||||||
sudo useradd -d $PWD mox
|
sudo useradd -d $PWD mox
|
||||||
sudo chown %s:mox . mox
|
sudo chown $(id -nu):mox . mox
|
||||||
sudo chown -R mox:%s config data
|
sudo chown -R mox:$(id -ng) config data
|
||||||
sudo chmod 751 .
|
sudo chmod 751 .
|
||||||
sudo chmod 750 mox
|
sudo chmod 750 mox
|
||||||
sudo chmod -R u=rwX,g=rwX,o= config data
|
sudo chmod -R u=rwX,g=rwX,o= config data
|
||||||
sudo chmod g+s $(find . -type d)
|
sudo chmod g+s $(find . -type d)
|
||||||
|
|
||||||
`, userName, groupName)
|
`)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(`Assuming you will run mox under user name "mox", and the admin user is the
|
||||||
|
current user, the following commands set the correct permissions:
|
||||||
|
|
||||||
// For now, we only give service config instructions for linux.
|
sudo useradd -d $PWD mox
|
||||||
if runtime.GOOS == "linux" {
|
sudo chown $(id -nu):mox .
|
||||||
|
sudo chown -R mox:$(id -ng) config data
|
||||||
|
sudo chmod 751 .
|
||||||
|
sudo chmod -R u=rwX,g=rwX,o= config data
|
||||||
|
sudo chmod g+s $(find . -type d)
|
||||||
|
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, we only give service config instructions for linux when not running in docker.
|
||||||
|
if runtime.GOOS == "linux" && os.Getenv("MOX_DOCKER") == "" {
|
||||||
pwd, err := os.Getwd()
|
pwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("current working directory: %v", err)
|
log.Printf("current working directory: %v", err)
|
||||||
|
|
Loading…
Reference in a new issue