Compare commits

...

28 commits

Author SHA1 Message Date
PJ Eby
697e2a7039 Update push actions 2023-01-22 04:43:43 -05:00
PJ Eby
488a3d202c Update unstable tag to upstream 2.3.10 2023-01-22 04:39:31 -05:00
PJ Eby
e303e83e7b Fix Let's Encrypt renewals on 2.3.x 2023-01-22 03:47:45 -05:00
PJ Eby
0501a5c984 2.3.x compatibility (untested/unstable) 2022-02-04 20:44:40 -05:00
PJ Eby
2371f9167f Auto-update README on Docker Hub 2021-08-04 18:48:16 -04:00
PJ Eby
1f927c6300 Match entire tag during build 2021-08-04 17:22:58 -04:00
PJ Eby
2e6f102dce Fix build tag processing 2021-08-04 17:18:05 -04:00
PJ Eby
0fdc892716 Show correct redis URLs in log output 2021-08-04 17:12:30 -04:00
PJ Eby
8b82c06853 Handle tagged builds as well as unstable 2021-08-04 17:11:39 -04:00
PJ Eby
0ad79bf22e Add github actions build 2021-08-04 16:35:01 -04:00
PJ Eby
97f7da4108 Ensure cron errors can be sent 2021-08-04 13:55:20 -04:00
PJ Eby
e4c7539106 Update to 2.2.32 upstream 2021-05-31 16:06:26 -04:00
PJ Eby
825352a131 Fix #13 (ham/spam reporting issues w/sieve script) 2021-05-31 15:46:42 -04:00
PJ Eby
d20b2b481f Fix #12 - Haraka needs [] for IPv6 listen ports 2021-05-30 13:12:11 -04:00
PJ Eby
019a793c8e Update build to 2.2.31 2021-05-02 11:38:33 -04:00
PJ Eby
84cb77d234 Fix #9 - redis-cli needs socket arg 2021-05-02 11:03:09 -04:00
PJ Eby
3f79ad20bc Update build to 2.2.27 2021-01-22 12:34:51 -05:00
PJ Eby
5657070674 Fix recursive log rotation for roundcube 2020-12-07 15:59:41 -05:00
PJ Eby
5187d6272a Update build to 2.2.26 2020-12-07 15:43:06 -05:00
PJ Eby
280c3d59e1 Update build to 2.2.23 2020-10-31 13:35:02 -04:00
PJ Eby
f7312dbb06 Update build to 2.2.20 2020-06-03 13:15:30 -04:00
PJ Eby
3e3d73ef8a Patch health checks to do the right thing 2020-04-26 17:11:58 -04:00
PJ Eby
4b6a1839fb Fake 127.0.0.1 for connections from listening IPs 2020-04-15 20:24:48 -04:00
PJ Eby
333667db8c Updates for 2.2.19 2020-04-15 17:18:28 -04:00
PJ Eby
b310e9b3de Support upstream version selection w/UPSTREAM arg 2020-04-15 13:50:18 -04:00
PJ Eby
bee74835b5 Document build tagging 2020-04-06 03:29:33 -04:00
PJ Eby
422e76f0c2 Configure webmail filter to connect properly 2020-04-06 03:28:33 -04:00
PJ Eby
a935d5cc58 Support custom Roundcube plugins under /data 2020-04-03 19:38:05 -04:00
7 changed files with 286 additions and 34 deletions

53
.github/workflows/docker-hub.yml vendored Normal file
View file

@ -0,0 +1,53 @@
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,4 +1,5 @@
FROM analogic/poste.io:2.2.2
ARG UPSTREAM=2.3.10
FROM analogic/poste.io:$UPSTREAM
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

