Compare commits
28 commits
2.2.2-0.2.
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
697e2a7039 | ||
![]() |
488a3d202c | ||
![]() |
e303e83e7b | ||
![]() |
0501a5c984 | ||
![]() |
2371f9167f | ||
![]() |
1f927c6300 | ||
![]() |
2e6f102dce | ||
![]() |
0fdc892716 | ||
![]() |
8b82c06853 | ||
![]() |
0ad79bf22e | ||
![]() |
97f7da4108 | ||
![]() |
e4c7539106 | ||
![]() |
825352a131 | ||
![]() |
d20b2b481f | ||
![]() |
019a793c8e | ||
![]() |
84cb77d234 | ||
![]() |
3f79ad20bc | ||
![]() |
5657070674 | ||
![]() |
5187d6272a | ||
![]() |
280c3d59e1 | ||
![]() |
f7312dbb06 | ||
![]() |
3e3d73ef8a | ||
![]() |
4b6a1839fb | ||
![]() |
333667db8c | ||
![]() |
b310e9b3de | ||
![]() |
bee74835b5 | ||
![]() |
422e76f0c2 | ||
![]() |
a935d5cc58 |
7 changed files with 286 additions and 34 deletions
53
.github/workflows/docker-hub.yml
vendored
Normal file
53
.github/workflows/docker-hub.yml
vendored
Normal 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 }}
|
|
@ -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
|
||||
|
|
62
README.md
62
README.md
|
@ -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.)
|
|
@ -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
|
||||
|
|
55
files/etc/cont-init.d/26-roundcube-plugins.sh
Normal file
55
files/etc/cont-init.d/26-roundcube-plugins.sh
Normal 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
|
21
files/opt/haraka-smtp/plugins/inbound_ips.js
Normal file
21
files/opt/haraka-smtp/plugins/inbound_ips.js
Normal 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();
|
||||
}
|
|
@ -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;'
|
||||
- '}'
|
||||
}}
|
||||
}}
|
Loading…
Add table
Reference in a new issue