diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30ed369 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +data +docker-compose.override.yml diff --git a/README.md b/README.md index e292b48..e266ede 100644 --- a/README.md +++ b/README.md @@ -1 +1,34 @@ -# imap-proxy +# Dovecot IMAP Proxy + +Dovecot deployment acting as a pure IMAP proxy: it listens on your hostname (e.g. `imap.example.com`) with its own SSL certificate, accepts and terminates the client connections (implicit TLS on 993, STARTTLS on 143), then connects to the destination server (e.g. `imap.example.net`) as if it were the client, over the destination's own SSL, and forwards the traffic bit-by-bit in both directions. + +## How it works +Dovecot's login proxy is used with a `static` passdb: any username is accepted, no password is verified locally (`nopassword`), and the login is forwarded (credentials included) to the destination host, which performs the real authentication. Once the remote login succeeds, dovecot becomes a dumb pipe between client and destination. No mail is ever stored locally. + +Because the password must be forwarded, clients have to use cleartext mechanisms (`PLAIN` / `LOGIN`); dovecot only allows them after TLS is negotiated, so nothing travels unencrypted. + +## Configuration +Copy `example.env` to `.env` and adjust: +- `SSL_CERT` / `SSL_KEY`: certificate and key for the hostname the proxy serves (e.g. Let's Encrypt live paths). +- `IMAP_EXPOSE` / `IMAPS_EXPOSE`: host bindings for ports 143/993. + +Copy `example.dovecot.conf` to `${DOVECOT_CONF}` (default `./data/dovecot.conf`) and set `host` in the `passdb static` block to your destination server. The destination certificate is verified against the system CA bundle (`ssl_client_ca_file`); use `ssl = any-cert` instead of `ssl = yes` if the destination has a self-signed certificate. + +## Usage +```sh +cp example.env .env +mkdir -p data && cp example.dovecot.conf data/dovecot.conf +$EDITOR .env data/dovecot.conf +docker compose up -d +``` + +## Testing +```sh +openssl s_client -connect imap.example.com:993 -quiet +# then login as an existing user on the destination server: +a LOGIN user@example.com password +b LIST "" "*" +``` + +## Notes +The `-root` image flavor is used so dovecot can read certificates that are only readable by root (as the Let's Encrypt live folder is); dovecot itself still drops privileges per-service. If your certificates are world-readable you can drop the `-root` suffix from `DOVECOT_VERSION`. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..caa3308 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +--- +services: + dovecot: + image: dovecot/dovecot:${DOVECOT_VERSION} + restart: unless-stopped + ports: + - ${IMAP_EXPOSE}:143 + - ${IMAPS_EXPOSE}:993 + volumes: + - ${DOVECOT_CONF}:/etc/dovecot/dovecot.conf:ro + - ${SSL_CERT}:/etc/dovecot/ssl/cert.pem:ro + - ${SSL_KEY}:/etc/dovecot/ssl/key.pem:ro diff --git a/example.dovecot.conf b/example.dovecot.conf new file mode 100644 index 0000000..e3965c2 --- /dev/null +++ b/example.dovecot.conf @@ -0,0 +1,40 @@ +# Dovecot IMAP proxy configuration (dovecot 2.4 syntax) +# +# Terminates SSL/TLS for the local hostname (e.g. imap.example.com) and +# proxies every login, credentials included, to the destination server +# (e.g. imap.example.net) over its own SSL/TLS connection. After the login +# succeeds, dovecot forwards the connection bit-by-bit in both directions. + +dovecot_config_version = 2.4.0 +dovecot_storage_version = 2.4.0 + +protocols = imap +log_path = /dev/stdout + +ssl = yes +ssl_server_cert_file = /etc/dovecot/ssl/cert.pem +ssl_server_key_file = /etc/dovecot/ssl/key.pem +ssl_min_protocol = TLSv1.2 +ssl_client_ca_file = /etc/ssl/certs/ca-certificates.crt + +auth_mechanisms = plain login + +service imap-login { + inet_listener imap { + port = 143 + } + inet_listener imaps { + port = 993 + ssl = yes + } +} + +passdb static { + fields { + nopassword = yes + proxy = yes + host = imap.example.net + port = 993 + ssl = yes + } +} diff --git a/example.env b/example.env new file mode 100644 index 0000000..fedd384 --- /dev/null +++ b/example.env @@ -0,0 +1,9 @@ +# Dovecot +DOVECOT_VERSION=2.4.4-root +DOVECOT_CONF=./data/dovecot.conf +IMAP_EXPOSE=143 +IMAPS_EXPOSE=993 + +# SSL certificates +SSL_CERT=/etc/letsencrypt/live/imap.example.com/fullchain.pem +SSL_KEY=/etc/letsencrypt/live/imap.example.com/privkey.pem