Compare commits

..

No commits in common. "master" and "2.2.2-0.3.1" have entirely different histories.

6 changed files with 33 additions and 161 deletions

View file

@ -1,53 +0,0 @@
name: Build and Push to Docker Hub
on:
push:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Calculate Tags
env:
ref: ${{ github.ref }}
repo: ${{ github.repository }}
run: |
ref=${ref##*/}
if [[ $ref == master ]]; then
tags=$repo:unstable
elif [[ $ref =~ ^([0-9.]+)-((([0-9]+[.])[0-9]+[.])([.][0-9+])*)$ ]]; then
upstream=${BASH_REMATCH[1]}
minor=${BASH_REMATCH[3]}x
major=${BASH_REMATCH[4]}x
tags=$repo:latest,$repo:$ref,$repo:$upstream-$minor,$repo:$upstream-$major,$repo:$upstream
else
echo "Bad tag: $ref"
exit 1
fi
echo "$tags"
echo "build_tags=$tags" >> $GITHUB_ENV
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- name: Build and push
id: build
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: ${{ env.build_tags }}
- name: Update repo description
uses: peter-evans/dockerhub-description@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
repository: ${{ github.repository }}

View file

@ -1,5 +1,4 @@
ARG UPSTREAM=2.3.10
FROM analogic/poste.io:$UPSTREAM
FROM analogic/poste.io:2.2.2
RUN apt-get update && apt-get install less # 'less' is Useful for debugging
# Default to listening only on IPs bound to the container hostname

View file

@ -26,7 +26,6 @@ Specifically, it lets you:
- [Using Custom Roundcube Plugins](#using-custom-roundcube-plugins)
* [The DES_KEY Variable](#the-des_key-variable)
- [Can I use these changes with poste.io's PRO version?](#can-i-use-these-changes-with-posteios-pro-version)
- [Docker Tags](#docker-tags)
<!-- tocstop -->
@ -94,7 +93,6 @@ Take note of the following, however:
* 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: host` as shown above), since in any other networking mode, this image will behave roughly the same as the original `analogic/poste.io` image, and have the same limitations and caveats. (Specifically, using any other networking mode means putting specific IP addresses into `LISTEN_ON`, `SEND_ON`, or `outbound-hosts.yml` will not do anything useful!)
* By default, outgoing email to other mail servers will be sent via the first IP address found in `LISTEN_ON` or returned by running `hostname -i` in the container. If you need to override this behavior, configure the container with `SEND_ON` set to the specific IP address to be used, OR create a `/data/outbound-hosts.yml` file as described in [Managing Sender IPs](#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 `*`.)
@ -175,9 +173,4 @@ Some plugins (such as [ident_switch](https://bitbucket.org/BoresExpress/ident_sw
I don't know, but you can find out by cloning this repo, changing the `FROM` in the Dockerfile, and trying to run the resulting build. It *might* work, since the main difference between the two versions is some admin interface code left out of the free version. But if that left-out code contains hardcoded or implicit references to localhost or 127.0.0.1, then those admin features will probably break, as they won't have been patched to use unix-domain sockets (or the container's hostname) instead.
If they do break, and you can figure out what to patch (most likely, PHP code in `/opt/admin/src/ProBundle/`), let me know. (Or if it works fine, I'd love to know that, too!)
### Docker Tags
Apart from `latest`, and `unstable`, current versions of this image on docker hub are tagged as a combination of the upstream version and a version number for this image's additions. For example, `2.2.2-0.3.1` is the `0.3.1` revision of upstream poste's `2.2.2` tag, if you need to pin a specific revision. You can also just use the upstream version (e.g. `2.2.2`) to get the latest patches for that upstream version, or `latest` to get the most-recent stable version. The `unstable` tag always refers to the current `master` branch from github.
If they do break, and you can figure out what to patch (most likely, PHP code in `/opt/admin/src/ProBundle/`), let me know. (Or if it works fine, I'd love to know that, too!)

View file

@ -2,21 +2,13 @@
# Given a variable name and setting, get the matching IP addresses as a comma-delimited list
function ip_list() {
local -n ips=$1 v6=${1}_b
local -n ips=$1
case $2 in
host) ips=$(hostname -i) ;;
'*') ips='* ::' ;;
*) read -ra ips <<<"$2"; ips=("${ips[*]}") ;; # trim/normalize whitespace
esac
ips="${ips// /,}"; ips=${ips:-*,::} # handle empty list
# Create a bracketed version for configs that need [host]:port for IPv6 addrs
local addr i
IFS=, read -ra addr <<<"$ips"
for i in "${!addr[@]}"; do
case ${addr[i]} in *:*) addr[i]="[${addr[i]}]" ;; esac
done
v6=("${addr[*]}"); v6="${v6// /,}"
}
# Expand LISTEN_ON and SEND_ON into comma-delimited IP lists in `listen` and `send`
@ -35,11 +27,6 @@ bindhost=$(hostname)
# We only care about the hostname for connnecting to the submission port
sub 'submission_host = .*:587$' "submission_host = $bindhost:587" /etc/dovecot/conf.d/15-lda.conf
sub '^host.*' "host $bindhost" /etc/msmtprc
# Admin emails should go to the bindhost as well
sub "%env(MAILER_DSN)%" "smtp://$bindhost:25?verify_peer=0" /opt/admin/config/packages/mailer.yaml
sub "MAILER_DSN=.*" "MAILER_DSN=smtp://$bindhost:25?verify_peer=0" /opt/admin/.env
if [[ "$LISTEN_ON" == host ]]; then
# No IPs given, just use the hostname
@ -49,8 +36,9 @@ else
# We have explicit listening IPs (or wildcards): give them to dovecot and nginx
sub '^#\?listen = .*' "listen = ${listen}" /etc/dovecot/dovecot.conf
IFS=, read -ra ipaddrs <<<"$listen_b"
IFS=, read -ra ipaddrs <<<"$listen"
for addr in "${ipaddrs[@]}"; do
if [[ "$addr" == *:* ]]; then addr="[${addr}]"; fi # nginx needs IPv6 addresses to be in '[]'
# Add listen lines above the default ones, for the specified address, port and options
ins "__HOST__:$HTTP_PORT" " listen $addr:$HTTP_PORT;" /etc/nginx/sites-enabled/administration
ins "__HOST__:$HTTPS_PORT" " listen $addr:$HTTPS_PORT ssl;" /etc/nginx/sites-enabled/administration
@ -64,10 +52,8 @@ fi
# === Haraka needs each IP address to be listed explicitly, unless you're using wildcards ===
if [[ $listen != *'*'* ]]; then
sub '^listen=.*:25$' "listen=${listen_b//,/:25,}:25" /opt/haraka-smtp/config/smtp.ini
sub '^listen=.*:587,.*:465$' "listen=${listen_b//,/:587,}:587,${listen_b//,/:465,}:465" /opt/haraka-submission/config/smtp.ini
else
listen=::0
sub '^listen=.*:25$' "listen=${listen//,/:25,}:25" /opt/haraka-smtp/config/smtp.ini
sub '^listen=.*:587,.*:465$' "listen=${listen//,/:587,}:587,${listen//,/:465,}:465" /opt/haraka-submission/config/smtp.ini
fi
# Our Haraka sender-ip control plugin will validate outgoing IPs against the
@ -76,8 +62,3 @@ fi
echo "$send" >/opt/haraka-submission/config/my-ips
echo "$send" >/opt/haraka-smtp/config/my-ips
# Our inbound IP plugin will translate local connections to 127.0.0.1
echo "$listen" >/opt/haraka-submission/config/listen-ips
echo "$listen" >/opt/haraka-smtp/config/listen-ips

View file

@ -1,21 +0,0 @@
'use strict';
/*****
This plugin detects local connections from listening IPs, and changes the remote
IP to 127.0.0.1, simulating a local connection. Many of poste.io's plugins
have 127.0.0.1 hardcoded for special handling that otherwise might not be applied
when using this image.
*****/
const listening_ips = require("haraka-config").get("listen-ips").trim().split(/\s*,\s*/);
const is_local = listening_ips.reduce((map, addr)=>{map[addr]=true; return map;}, {});
exports.hook_connect_init = function(next, connection) {
if ( is_local[connection.remote.ip] ) {
this.logdebug(`localhost connection from ${connection.remote.ip}`);
connection.remote.ip = '127.0.0.1';
}
return next();
}

View file

@ -14,10 +14,9 @@
# loopback interface.
set -eu # fail on any errors or undefined variables
shopt -s nullglob
# A tiny DSL for editing files with sed: `~ edit files...; {{ commands }}`
edit() { local sed; ::block sed-dsl; if (($#)); then sed -i -e "$sed" "$@"; fi; }
edit() { local sed; ::block sed-dsl; sed -i -e "$sed" "$@"; }
sed-dsl() { sed."$@"; }
sed.sub() { sed+="s~$1~$2~${3-}"$'\n'; }
sed.del() { sed+="${1+/$1/}d"$'\n'; }
@ -30,15 +29,6 @@ __sedline() { sed+="${*/#/\\$'\n'}"; }
shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias +='{ ::__;::(){ ((!$#))||{ shift;"${__dsl__[@]-::no-dsl}" ' ~='{ ::__;::(){ ((!$#))||{ shift; ' -='"${__dsl__[@]-::no-dsl}" ' '{{=return;return;};__blk__=;set -- "${__blarg__[@]:1}"; ' '}}=};__:: 0 "$@";}';::block(){ ((!$#))||local __dsl__=("$@");${__blk__:+::};};__bsp__=0;::__(){ __bstk__[__bsp__++]="${__blk__:+__blk__=1;$(declare -f ::)}";};__::(){ local __blarg__=("$@");__blk__=1;:: "$@"||set -- $?;__blk__=;local REPLY;${__bstk__[--__bsp__]:+eval "${__bstk__[__bsp__]}"}||:;return $1;}
# === Upstream bug fixes ===
# Remove this when 2.3.x is stable
~ edit opt/admin/src/AppBundle/Resources/views/Box/edit.html[.]twig; {{
# Fix typo
- sub "refereneId" "referenceId"
}}
# === Restrict public ports to the container hostname IP ===
~ edit /opt/www/webmail/config/config.inc.php; {{
@ -52,15 +42,7 @@ shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias +=
}}
}}
~ edit /healthcheck/nginx.sh; {{
- sub "http://127.0.0.1" '"http://$(hostname)"'
}}
~ edit \
/opt/admin/src/AppBundle/CommandInternal/DeliverQuarantineCommand[.]php \
/opt/admin/src/Base/CommandInternal/DeliverQuarantineCommand[.]php ;
{{
~ edit /opt/admin/src/AppBundle/CommandInternal/DeliverQuarantineCommand.php; {{
# Quarantine "deliver" / deliver:quarantine should send to host, not localhost
- sub "\['msmtp', '-f'.*" "['msmtp', '--host', gethostname(), '-f', \$meta['from']];"
}}
@ -76,9 +58,6 @@ shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias +=
}}
~ edit /opt/haraka-{smtp,submission}/config/plugins; {{
# Fake remote IP to 127.0.0.1 when connection is from localhost
- after "status_http" \
"inbound_ips"
# Add our outbound IP routing plugin
- append 'outbound_ips'
}}
@ -117,13 +96,13 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
# The rspamc command needs to reference the web socket explicitly
~ edit /opt/admin/src/AppBundle/Server/System[.]php /opt/admin/src/Base/Server/System[.]php; {{
~ edit /opt/admin/src/AppBundle/Server/System.php; {{
- sub "rspamc stat" \
"rspamc -h $rspam_web stat"
}}
~ edit /etc/dovecot/sieve/report-{spam,ham}.sieve; {{
- sub '"rspamc" \[' \
'"rspamc" ["--connect='"$rspam_web"'", '
'"rspamc" ["-h" "'"$rspam_web"'" '
}}
# Disable dovecot quota service on localhost
@ -141,33 +120,41 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
"socket.connect('$quota');"
}}
# Haraka logs should show the redis socket
~ edit /usr/lib/node_modules/Haraka/node_modules/haraka-plugin-redis/index.js; {{
- sub 'redis://\${opts.host}:\${opts.port}' \
'redis://${opts.path}'
}}
# Haraka web servers need to listen on unix sockets
~ edit /usr/lib/node_modules/Haraka/server.js; {{
- sub 'Server.get_listen_addrs(Server.http.cfg, 80)' \
'[Server.http.cfg.listen]'
+ range '^Server.setup_http_listeners' '^}$'; {{
- sub 'const hp = .*' \
'const hp = [null, null, host_port];'
- sub 'Server.http.server.listen.*$' \
'!fs.existsSync(host_port)||fs.unlinkSync(host_port); Server.http.server.listen(host_port, function(){fs.chmodSync(host_port, 0o777);});'
}}
}}
~ edit /opt/haraka-smtp/config/http.ini; {{
- sub 'listen=127.0.0.1:11380' "listen=$haraka_smtp_web:777"
- sub 'listen=127.0.0.1:11380' "listen=$haraka_smtp_web"
}}
~ edit /opt/haraka-submission/config/http.ini; {{
- sub 'listen=127.0.0.1:11381' "listen=$haraka_sub_web:777"
- sub 'listen=127.0.0.1:11381' "listen=$haraka_sub_web"
}}
# Have haraka talk to rspamd via unix socket
~ edit /opt/haraka-{smtp,submission}/config/rspamd.ini; {{
- sub '^host.*=.*$' "unix_socket = $rspam"
~ edit /usr/lib/node_modules/Haraka/node_modules/haraka-plugin-rspamd/index.js; {{
- del 'port: plugin'
- sub 'host: plugin.*,' \
"socketPath: '$rspam',"
}}
# Configure redis to listen on a unix socket, and rspamd+admin to connect there
~ edit /etc/redis/redis.conf; {{
- sub "^port 6379" "port 0" # disable the localhost port
- append "" "unixsocket $redis" "unixsocketperm 777" # can be removed as of 2.3.7
- append "" "unixsocket $redis" "unixsocketperm 777"
}}
~ edit /etc/rspamd/local.d/{redis,statistic}.conf; {{
@ -175,19 +162,7 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
'servers = "'"$redis"'";'
}}
~ edit /healthcheck/redis.sh; {{
- sub '-h "127.0.0.1"' "-s '$redis'";
}}
~ edit /bin/clear[-]idle-connections; {{ # can be removed as of 2.3.7
- sub "redis-cli'" "redis-cli', '-s', '$redis'"
}}
~ edit /bin/poste-redis-statistics; {{
- sub "redis-cli" "redis-cli -s '$redis'"
}}
~ edit /opt/admin/src/AppBundle/Resources/config/services[.]yml /opt/admin/config/services_base[.]yaml; {{
~ edit /opt/admin/src/AppBundle/Resources/config/services.yml; {{
- sub '^ Predis\\Client: .*$' \
' Predis\\Client: { arguments: [ "unix:'"$redis"'" ] }'
@ -198,10 +173,8 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
# === Support Roundcube plugins and persistent encryption key
# Load 48-digit hex des_key from DES_KEY
~ edit /etc/cont-init.d/{20-apply-server-config,97[-]randoms}; {{
+ range 'roundcube' 'preg_replace'; {{
- sub '[$]key = bin2hex' '$key = getenv("DES_KEY") ?: bin2hex'
}}
~ edit /etc/cont-init.d/20-apply-server-config; {{
- sub '[$]key = bin2hex' '$key = getenv("DES_KEY") ?: bin2hex'
}}
# Autoload roundcube plugins from /data/roundcube/installed-plugins