Poste.io
poste.io mail server, but with IP management and custom webmail plugins
Install / Use
/learn @dirtsimple/Poste.ioREADME
Enhanced Poste.io (IP Management & Roundcube Plugins)
poste.io is a pretty cool email server implementation for docker. But this image makes it cooler.
Specifically, it lets you:
- Use host-mode networking and still:
- Run things besides poste on the same server without localhost port conflicts
- Have multiple poste instances (e.g. dev and prod) running on the same server, listening on different IPs
- Restrict which IP addresses poste listens on, so non-poste mail servers can run on the same server
- Select which IP addresses poste sends mail from, on a domain-by-domain basis
- Install and use custom Roundcube plugins from the
/datavolume - Optionally use a persistent
DES_KEYfor Roundcube, to support plugins that store encrypted data
Contents
<!-- toc -->- Why Is This Image Needed?
- Basic Usage
- Managing Hostnames and IP Addresses
- Managing Sender IPs
- IPv6 Support
- Using Custom Roundcube Plugins
- Can I use these changes with poste.io's PRO version?
- Docker Tags
Why Is This Image Needed?
One of the big challenges of using the stock poste image with host-mode networking (the poste.io recommended configuration) is that it doesn't play well with other mail servers on the same machine. (Which makes it hard to e.g., have both a development and production instance, or to provide service to multiple clients on one machine.)
Specifically, in host mode networking, poste.io binds its outward-facing services to every IP address of the machine, and binds several of its internal services to localhost ports (6379, 11332-11334, 11380, 11381, and 13001), which can conflict with things besides mail servers or other poste.io instances.
As a result, poste.io not only doesn't play well with other mail servers (including other instances of itself), it also doesn't play well with being used on a server that does anything else. (It almost might as well not be a docker container at all, in such a setup!) And last, but not least, it sends email out on any old IP address as well, with no way to choose which IP you actually want to send things on.
So, this image fixes these issues by adding support for two environment variables and a configuration file, that let you not only control which IPs poste will listen on, but also which addresses poste will send mail on, optionally on a per-domain basis. (Plus, it patches poste.io's default configuration so that all its internal services use unix domain sockets inside the docker container, instead of tying up localhost ports on the main server.)
The first variable it adds is LISTEN_ON, which can be set to either a list of specific IP addresses to listen on, host (to listen only on addresses bound to the container's hostname), or * (for poste's default behavior of listening on every available interface).
The second variable is SEND_ON, which can also be set to a list of IP addresses, host, or *. (If unset or empty, it defaults to the value set in LISTEN_ON.) By default, mail will be sent from the first IP address in the resulting list, unless it's *, in which case the operating system will pick the IP. If there's only one sending IP, all mail will be sent from the default IP. Otherwise, a configuration file will be used to pick an IP address from the list, based on the domain the mail is being sent from.
Basic Usage
To use this image, just replace analogic/poste.io in your config with dirtsimple/poste.io. For example, you might use something like this as your docker-compose.yml, replacing mail.example.com with a suitable hostname for your installation:
version: "2.3"
services:
poste:
image: dirtsimple/poste.io
restart: always
network_mode: host # <-- a must-have for poste
# serve everything on `mail.example.com`, which will be the default HELO as well:
hostname: mail.example.com
volumes:
- ./data:/data
- /etc/localtime:/etc/localtime:ro
# ==== Optional settings below: you don't need any environment vars by default ====
environment:
# Whitespace-separated list of IP addresses to listen on. If this variable
# is set to "host" (which is also the default if it's empty or unset), the
# container will listen on all the IPs (v4 and v6) found in DNS or /etc/hosts
# for the container's hostname. Or it can be set to "*", to listen on ALL
# available addresses (the way the standard poste.io image does).
- "LISTEN_ON=1.2.3.4 5.6.7.8 90a:11:12::13"
# Whitespace-separated list of IP addresses mail can be sent from; the first
# one in the list will be the default. Like LISTEN_ON, it can be set to '*'
# for "any available address" or 'host' for "any IP (v4 or v6) attached to
# the container hostname". If the list expands to only one address, it
# will be used for all outgoing mail. Otherwise, data/outbound-hosts.yml
# is read to determine the outgoing IP for each domain, and the result is
# validated against this list. If this variable is empty or unset, it defaults
# to whatever LISTEN_ON was set to.
- "SEND_ON=9.10.11.12"
# Other standard poste.io vars can also be used, e.g. HTTPS_PORT, etc.
Take note of the following, however:
- You must configure the container with a fully-qualified hostname (e.g.
mail.example.comabove), with at least one IP address listed in the public DNS system - The hostname's IP addresses (or those listed in
LISTEN_ON) must be public IPs attached to the server hosting the container - The listening IPs must not have any other services listening on ports 25, 80, 110, 143, 443, 466, 587, 993, 995, or 4190. (Though you can change or disable some of those ports using poste.io's environment variables.)
- You should be using host-mode networking (
network_mode: hostas shown above), since in any other networking mode, this image will behave roughly the same as the originalanalogic/poste.ioimage, and have the same limitations and caveats. (Specifically, using any other networking mode means putting specific IP addresses intoLISTEN_ON,SEND_ON, oroutbound-hosts.ymlwill not do anything useful!) - By default, outgoing email to other mail servers will be sent via the first IP address found in
LISTEN_ONor returned by runninghostname -iin the container. If you need to override this behavior, configure the container withSEND_ONset to the specific IP address to be used, OR create a/data/outbound-hosts.ymlfile as described in Managing Sender IPs below. - Connections from a listening IP will be treated as if they are connections from 127.0.0.1 (because they are from the local host) unless you're using
LISTEN_ON=*mode. This disables certain host-specific spam checks (e.g. asn, fcrdns, karma/history, etc.), that would otherwise apply. This special behavior is not enabled for IPs that are used only for outgoing mail transmission; such IPs will be treated as normal unless you explicitly add them to your relay networks list.
Notice, by the way, that there are no port mappings used in this example, because the container uses host-mode networking and thus has direct access to all of the server's network interfaces. This means that the IP addresses to be used by the container must be explicitly defined (either by the DNS address(es) of the hostname, or by setting the LISTEN_ON variable to the exact IP addresses) so that the container doesn't take over every IP address on the server. (Unless that's what you want, in which case you can set LISTEN_ON to *.)
Managing Hostnames and IP Addresses
In the simplest cases, an installation of this image would only need to use one hostname and IP, and:
- The hostname would be set as the MX record of any domains to be hosted on the instance
- Reverse DNS for the IP would point to the hostname
- The default TLS certificate generated by the image would suffice
- Users would log into webmail and admin using the single, primary hostname
In more complex setups, you may wish to use multiple IPs or hostnames, for example to give each domain its own mail.somedomain.com website and/or MX, or to separate the sending reputation of different domains, while keeping to a single container. These scenarios can be done, but note that it is not possible to 100% hide the fact that all the domains are being served by the same container, as the TLS certificate used for both the web interface and SMTP will list all the hostnames sharing the container. (So if you need truly private instances, you will need to create separate containers.)
But, if all you need is to give users domain-specific hostnames, or separate sender IP reputation for different domains, you can accomplish that with a single shared container.
Vanity or Private-Label Logins
Let's say you want to give each domain its own mail.mydomain.com address for users to put into their mail clients, log into on the web, use as an MX entry, etc. You don't need multiple IP addresses to do this, just multiple hostnames. All that's needed is to:
- Have each vanity/private-label hostname resolve to one of the IP addresses the container listens on (e.g. by being a CNAME of the primary hostname)
- Add each such hostname to the "Alternative names" of your TLS certificate in the "Mailserver
Related Skills
node-connect
340.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
prose
340.2kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
frontend-design
84.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
sonoscli
340.2kControl Sonos speakers (discover/status/play/volume/group).