@ -1,6 +1,38 @@
## A Fully-Virtual, Host-Mode Version of Poste.io
## Enhanced Poste.io (IP Management & Roundcube Plugins)
[poste.io](https://poste.io) is a pretty cool email server implementation for docker. Unfortunately, when used with host-mode networking (the poste.io recommended configuration) 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.)
[poste.io](https://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](#managing-sender-ips)
* Install and use [custom Roundcube plugins](#using-custom-roundcube-plugins) from the `/data` volume
* Optionally [use a persistent `DES_KEY`](#the-des_key-variable) for Roundcube, to support plugins that store encrypted data
#### Contents
<!-- toc -->
- [Why Is This Image Needed?](#why-is-this-image-needed)
- [Basic Usage](#basic-usage)
- [Managing Hostnames and IP Addresses](#managing-hostnames-and-ip-addresses)
* [Vanity or Private-Label Logins](#vanity-or-private-label-logins)
* [Separate IPs for Different Domains](#separate-ips-for-different-domains)
- [Managing Sender IPs](#managing-sender-ips)
- [IPv6 Support](#ipv6-support)
- [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 -->
### 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.
@ -62,6 +94,7 @@ 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 `*`.)
@ -122,8 +155,29 @@ In addition, for best deliverability, you should also:
And of course, you will need to update all of this information whenever any of the configuration changes! If you control DNS for all the relevant domains yourself, you may be able to generate this file automatically from your domain list and DNS: e.g. by looking up MX records and their corresponding addresses. (But you shouldn't trust the DNS for domains you don't control, as that would effectively let your clients pick their own sending IPs.)
### IPv6 Support
This image supports listening on IPv6 addresses, and in principle allows sending mail via them as well. However, since relatively few mailservers are actually configured to receive mail via IPv6, we don't recommend actually *using* IPv6 addresses for outgoing mail, unless your server will be communicating exclusively with other mailservers that support IPv6. (You should also test to make sure IPv6 sending actually works correctly in your networking environment, and to see what happens when you try sending outbound IPv6 mail to an IPv4-only server.)
### Using Custom Roundcube Plugins
On startup, this image will automatically install, activate, and attempt to run SQL initialization for any Roundcube plugins found as subdirectories of `/data/roundcube-plugins`. Only plugins without dependencies (other than those already installed with Roundcube) will work correctly. (Plugins should generally be installed with world-readable permissions, but *not* owned or writable by the www-data user or group, so that file-writing exploits don't become remote execution exploits.)
If you need to force a re-run of a plugin's setup SQL, you can remove its name from the `/data/roundcube/installed-plugins` file, then restart the container. You can uninstall a plugin by stopping the container, removing it from the `/data/roundcube-plugins` directory, and then starting the container again. (Any SQL changes made by the plugin will remain in place.)
This feature is still quite experimental (and has only been tested with one plugin so far), so be sure to experiment with it on a development instance before using it in production.
#### The DES_KEY Variable
Some plugins (such as [ident_switch](https://bitbucket.org/BoresExpress/ident_switch)) may need to store encrypted data in the roundcube database. By default, poste generates a new encryption key on every container start, rendering such data unable to be decrypted. To work around this issue, you can set a `DES_KEY` environment variable containing a string of exactly 48 random hex characters. The given string will be used across restarts, allowing encrypted data stored in a previous session to be decrypted correctly. You can generate a suitable key using `openssl rand -hex 24` (which will generate 24 random bytes = 48 hex digits). The string used must be *exactly* 48 hex digits, or else the container's webmail service will silently cease to function.
### Can I use these changes with poste.io's PRO version?
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 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 instead.
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,13 +2,21 @@
# Given a variable name and setting, get the matching IP addresses as a comma-delimited list
function ip_list() {
local -n ips=$1
local -n ips=$1 v6=${1}_b
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`
@ -27,6 +35,11 @@ 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
@ -36,9 +49,8 @@ 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"
IFS=, read -ra ipaddrs <<<"$listen_b"
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
@ -52,8 +64,10 @@ fi
# === Haraka needs each IP address to be listed explicitly, unless you're using wildcards ===
if [[ $listen != *'*'* ]]; then
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
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
fi
# Our Haraka sender-ip control plugin will validate outgoing IPs against the
@ -62,3 +76,8 @@ 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

@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -e
PLUGIN_LIST=/data/roundcube/installed-plugins
PLUGINS_DIR=/data/roundcube-plugins
[[ -f "$PLUGIN_LIST" ]] || touch "$PLUGIN_LIST" # plugin list must exist
[[ -d "$PLUGINS_DIR" ]] || exit 0 # but it can be empty if no plugins
cd /opt/www/webmail
log() { echo -e "\t\t\033[1;33m* $*\033[0m"; }
# Remove any plugin symlinks left over since last container rebuild
for plugin in plugins/*; do [[ ! -L "$plugin" ]] || rm "$plugin"; done
# Link and possibly-install plugins
for plugin_path in "$PLUGINS_DIR"/*; do
[[ -d $plugin_path ]] || continue # not a plugin
plugin=${plugin_path##*/}
# Remove any existing plugin of this name that's not a symlink
if [[ -d plugins/"$plugin" && ! -L plugins/"$plugin" ]]; then
# We must overwrite existing plugin dir, if found
log "Removing pre-installed version of $plugin plugin"
rm -rf plugins/$plugin
fi
# Symlink plugin to the plugins dir
log "Mounting plugin $plugin"
ln -sfn "$plugin_path" plugins/"$plugin"
if ! grep -q "^$plugin\$" "$PLUGIN_LIST"; then
log "Installing new roundcube plugin $plugin"
# Not in installed plugin list; check for SQL
sqldir=$(
php -r 'echo(
@json_decode(
file_get_contents("plugins/'"$plugin"'/composer.json")
)->extra->roundcube->{"sql-dir"}
);'
)
if [[ $sqldir ]]; then
# Got SQL
log "Running SQL for $plugin"
vendor/bin/rcubeinitdb.sh --package="$plugin" --dir="$plugin_path/$sqldir" || true # ignore errors
fi
# Record installation complete
echo "$plugin" >>"$PLUGIN_LIST"
fi
done

View file

@ -0,0 +1,21 @@
'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,9 +14,10 @@
# 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; sed -i -e "$sed" "$@"; }
edit() { local sed; ::block sed-dsl; if (($#)); then sed -i -e "$sed" "$@"; fi; }
sed-dsl() { sed."$@"; }
sed.sub() { sed+="s~$1~$2~${3-}"$'\n'; }
sed.del() { sed+="${1+/$1/}d"$'\n'; }
@ -29,6 +30,15 @@ __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; {{
@ -36,10 +46,21 @@ shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias +=
+ append ""; {{
- "\$config['default_host'] = 'ssl://' . gethostname();"
- "\$config['smtp_server'] = 'tls://' . gethostname() . ':587';"
- "\$config['managesieve_port'] = 4190;"
- "\$config['managesieve_host'] = gethostname();"
- "\$config['managesieve_usetls'] = true;"
}}
}}
~ edit /opt/admin/src/AppBundle/CommandInternal/DeliverQuarantineCommand.php; {{
~ 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 ;
{{
# Quarantine "deliver" / deliver:quarantine should send to host, not localhost
- sub "\['msmtp', '-f'.*" "['msmtp', '--host', gethostname(), '-f', \$meta['from']];"
}}
@ -55,6 +76,9 @@ 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'
}}
@ -93,13 +117,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; {{
~ edit /opt/admin/src/AppBundle/Server/System[.]php /opt/admin/src/Base/Server/System[.]php; {{
- sub "rspamc stat" \
"rspamc -h $rspam_web stat"
}}
~ edit /etc/dovecot/sieve/report-{spam,ham}.sieve; {{
- sub '"rspamc" \[' \
'"rspamc" ["-h" "'"$rspam_web"'" '
'"rspamc" ["--connect='"$rspam_web"'", '
}}
# Disable dovecot quota service on localhost
@ -117,41 +141,33 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
"socket.connect('$quota');"
}}
# 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);});'
}}
# 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 /opt/haraka-smtp/config/http.ini; {{
- sub 'listen=127.0.0.1:11380' "listen=$haraka_smtp_web"
- sub 'listen=127.0.0.1:11380' "listen=$haraka_smtp_web:777"
}}
~ edit /opt/haraka-submission/config/http.ini; {{
- sub 'listen=127.0.0.1:11381' "listen=$haraka_sub_web"
- sub 'listen=127.0.0.1:11381' "listen=$haraka_sub_web:777"
}}
# Have haraka talk to rspamd via unix socket
~ edit /usr/lib/node_modules/Haraka/node_modules/haraka-plugin-rspamd/index.js; {{
- del 'port: plugin'
- sub 'host: plugin.*,' \
"socketPath: '$rspam',"
~ edit /opt/haraka-{smtp,submission}/config/rspamd.ini; {{
- sub '^host.*=.*$' "unix_socket = $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"
- append "" "unixsocket $redis" "unixsocketperm 777" # can be removed as of 2.3.7
}}
~ edit /etc/rspamd/local.d/{redis,statistic}.conf; {{
@ -159,10 +175,43 @@ haraka_sub_web=$sockdir/haraka/web-11381.sock
'servers = "'"$redis"'";'
}}
~ edit /opt/admin/src/AppBundle/Resources/config/services.yml; {{
~ 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; {{
- sub '^ Predis\\Client: .*$' \
' Predis\\Client: { arguments: [ "unix:'"$redis"'" ] }'
# The above change won't take effect unless the service cache is cleared:
rm -rf /opt/admin/var/cache/prod
}}
# === 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'
}}
}}
# Autoload roundcube plugins from /data/roundcube/installed-plugins
~ edit /opt/www/webmail/config/config.inc.php; {{
+ append ""; {{
- 'foreach ( explode("\\n", file_get_contents("/data/roundcube/installed-plugins")) as $line ) {'
- ' $line = trim($line);'
- ' if ( "" === $line || substr($line,0,1) === "#" || ! is_dir("plugins/$line")) continue;'
- ' $config["plugins"][] = $line;'
- '}'
}}
}}