mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2024-01-19 02:48:50 +00:00
Merge pull request #1601 from aendeavor/master
- outsourced badges-links in `README.md` to clean this section up - refactored `.travis.yml` with Prettier and added **shellcheck capabilities** - refactored Makefile to make it verbose where it should be and added a **shellcheck target** - refactored all scripts in `target/` (except `start-mailserver.sh`) - added **coding style guidelines** to `CONTRIBUTING.md` so everyone can and must adhere to consistent guidelines - `start-mailserver.sh` had to be touched due to renaming of functions - added a table of contents to Markdown documents
This commit is contained in:
commit
ae6f41e303
32
.travis.yml
32
.travis.yml
|
@ -1,23 +1,41 @@
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
- donttestme
|
- donttestme
|
||||||
|
|
||||||
language: bash
|
language: bash
|
||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- HADOLINT_VERSION=1.17.1
|
- HADOLINT_VERSION=1.17.1
|
||||||
|
- SHELLCHECK_VERSION=0.7.1
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- xz-utils
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo curl -L https://github.com/hadolint/hadolint/releases/download/v$HADOLINT_VERSION/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint
|
- sudo curl -L https://github.com/hadolint/hadolint/releases/download/v$HADOLINT_VERSION/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint
|
||||||
- sudo chmod +rx /usr/local/bin/hadolint
|
- sudo chmod +rx /usr/local/bin/hadolint
|
||||||
|
- sudo wget -qO- "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar -xJv
|
||||||
|
- sudo cp "shellcheck-v${SHELLCHECK_VERSION}/shellcheck" /usr/bin/
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- make lint
|
- make lint
|
||||||
- travis_retry travis_wait make build
|
- travis_retry travis_wait make build
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make generate-accounts run generate-accounts-after-run fixtures tests
|
- make shellcheck
|
||||||
|
- make generate-accounts run generate-accounts-after-run fixtures tests
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
- make clean
|
- make clean
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww=
|
secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww=
|
||||||
|
|
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## 6.2.0+
|
## 6.2.0+
|
||||||
|
|
||||||
see https://github.com/tomav/docker-mailserver/releases
|
* see <https://github.com/tomav/docker-mailserver/releases>
|
||||||
|
|
||||||
## 6.1.0
|
## 6.1.0
|
||||||
|
|
||||||
|
@ -56,93 +56,114 @@ see https://github.com/tomav/docker-mailserver/releases
|
||||||
Fixes to setup where made for deletion and addition.
|
Fixes to setup where made for deletion and addition.
|
||||||
|
|
||||||
## 5.7.0
|
## 5.7.0
|
||||||
|
|
||||||
* Delmailuser (#878)
|
* Delmailuser (#878)
|
||||||
You can now delete users and the mailbox
|
You can now delete users and the mailbox
|
||||||
* Backup config folder while testing (#901)
|
* Backup config folder while testing (#901)
|
||||||
* added error messages to letsencrypt on startup (#898)
|
* added error messages to letsencrypt on startup (#898)
|
||||||
|
|
||||||
## 5.6.1
|
## 5.6.1
|
||||||
|
|
||||||
* Update docker-configomat (#680)
|
* Update docker-configomat (#680)
|
||||||
|
|
||||||
## 5.6.0
|
## 5.6.0
|
||||||
|
|
||||||
* Generate SRS secret on first run and store it (#891)
|
* Generate SRS secret on first run and store it (#891)
|
||||||
The secret will be constant afther this.
|
The secret will be constant afther this.
|
||||||
|
|
||||||
## 5.5.0
|
## 5.5.0
|
||||||
|
|
||||||
* Add /var/lib/dovecot to mailstate persistence (#887)
|
* Add /var/lib/dovecot to mailstate persistence (#887)
|
||||||
|
|
||||||
## 5.4.0
|
## 5.4.0
|
||||||
|
|
||||||
* Allow configuring SRS secrets using the environment (#885)
|
* Allow configuring SRS secrets using the environment (#885)
|
||||||
You can set your own secret with the env SRS_SECRET
|
You can set your own secret with the env SRS_SECRET
|
||||||
By default it uses the docker generated secret
|
By default it uses the docker generated secret
|
||||||
* Removed unneeded check for Let's encrypt cert.pem (#843)
|
* Removed unneeded check for Let's encrypt cert.pem (#843)
|
||||||
|
|
||||||
## 5.3.0
|
## 5.3.0
|
||||||
|
|
||||||
* Added reject_authenticated_sender_login_mismatch (#872)
|
* Added reject_authenticated_sender_login_mismatch (#872)
|
||||||
You can enable it with the env SPOOF_PROTECTION
|
You can enable it with the env SPOOF_PROTECTION
|
||||||
It is not enabled by default
|
It is not enabled by default
|
||||||
|
|
||||||
## 5.2.0
|
## 5.2.0
|
||||||
|
|
||||||
* Setting quiet mode on invoke-rc.d (#792)
|
* Setting quiet mode on invoke-rc.d (#792)
|
||||||
* Implement undef option for SA_SPAM_SUBJECT (#767)
|
* Implement undef option for SA_SPAM_SUBJECT (#767)
|
||||||
|
|
||||||
## 5.1.0
|
## 5.1.0
|
||||||
|
|
||||||
* Dkim key size can be changed (#868)
|
* Dkim key size can be changed (#868)
|
||||||
It defaults to 2048 bits
|
It defaults to 2048 bits
|
||||||
|
|
||||||
## 5.0.1
|
## 5.0.1
|
||||||
|
|
||||||
* update postmaster_address in dovecot config according to
|
* update postmaster_address in dovecot config according to
|
||||||
POSTMASTER_ADDRESS env var (#866)
|
POSTMASTER_ADDRESS env var (#866)
|
||||||
|
|
||||||
## 5.0.0
|
## 5.0.0
|
||||||
|
|
||||||
* Use Nist tls recommendations (#831)
|
* Use Nist tls recommendations (#831)
|
||||||
This might break access with older email clients that use
|
This might break access with older email clients that use
|
||||||
an older version of openssl. You can TLS_LEVEL to lower
|
an older version of openssl. You can TLS_LEVEL to lower
|
||||||
the ciphers.
|
the ciphers.
|
||||||
|
|
||||||
## 4.2.0
|
## 4.2.0
|
||||||
* Add environment variable to allow for customizing postsrsd's
|
|
||||||
SRS_EXCLUDE_DOMAINS setting (#849, #842)
|
* Add environment variable to allow for customizing postsrsd's SRS_EXCLUDE_DOMAINS setting (#849, #842)
|
||||||
|
|
||||||
## 4.1.0
|
## 4.1.0
|
||||||
|
|
||||||
* fixed greedy postgrey sed command (#845)
|
* fixed greedy postgrey sed command (#845)
|
||||||
* postscreen implementation altered (#846)
|
* postscreen implementation altered (#846)
|
||||||
You can now apply sender and receives restrictions
|
You can now apply sender and receives restrictions
|
||||||
|
|
||||||
## 4.0.0
|
## 4.0.0
|
||||||
|
|
||||||
* moved fail2ban function from setup.sh to own file (#837)
|
* moved fail2ban function from setup.sh to own file (#837)
|
||||||
This might break automatic scripting and you need to use
|
This might break automatic scripting and you need to use
|
||||||
fail2ban now
|
fail2ban now
|
||||||
|
|
||||||
## 3.4.0
|
## 3.4.0
|
||||||
|
|
||||||
* Generate new DH param weekly instead of daily (#834, #836)
|
* Generate new DH param weekly instead of daily (#834, #836)
|
||||||
|
|
||||||
## 3.3.1
|
## 3.3.1
|
||||||
|
|
||||||
* added config-path option to setup.sh script (#698)
|
* added config-path option to setup.sh script (#698)
|
||||||
|
|
||||||
## 3.3.0
|
## 3.3.0
|
||||||
|
|
||||||
* Restrict access (#452, #816)
|
* Restrict access (#452, #816)
|
||||||
|
|
||||||
## 3.2.3
|
## 3.2.3
|
||||||
|
|
||||||
* Introduce .env for docker-compose examples (#815)
|
* Introduce .env for docker-compose examples (#815)
|
||||||
|
|
||||||
## 3.2.2
|
## 3.2.2
|
||||||
|
|
||||||
* Changed Junk folder to be created and subscribed by default (#806)
|
* Changed Junk folder to be created and subscribed by default (#806)
|
||||||
|
|
||||||
## 3.2.1 (2018-02-06)
|
## 3.2.1 (2018-02-06)
|
||||||
|
|
||||||
* Added reject_sender_login_mismatch (#811)
|
* Added reject_sender_login_mismatch (#811)
|
||||||
|
|
||||||
## 3.2.0 (2018-02-06)
|
## 3.2.0 (2018-02-06)
|
||||||
|
|
||||||
* Add SRS to fix SPF issues on redirect (#611, #814)
|
* Add SRS to fix SPF issues on redirect (#611, #814)
|
||||||
|
|
||||||
## 3.1.0 (2018-02-04)
|
## 3.1.0 (2018-02-04)
|
||||||
|
|
||||||
* Introduced Postscreen
|
* Introduced Postscreen
|
||||||
Breaks email submission on port 25. Sending emails should be done on port 465 or 587
|
Breaks email submission on port 25. Sending emails should be done on port 465 or 587
|
||||||
|
|
||||||
## 3.0.0 (2018-02-04)
|
## 3.0.0 (2018-02-04)
|
||||||
|
|
||||||
* Image rebased on Debian stable
|
* Image rebased on Debian stable
|
||||||
|
|
||||||
## 2.0.0 (2016-05-09)
|
## 2.0.0 (2016-05-09)
|
||||||
|
|
||||||
* New version
|
* New version
|
||||||
* Major redesign of configuration
|
* Major redesign of configuration
|
||||||
|
|
||||||
|
|
174
CONTRIBUTING.md
174
CONTRIBUTING.md
|
@ -2,18 +2,29 @@
|
||||||
|
|
||||||
`docker-mailserver` is OpenSource. That means that you can contribute on enhancements, bug fixing or improving the documentation in the Wiki.
|
`docker-mailserver` is OpenSource. That means that you can contribute on enhancements, bug fixing or improving the documentation in the Wiki.
|
||||||
|
|
||||||
## Open an issue
|
1. [Issues & PRs](#issues--prs)
|
||||||
|
1. [Open an Issue](#open-an-issue)
|
||||||
|
2. [Pull Request](#pull-requests)
|
||||||
|
2. [Coding Style](#coding-style)
|
||||||
|
1. [Bash and Shell](#bash-and-shell)
|
||||||
|
2. [YAML](#yaml)
|
||||||
|
|
||||||
|
## Issues & PRs
|
||||||
|
|
||||||
|
### Open an issue
|
||||||
|
|
||||||
When opening an issue, please provide details use case to let the community reproduce your problem.
|
When opening an issue, please provide details use case to let the community reproduce your problem.
|
||||||
Please start the mail server with env `DMS_DEBUG=1` and paste the ouput into the issue.
|
Please start the mail server with env `DMS_DEBUG=1` and paste the output into the issue.
|
||||||
|
|
||||||
## Pull Requests
|
### Pull Requests
|
||||||
|
|
||||||
#### Project architecture
|
#### Project architecture
|
||||||
|
|
||||||
├── config # User: personal configurations
|
``` TXT
|
||||||
├── target # Developer: default server configuration, used when building the image
|
├── config # User: personal configurations
|
||||||
└── test # Developer: integration tests to check that everything keeps working
|
├── target # Developer: default server configuration, used when building the image
|
||||||
|
└── test # Developer: integration tests to check that everything keeps working
|
||||||
|
```
|
||||||
|
|
||||||
#### Submit a Pull-Request
|
#### Submit a Pull-Request
|
||||||
|
|
||||||
|
@ -29,9 +40,158 @@ The development workflow is the following:
|
||||||
- Use `make clean all` to build image locally and run tests
|
- Use `make clean all` to build image locally and run tests
|
||||||
Note that tests work on Linux only; they hang on Mac and Windows.
|
Note that tests work on Linux only; they hang on Mac and Windows.
|
||||||
- Document your improvements in `README.md` or Wiki depending on content
|
- Document your improvements in `README.md` or Wiki depending on content
|
||||||
- [Commit](https://help.github.com/articles/closing-issues-via-commit-messages/), push and make a pull-request
|
- [Commit][commit], if possible with [signing your commit with a GPG key][gpg], push and make a pull-request
|
||||||
- Pull-request is automatically tested on Travis
|
- Pull-request is automatically tested on Travis
|
||||||
- When tests are green, a review may be done
|
- When tests are green, a review may be done
|
||||||
- When changed are validated, your branch is merged into `master`
|
- When changed are validated, your branch is merged into `master`
|
||||||
- `master` is automatically tested on Travis
|
- `master` is automatically tested on Travis
|
||||||
- Docker builds a new `latest` image
|
- Docker builds a new `latest` image
|
||||||
|
|
||||||
|
## Coding Style
|
||||||
|
|
||||||
|
### Bash and Shell
|
||||||
|
|
||||||
|
When refactoring, writing or altering Script, that is Shell and Bash scripts, in any way, adhere to these rules:
|
||||||
|
|
||||||
|
1. **Adjust your style of coding to the style that is already present**! Even if you do not like it, this is due to consistency. Look up the GNU coding style guide. There was a lot of work involved in making these scripts consistent.
|
||||||
|
2. **Use `shellcheck` to check your scripts**! Your contributions are checked by TravisCI with shellcheck.
|
||||||
|
3. There is a **`.editorconfig`** file. Make your IDE use it or adhere to it manually!
|
||||||
|
4. It's okay to use `/bin/bash` instead of `/bin/sh`. You can alternatively use `/usr/bin/env bash`.
|
||||||
|
5. `setup.sh` provides a good starting point to look for.
|
||||||
|
6. When appropriate, use the `set` builtin. We recommend `set -euEo pipefail` (very strong) or `set -uE` (weaker).
|
||||||
|
|
||||||
|
#### Styling rules
|
||||||
|
|
||||||
|
##### Initial Description
|
||||||
|
|
||||||
|
When writing a script, provide the version and the script's task. We use [semantic versioning][semver] - so do you.
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# version 0.1.0
|
||||||
|
#
|
||||||
|
# <TASK DESCRIPTION> -> cut this off
|
||||||
|
# to make it not longer than approx.
|
||||||
|
# 80 cols.
|
||||||
|
```
|
||||||
|
|
||||||
|
##### If-Else-Statements
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
# when using braces, use double braces
|
||||||
|
# remember you do not need "" when using [[ ]]
|
||||||
|
if [[ <CONDITION1> ]] && [[ -f ${FILE} ]]
|
||||||
|
then
|
||||||
|
<CODE TO RUN>
|
||||||
|
# when running code, you don't need them
|
||||||
|
elif <COMMAND TO RUN>
|
||||||
|
<CODE TO TUN>
|
||||||
|
else
|
||||||
|
<CODE TO TUN>
|
||||||
|
fi
|
||||||
|
|
||||||
|
# equality checks with numbers, use
|
||||||
|
# -eq/-ne/-lt/-ge, not != or ==
|
||||||
|
if [[ $VAR -ne 42 ]] || [[ $SOME_VAR -eq 6 ]]
|
||||||
|
then
|
||||||
|
<CODE TO RUN>
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Variables & Braces
|
||||||
|
|
||||||
|
Variables are always uppercase. We always use braces. If you forgot this and want to change it later, you can use [this link][regex], which points to <https://regex101.com>. The used regex is `\$([^{("\\'\/])([a-zA-Z0-9_]*)([^}\/ \t'"\n.\]:]*)`, where you should in practice be able to replace all variable occurrences without braces with occurrences with braces.
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
# good
|
||||||
|
local VAR="good"
|
||||||
|
local NEW="${VAR}"
|
||||||
|
|
||||||
|
# bad
|
||||||
|
var="bad"
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Loops
|
||||||
|
|
||||||
|
Like `if-else`, loops look like this
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
for / while <LOOP CONDITION>
|
||||||
|
do
|
||||||
|
<CODE TO RUN>
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Functions
|
||||||
|
|
||||||
|
It's always nice to see the use of functions. Not only as it's more C-style, but it also provides a clear structure. If scripts are small, this is unnecessary, but if they become larger, please consider using functions. When doing so, provide `function _main()`. When using functions, they are **always** at the top of the script!
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
function _<name_underscored_and_lowercase>()
|
||||||
|
{
|
||||||
|
<CODE TO RUN>
|
||||||
|
|
||||||
|
# variables that can be local should be local
|
||||||
|
local _<LOCAL_VARIABLE_NAME>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Error Tracing
|
||||||
|
|
||||||
|
A construct to trace error in your scripts looks like this. Please use it like this (copy-paste) to make errors streamlined. Remember: Remove `set -x` in the end. This of debugging purposes only.
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
set -euxEo pipefail
|
||||||
|
trap '_report_err $_ $LINENO $?' ERR
|
||||||
|
|
||||||
|
function _report_err()
|
||||||
|
{
|
||||||
|
echo "ERROR occurred :: source (hint) $1 ; line $2 ; exit code $3 ;;" >&2
|
||||||
|
|
||||||
|
<CODE TO RUN AFTERWARDS>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Comments and Descriptiveness
|
||||||
|
|
||||||
|
Comments should only describe non-obvious matters. Comments should start lowercase when they aren't sentences. Make the code **self-descriptive** by using meaningful names! Make comments not longer than approximately 80 columns, then wrap the line.
|
||||||
|
|
||||||
|
A negative example:
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
# adds one to the first argument and print it to stdout
|
||||||
|
function _add_one()
|
||||||
|
{
|
||||||
|
# save the first variable
|
||||||
|
local FIRST=$1
|
||||||
|
|
||||||
|
# add one here
|
||||||
|
local RESULT=$(( _FIRST + 1 ))
|
||||||
|
|
||||||
|
# print it to stdout
|
||||||
|
echo "$_RESULT"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A positive example:
|
||||||
|
|
||||||
|
``` BASH
|
||||||
|
# writes result to stdout
|
||||||
|
function _add_one()
|
||||||
|
{
|
||||||
|
echo $(( $1 + 1 ))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### YAML
|
||||||
|
|
||||||
|
When formatting YAML files, you can opt for [Prettier][prettier]. There are any plugins for IDEs around.
|
||||||
|
|
||||||
|
[//]: # (Links)
|
||||||
|
|
||||||
|
[commit]: https://help.github.com/articles/closing-issues-via-commit-messages/
|
||||||
|
[gpg]: https://docs.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key
|
||||||
|
[semver]: https://semver.org/
|
||||||
|
[regex]: https://regex101.com/r/ikzJpF/4
|
||||||
|
[prettier]: https://prettier.io
|
||||||
|
|
|
@ -182,8 +182,7 @@ COPY target/fail2ban/filter.d/postfix-sasl.conf /etc/fail2ban/filter.d/postfix-s
|
||||||
RUN mkdir /var/run/fail2ban
|
RUN mkdir /var/run/fail2ban
|
||||||
|
|
||||||
# Enables Pyzor and Razor
|
# Enables Pyzor and Razor
|
||||||
RUN su - amavis -c "razor-admin -create && \
|
RUN su - amavis -c "razor-admin -create && razor-admin -register"
|
||||||
razor-admin -register"
|
|
||||||
|
|
||||||
# Configure DKIM (opendkim)
|
# Configure DKIM (opendkim)
|
||||||
# DKIM config files
|
# DKIM config files
|
||||||
|
|
89
Makefile
89
Makefile
|
@ -1,9 +1,14 @@
|
||||||
|
SHELL = /bin/bash
|
||||||
|
|
||||||
NAME = tvial/docker-mailserver:testing
|
NAME = tvial/docker-mailserver:testing
|
||||||
VCS_REF := $(shell git rev-parse --short HEAD)
|
VCS_REF := $(shell git rev-parse --short HEAD)
|
||||||
VCS_VERSION := $(shell git describe --tags --contains --always)
|
VCS_VERSION := $(shell git describe --tags --contains --always)
|
||||||
|
|
||||||
|
SLEEP = 15s
|
||||||
|
|
||||||
all: build backup generate-accounts run generate-accounts-after-run fixtures tests clean
|
all: build backup generate-accounts run generate-accounts-after-run fixtures tests clean
|
||||||
no-build: backup generate-accounts run generate-accounts-after-run fixtures tests clean
|
no-build: backup generate-accounts run generate-accounts-after-run fixtures tests clean
|
||||||
|
complete_test: lint build generate-accounts run generate-accounts-after-run fixtures tests
|
||||||
|
|
||||||
build:
|
build:
|
||||||
docker build \
|
docker build \
|
||||||
|
@ -12,22 +17,24 @@ build:
|
||||||
-t $(NAME) .
|
-t $(NAME) .
|
||||||
|
|
||||||
backup:
|
backup:
|
||||||
# if backup directories exist, clean hasn't been called, therefore we shouldn't overwrite it. It still contains the original content.
|
# if backup directories exist, clean hasn't been called, therefore
|
||||||
@if [ ! -d config.bak ]; then\
|
# we shouldn't overwrite it. It still contains the original content.
|
||||||
cp -rp config config.bak; \
|
@ if [ ! -d config.bak ]; then\
|
||||||
|
cp -rp config config.bak;\
|
||||||
fi
|
fi
|
||||||
@if [ ! -d testconfig.bak ]; then\
|
@ if [ ! -d testconfig.bak ]; then\
|
||||||
cp -rp test/config testconfig.bak ;\
|
cp -rp test/config testconfig.bak;\
|
||||||
fi
|
fi
|
||||||
|
|
||||||
generate-accounts:
|
generate-accounts:
|
||||||
docker run --rm -e MAIL_USER=user1@localhost.localdomain -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' > test/config/postfix-accounts.cf
|
@ docker run --rm -e MAIL_USER=user1@localhost.localdomain -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' > test/config/postfix-accounts.cf
|
||||||
docker run --rm -e MAIL_USER=user2@otherdomain.tld -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' >> test/config/postfix-accounts.cf
|
@ docker run --rm -e MAIL_USER=user2@otherdomain.tld -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' >> test/config/postfix-accounts.cf
|
||||||
echo "# this is a test comment, please don't delete me :'(" >> test/config/postfix-accounts.cf
|
@ echo "# this is a test comment, please don't delete me :'(" >> test/config/postfix-accounts.cf
|
||||||
echo " # this is also a test comment, :O" >> test/config/postfix-accounts.cf
|
@ echo " # this is also a test comment, :O" >> test/config/postfix-accounts.cf
|
||||||
|
|
||||||
run:
|
run:
|
||||||
# Run containers
|
# run containers
|
||||||
|
-@ echo "Sleeping $(SLEEP) after each container"
|
||||||
docker run --rm -d --name mail \
|
docker run --rm -d --name mail \
|
||||||
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
||||||
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||||
|
@ -50,14 +57,14 @@ run:
|
||||||
-e PERMIT_DOCKER=host \
|
-e PERMIT_DOCKER=host \
|
||||||
-e DMS_DEBUG=0 \
|
-e DMS_DEBUG=0 \
|
||||||
-h mail.my-domain.com -t $(NAME)
|
-h mail.my-domain.com -t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
docker run --rm -d --name mail_smtponly_without_config \
|
docker run --rm -d --name mail_smtponly_without_config \
|
||||||
-e SMTP_ONLY=1 \
|
-e SMTP_ONLY=1 \
|
||||||
-e ENABLE_LDAP=1 \
|
-e ENABLE_LDAP=1 \
|
||||||
-e PERMIT_DOCKER=network \
|
-e PERMIT_DOCKER=network \
|
||||||
-e OVERRIDE_HOSTNAME=mail.mydomain.com \
|
-e OVERRIDE_HOSTNAME=mail.mydomain.com \
|
||||||
-t $(NAME)
|
-t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
docker run --rm -d --name mail_override_hostname \
|
docker run --rm -d --name mail_override_hostname \
|
||||||
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
||||||
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||||
|
@ -67,7 +74,7 @@ run:
|
||||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||||
-h unknown.domain.tld \
|
-h unknown.domain.tld \
|
||||||
-t $(NAME)
|
-t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
docker run --rm -d --name mail_domainname \
|
docker run --rm -d --name mail_domainname \
|
||||||
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
||||||
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||||
|
@ -77,7 +84,7 @@ run:
|
||||||
-e DOMAINNAME=my-domain.com \
|
-e DOMAINNAME=my-domain.com \
|
||||||
-h unknown.domain.tld \
|
-h unknown.domain.tld \
|
||||||
-t $(NAME)
|
-t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
docker run --rm -d --name mail_srs_domainname \
|
docker run --rm -d --name mail_srs_domainname \
|
||||||
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
||||||
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||||
|
@ -88,7 +95,7 @@ run:
|
||||||
-e DOMAINNAME=my-domain.com \
|
-e DOMAINNAME=my-domain.com \
|
||||||
-h unknown.domain.tld \
|
-h unknown.domain.tld \
|
||||||
-t $(NAME)
|
-t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
docker run --rm -d --name mail_disabled_clamav_spamassassin \
|
docker run --rm -d --name mail_disabled_clamav_spamassassin \
|
||||||
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
-v "`pwd`/test/config":/tmp/docker-mailserver \
|
||||||
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
-v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||||
|
@ -96,19 +103,19 @@ run:
|
||||||
-e ENABLE_SPAMASSASSIN=0 \
|
-e ENABLE_SPAMASSASSIN=0 \
|
||||||
-e DMS_DEBUG=0 \
|
-e DMS_DEBUG=0 \
|
||||||
-h mail.my-domain.com -t $(NAME)
|
-h mail.my-domain.com -t $(NAME)
|
||||||
sleep 15
|
-@ sleep $(SLEEP)
|
||||||
|
|
||||||
generate-accounts-after-run:
|
generate-accounts-after-run:
|
||||||
docker run --rm -e MAIL_USER=added@localhost.localdomain -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' >> test/config/postfix-accounts.cf
|
@ docker run --rm -e MAIL_USER=added@localhost.localdomain -e MAIL_PASS=mypassword -t $(NAME) /bin/sh -c 'echo "$$MAIL_USER|$$(doveadm pw -s SHA512-CRYPT -u $$MAIL_USER -p $$MAIL_PASS)"' >> test/config/postfix-accounts.cf
|
||||||
docker exec mail addmailuser pass@localhost.localdomain 'may be \a `p^a.*ssword'
|
@ docker exec mail addmailuser pass@localhost.localdomain 'may be \a `p^a.*ssword'
|
||||||
|
@ sleep $(SLEEP)
|
||||||
sleep 10
|
|
||||||
|
|
||||||
fixtures:
|
fixtures:
|
||||||
# Setup sieve
|
# setup sieve
|
||||||
docker cp "`pwd`/test/config/sieve/dovecot.sieve" mail:/var/mail/localhost.localdomain/user1/.dovecot.sieve
|
docker cp "`pwd`/test/config/sieve/dovecot.sieve" mail:/var/mail/localhost.localdomain/user1/.dovecot.sieve
|
||||||
sleep 30
|
sleep $(SLEEP)
|
||||||
# Sending test mails
|
sleep $(SLEEP)
|
||||||
|
# sending test mails
|
||||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
||||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
|
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
|
||||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-external.txt"
|
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-external.txt"
|
||||||
|
@ -126,35 +133,45 @@ fixtures:
|
||||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt"
|
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt"
|
||||||
docker exec mail_disabled_clamav_spamassassin /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
docker exec mail_disabled_clamav_spamassassin /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||||
docker exec mail /bin/sh -c "sendmail root < /tmp/docker-mailserver-test/email-templates/root-email.txt"
|
docker exec mail /bin/sh -c "sendmail root < /tmp/docker-mailserver-test/email-templates/root-email.txt"
|
||||||
# postfix virtual transport lmtp
|
# postfix virtual transport lmtp
|
||||||
docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||||
# Wait for mails to be analyzed
|
# wait for mails to be analyzed
|
||||||
sleep 80
|
sleep 80
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
# Start tests
|
|
||||||
./test/bats/bin/bats test/*.bats
|
./test/bats/bin/bats test/*.bats
|
||||||
|
|
||||||
.PHONY: ALWAYS_RUN
|
.PHONY: ALWAYS_RUN
|
||||||
|
|
||||||
test/%.bats: ALWAYS_RUN
|
test/%.bats: ALWAYS_RUN
|
||||||
./test/bats/bin/bats $@
|
./test/bats/bin/bats $@
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
# List files which name starts with 'Dockerfile'
|
# List files which name starts with 'Dockerfile'
|
||||||
# eg. Dockerfile, Dockerfile.build, etc.
|
# eg. Dockerfile, Dockerfile.build, etc.
|
||||||
git ls-files --exclude='Dockerfile*' --ignored | xargs --max-lines=1 hadolint
|
-@ git ls-files --exclude='Dockerfile*' --ignored | xargs --max-lines=1 hadolint
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# Remove running and stopped test containers
|
# remove running and stopped test containers
|
||||||
-docker ps -a | grep -E "docker-mailserver:testing|ldap_for_mail" | cut -f 1-1 -d ' ' | xargs --no-run-if-empty docker rm -f
|
-@ docker ps -a | grep -E "docker-mailserver:testing|ldap_for_mail" | cut -f 1-1 -d ' ' | xargs --no-run-if-empty docker rm -f
|
||||||
|
-@ if [ -d config.bak ]; then\
|
||||||
@if [ -d config.bak ]; then\
|
|
||||||
rm -rf config ;\
|
rm -rf config ;\
|
||||||
mv config.bak config ;\
|
mv config.bak config ;\
|
||||||
fi
|
fi
|
||||||
@if [ -d testconfig.bak ]; then\
|
-@ if [ -d testconfig.bak ]; then\
|
||||||
sudo rm -rf test/config ;\
|
sudo rm -rf test/config ;\
|
||||||
mv testconfig.bak test/config ;\
|
mv testconfig.bak test/config ;\
|
||||||
fi
|
fi
|
||||||
-sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem
|
-@ sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem test/config/dovecot-lmtp/dh.pem test/config/relay-hosts/dovecot-quotas.cf test/config/user-patches.sh test/alias/config/postfix-virtual.cf test/quota/config/dovecot-quotas.cf test/quota/config/postfix-accounts.cf test/relay/config/postfix-relaymap.cf test/relay/config/postfix-sasl-password.cf
|
||||||
|
|
||||||
|
shellcheck:
|
||||||
|
@ echo -e "Testing shell / bash scripts with shellcheck\n"
|
||||||
|
@ /usr/bin/shellcheck --version
|
||||||
|
@ echo ''
|
||||||
|
# currently without `start-mailserver` as this is to be merged separately
|
||||||
|
@ if find -iname "*.sh" -not -path "./test/*" -not -path "./target/docker-configomat/*" -not -wholename ./target/start-mailserver.sh -exec /usr/bin/shellcheck -S style -Cauto -o all -e SC2250,SC2154 -W 50 {} \; | grep .; then\
|
||||||
|
echo -e "\nError" ;\
|
||||||
|
exit 1 ;\
|
||||||
|
else\
|
||||||
|
echo -e '\nSuccess' ;\
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
63
README.md
63
README.md
|
@ -1,12 +1,35 @@
|
||||||
# docker-mailserver
|
# docker-mailserver
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/tomav/docker-mailserver.svg?branch=master)](https://travis-ci.org/tomav/docker-mailserver) [![Docker Pulls](https://img.shields.io/docker/pulls/tvial/docker-mailserver.svg)](https://hub.docker.com/r/tvial/docker-mailserver/) [![Docker layers](https://images.microbadger.com/badges/image/tvial/docker-mailserver.svg)](https://microbadger.com/images/tvial/docker-mailserver) [![Github Stars](https://img.shields.io/github/stars/tomav/docker-mailserver.svg?label=github%20%E2%98%85)](https://github.com/tomav/docker-mailserver/) [![Github Stars](https://img.shields.io/github/contributors/tomav/docker-mailserver.svg)](https://github.com/tomav/docker-mailserver/) [![Github Forks](https://img.shields.io/github/forks/tomav/docker-mailserver.svg?label=github%20forks)](https://github.com/tomav/docker-mailserver/) [![Gitter](https://img.shields.io/gitter/room/tomav/docker-mailserver.svg)](https://gitter.im/tomav/docker-mailserver)
|
[![Build Status][build_status]][build_status::travis] [![Docker Pulls][docker_pulls]][docker_hub_pulls::hub] [![Docker layers][layers]][layers_outer::badger] [![Github Stars][gh_stars]][repo] [![Contributors][contributors]][repo] [![Github Forks][forks]][repo] [![Gitter][shields::gitter]][gitter]
|
||||||
|
|
||||||
|
[build_status]: https://travis-ci.org/tomav/docker-mailserver.svg?branch=master
|
||||||
|
[build_status::travis]: https://travis-ci.org/tomav/docker-mailserver
|
||||||
|
[docker_pulls]: https://img.shields.io/docker/pulls/tvial/docker-mailserver.svg
|
||||||
|
[docker_hub_pulls::hub]: https://hub.docker.com/r/tvial/docker-mailserver/
|
||||||
|
[layers]: https://images.microbadger.com/badges/image/tvial/docker-mailserver.svg
|
||||||
|
[layers_outer::badger]: https://microbadger.com/images/tvial/docker-mailserver
|
||||||
|
[gh_stars]: https://img.shields.io/github/stars/tomav/docker-mailserver.svg?label=github%20%E2%98%85
|
||||||
|
[repo]: https://github.com/tomav/docker-mailserver/
|
||||||
|
[contributors]: https://img.shields.io/github/contributors/tomav/docker-mailserver.svg
|
||||||
|
[forks]: https://img.shields.io/github/forks/tomav/docker-mailserver.svg?label=github%20forks
|
||||||
|
[shields::gitter]: https://img.shields.io/gitter/room/tomav/docker-mailserver.svg
|
||||||
|
[gitter]: https://gitter.im/tomav/docker-mailserver
|
||||||
|
|
||||||
A fullstack but simple mail server (smtp, imap, antispam, antivirus...).
|
A fullstack but simple mail server (smtp, imap, antispam, antivirus...).
|
||||||
Only configuration files, no SQL database. Keep it simple and versioned.
|
Only configuration files, no SQL database. Keep it simple and versioned.
|
||||||
Easy to deploy and upgrade.
|
Easy to deploy and upgrade.
|
||||||
|
|
||||||
## ANNOUNCEMENT
|
Why I created this image: [Simple Mail Server with Docker](http://tvi.al/simple-mail-server-with-docker/)
|
||||||
|
|
||||||
|
1. [Announcement](#announcement)
|
||||||
|
2. [Includes](#includes)
|
||||||
|
3. [Issues & Contributing](#issues--contributing)
|
||||||
|
4. [Requirements](#requirements)
|
||||||
|
5. [Usage](#usage)
|
||||||
|
6. [Examples](#examples)
|
||||||
|
7. [Environment Variables](#environment-variables)
|
||||||
|
|
||||||
|
## Announcement
|
||||||
|
|
||||||
At this point we have merged the next branch based on Debian Buster into master.
|
At this point we have merged the next branch based on Debian Buster into master.
|
||||||
That means the docker image latest uses Buster. The change may break things!
|
That means the docker image latest uses Buster. The change may break things!
|
||||||
|
@ -19,7 +42,7 @@ The following possibly breaking changes are known:
|
||||||
If you want to stick to the old version a while longer, either switch to stable or to a specific version.
|
If you want to stick to the old version a while longer, either switch to stable or to a specific version.
|
||||||
If you run into problems, please raise issues and ask for help. Don't forget to provide details.
|
If you run into problems, please raise issues and ask for help. Don't forget to provide details.
|
||||||
|
|
||||||
Includes:
|
## Includes
|
||||||
|
|
||||||
- [Postfix](http://www.postfix.org) with smtp or ldap auth
|
- [Postfix](http://www.postfix.org) with smtp or ldap auth
|
||||||
- [Dovecot](https://www.dovecot.org) for sasl, imap (and optional pop3) with ssl support, with ldap auth, sieve and [quotas](https://github.com/tomav/docker-mailserver/wiki/Configure-Accounts#mailbox-quota)
|
- [Dovecot](https://www.dovecot.org) for sasl, imap (and optional pop3) with ssl support, with ldap auth, sieve and [quotas](https://github.com/tomav/docker-mailserver/wiki/Configure-Accounts#mailbox-quota)
|
||||||
|
@ -42,9 +65,9 @@ Includes:
|
||||||
- Plus addressing (a.k.a. [extension delimiters](http://www.postfix.org/postconf.5.html#recipient_delimiter))
|
- Plus addressing (a.k.a. [extension delimiters](http://www.postfix.org/postconf.5.html#recipient_delimiter))
|
||||||
works out of the box: email for `you+extension@example.com` go to `you@example.com`
|
works out of the box: email for `you+extension@example.com` go to `you@example.com`
|
||||||
|
|
||||||
Why I created this image: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/)
|
## Issues & Contributing
|
||||||
|
|
||||||
Before you open an issue, please have a look this `README`, the [Wiki](https://github.com/tomav/docker-mailserver/wiki/) and Postfix/Dovecot documentation.
|
Before you open an issue, please have a look this `README`, the [Wiki](https://github.com/tomav/docker-mailserver/wiki/) and Postfix/Dovecot documentation. If you'd like to contribute, read [`CONTRIBUTING.md`](./CONTRIBUTING.md) thoroughly.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
@ -67,7 +90,7 @@ Minimum:
|
||||||
|
|
||||||
Download the docker-compose.yml, the .env and the setup.sh files:
|
Download the docker-compose.yml, the .env and the setup.sh files:
|
||||||
|
|
||||||
``` SH
|
``` BASH
|
||||||
curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh; chmod a+x ./setup.sh
|
curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh; chmod a+x ./setup.sh
|
||||||
|
|
||||||
curl -o docker-compose.yml https://raw.githubusercontent.com/tomav/docker-mailserver/master/docker-compose.yml.dist
|
curl -o docker-compose.yml https://raw.githubusercontent.com/tomav/docker-mailserver/master/docker-compose.yml.dist
|
||||||
|
@ -89,7 +112,7 @@ curl -o env-mailserver https://raw.githubusercontent.com/tomav/docker-mailserver
|
||||||
|
|
||||||
**Note:** If you want to use a bare domain (host name equals domain name) see [FAQ](https://github.com/tomav/docker-mailserver/wiki/FAQ-and-Tips#can-i-use-nakedbare-domains-no-host-name).
|
**Note:** If you want to use a bare domain (host name equals domain name) see [FAQ](https://github.com/tomav/docker-mailserver/wiki/FAQ-and-Tips#can-i-use-nakedbare-domains-no-host-name).
|
||||||
|
|
||||||
### Starting the Container
|
### Start the Container
|
||||||
|
|
||||||
``` BASH
|
``` BASH
|
||||||
docker-compose up -d mail
|
docker-compose up -d mail
|
||||||
|
@ -129,8 +152,6 @@ If you got any problems with SPF and/or forwarding mails, give [SRS](https://git
|
||||||
|
|
||||||
#### For informational purposes
|
#### For informational purposes
|
||||||
|
|
||||||
Your config folder will be mounted in `/tmp/docker-mailserver/`. To understand how things work on boot, please have a look at [start-mailserver.sh](https://github.com/tomav/docker-mailserver/blob/master/target/start-mailserver.sh)
|
|
||||||
|
|
||||||
`restart: always` ensures that the mail server container (and Filebeat/ELK containers when using the mail server together with ELK stack) is automatically restarted by Docker in cases like a Docker service or host restart or container exit.
|
`restart: always` ensures that the mail server container (and Filebeat/ELK containers when using the mail server together with ELK stack) is automatically restarted by Docker in cases like a Docker service or host restart or container exit.
|
||||||
|
|
||||||
#### Exposed ports
|
#### Exposed ports
|
||||||
|
@ -148,12 +169,12 @@ Your config folder will be mounted in `/tmp/docker-mailserver/`. To understand h
|
||||||
|
|
||||||
See the [wiki](https://github.com/tomav/docker-mailserver/wiki) for further details and best practice advice, especially regarding security concerns.
|
See the [wiki](https://github.com/tomav/docker-mailserver/wiki) for further details and best practice advice, especially regarding security concerns.
|
||||||
|
|
||||||
### Examples
|
## Examples
|
||||||
|
|
||||||
#### Just the relevant environmental variables
|
### With Relevant Environmental Variables
|
||||||
|
|
||||||
```yaml
|
``` YAML
|
||||||
version: '2'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mail:
|
mail:
|
||||||
|
@ -195,7 +216,7 @@ volumes:
|
||||||
#### LDAP setup
|
#### LDAP setup
|
||||||
|
|
||||||
``` YAML
|
``` YAML
|
||||||
version: '2'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mail:
|
mail:
|
||||||
|
@ -256,9 +277,7 @@ volumes:
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
Please check [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/target/start-mailserver.sh) to understand what's expected. Also if an option doesn't work as documented here, check if you are running the latest image!
|
If an option doesn't work as documented here, check if you are running the latest image! Value in **bold** is the default value.
|
||||||
|
|
||||||
Value in **bold** is the default value.
|
|
||||||
|
|
||||||
### Assignments
|
### Assignments
|
||||||
|
|
||||||
|
@ -794,7 +813,7 @@ you to replace both instead of just the envelope sender.
|
||||||
|
|
||||||
#### Default Relay Host
|
#### Default Relay Host
|
||||||
|
|
||||||
#### DEFAULT_RELAY_HOST
|
##### DEFAULT_RELAY_HOST
|
||||||
|
|
||||||
- **empty** => don't set default relayhost setting in main.cf
|
- **empty** => don't set default relayhost setting in main.cf
|
||||||
- default host and port to relay all mail through.
|
- default host and port to relay all mail through.
|
||||||
|
@ -803,22 +822,22 @@ you to replace both instead of just the envelope sender.
|
||||||
|
|
||||||
#### Multi-domain Relay Hosts
|
#### Multi-domain Relay Hosts
|
||||||
|
|
||||||
#### RELAY_HOST
|
##### RELAY_HOST
|
||||||
|
|
||||||
- **empty** => don't configure relay host
|
- **empty** => don't configure relay host
|
||||||
- default host to relay mail through
|
- default host to relay mail through
|
||||||
|
|
||||||
#### RELAY_PORT
|
##### RELAY_PORT
|
||||||
|
|
||||||
- **empty** => 25
|
- **empty** => 25
|
||||||
- default port to relay mail through
|
- default port to relay mail through
|
||||||
|
|
||||||
#### RELAY_USER
|
##### RELAY_USER
|
||||||
|
|
||||||
- **empty** => no default
|
- **empty** => no default
|
||||||
- default relay username (if no specific entry exists in postfix-sasl-password.cf)
|
- default relay username (if no specific entry exists in postfix-sasl-password.cf)
|
||||||
|
|
||||||
#### RELAY_PASSWORD
|
##### RELAY_PASSWORD
|
||||||
|
|
||||||
- **empty** => no default
|
- **empty** => no default
|
||||||
- password for default relay user
|
- password for default relay user
|
||||||
|
|
187
setup.sh
187
setup.sh
|
@ -4,11 +4,11 @@
|
||||||
# included in the docker-mailserver
|
# included in the docker-mailserver
|
||||||
|
|
||||||
set -euEo pipefail
|
set -euEo pipefail
|
||||||
trap '_report_err $_ $LINENO $?' ERR
|
trap '_report_err ${_:-"SOURCE UNKNOWN"} ${LINENO} ${?}' ERR
|
||||||
|
|
||||||
function _report_err()
|
function _report_err()
|
||||||
{
|
{
|
||||||
echo "ERROR occured :: source (hint) $1 ; line $2 ; exit code $3 ;;" >&2
|
echo "ERROR occured :: source ${1} ; line ${2} ; exit code ${3} ;;" >&2
|
||||||
_unset_vars
|
_unset_vars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,12 +18,26 @@ function _unset_vars()
|
||||||
unset USE_CONTAINER WISHED_CONFIG_PATH CONFIG_PATH VOLUME USE_TTY
|
unset USE_CONTAINER WISHED_CONFIG_PATH CONFIG_PATH VOLUME USE_TTY
|
||||||
}
|
}
|
||||||
|
|
||||||
CDIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
|
function _get_current_directory()
|
||||||
|
{
|
||||||
|
if dirname "$(readlink -f "${0}")" &>/dev/null
|
||||||
|
then
|
||||||
|
CDIR="$(cd "$(dirname "$(readlink -f "${0}")")" && pwd)"
|
||||||
|
elif realpath -e -L "${0}" &>/dev/null
|
||||||
|
then
|
||||||
|
CDIR="$(realpath -e -L "${0}")"
|
||||||
|
CDIR="${CDIR%/setup.sh}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
CDIR="$(pwd)"
|
||||||
|
_get_current_directory
|
||||||
|
|
||||||
CRI=
|
CRI=
|
||||||
INFO=
|
INFO=
|
||||||
IMAGE_NAME=
|
IMAGE_NAME=
|
||||||
CONTAINER_NAME='mail'
|
CONTAINER_NAME='mail'
|
||||||
DEFAULT_CONFIG_PATH="$CDIR/config"
|
DEFAULT_CONFIG_PATH="${CDIR}/config"
|
||||||
USE_CONTAINER=false
|
USE_CONTAINER=false
|
||||||
WISHED_CONFIG_PATH=
|
WISHED_CONFIG_PATH=
|
||||||
CONFIG_PATH=
|
CONFIG_PATH=
|
||||||
|
@ -32,7 +46,7 @@ USE_TTY=
|
||||||
|
|
||||||
function _check_root()
|
function _check_root()
|
||||||
{
|
{
|
||||||
if [[ $EUID -ne 0 ]]
|
if [[ ${EUID} -ne 0 ]]
|
||||||
then
|
then
|
||||||
echo "Curently docker-mailserver doesn't support podman's rootless mode, please run this script as root user."
|
echo "Curently docker-mailserver doesn't support podman's rootless mode, please run this script as root user."
|
||||||
return 1
|
return 1
|
||||||
|
@ -41,32 +55,32 @@ function _check_root()
|
||||||
|
|
||||||
function _update_config_path()
|
function _update_config_path()
|
||||||
{
|
{
|
||||||
if [[ -n $CONTAINER_NAME ]]
|
if [[ -n ${CONTAINER_NAME} ]]
|
||||||
then
|
then
|
||||||
VOLUME=$(docker inspect "$CONTAINER_NAME" \
|
VOLUME=$(docker inspect "${CONTAINER_NAME}" \
|
||||||
--format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \
|
--format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \
|
||||||
grep "/tmp/docker-mailserver$" 2>/dev/null)
|
grep "/tmp/docker-mailserver$" 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $VOLUME ]]
|
if [[ -n ${VOLUME} ]]
|
||||||
then
|
then
|
||||||
CONFIG_PATH=$(echo "$VOLUME" | awk '{print $1}')
|
CONFIG_PATH=$(echo "${VOLUME}" | awk '{print $1}')
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function _inspect()
|
function _inspect()
|
||||||
{
|
{
|
||||||
if _docker_image_exists "$IMAGE_NAME"
|
if _docker_image_exists "${IMAGE_NAME}"
|
||||||
then
|
then
|
||||||
echo "Image: $IMAGE_NAME"
|
echo "Image: ${IMAGE_NAME}"
|
||||||
else
|
else
|
||||||
echo "Image: '$IMAGE_NAME' can’t be found."
|
echo "Image: '${IMAGE_NAME}' can’t be found."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $CONTAINER_NAME ]]
|
if [[ -n ${CONTAINER_NAME} ]]
|
||||||
then
|
then
|
||||||
echo "Container: $CONTAINER_NAME"
|
echo "Container: ${CONTAINER_NAME}"
|
||||||
echo "Config mount: $CONFIG_PATH"
|
echo "Config mount: ${CONFIG_PATH}"
|
||||||
else
|
else
|
||||||
echo "Container: Not running, please start docker-mailserver."
|
echo "Container: Not running, please start docker-mailserver."
|
||||||
fi
|
fi
|
||||||
|
@ -74,7 +88,7 @@ function _inspect()
|
||||||
|
|
||||||
function _usage()
|
function _usage()
|
||||||
{
|
{
|
||||||
echo "Usage: $0 [-i IMAGE_NAME] [-c CONTAINER_NAME] <subcommand> <subcommand> [args]
|
echo "Usage: ${0} [-i IMAGE_NAME] [-c CONTAINER_NAME] <subcommand> <subcommand> [args]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
|
||||||
|
@ -84,53 +98,52 @@ OPTIONS:
|
||||||
|
|
||||||
-c CONTAINER_NAME The name of the running container.
|
-c CONTAINER_NAME The name of the running container.
|
||||||
|
|
||||||
-p PATH config folder path (default: $(pwd)/config)
|
-p PATH config folder path (default: ${CDIR}/config)
|
||||||
|
|
||||||
SUBCOMMANDS:
|
SUBCOMMANDS:
|
||||||
|
|
||||||
email:
|
email:
|
||||||
|
|
||||||
$0 email add <email> [<password>]
|
${0} email add <email> [<password>]
|
||||||
$0 email update <email> [<password>]
|
${0} email update <email> [<password>]
|
||||||
$0 email del <email>
|
${0} email del <email>
|
||||||
$0 email restrict <add|del|list> <send|receive> [<email>]
|
${0} email restrict <add|del|list> <send|receive> [<email>]
|
||||||
$0 email list
|
${0} email list
|
||||||
|
|
||||||
alias:
|
alias:
|
||||||
$0 alias add <email> <recipient>
|
${0} alias add <email> <recipient>
|
||||||
$0 alias del <email> <recipient>
|
${0} alias del <email> <recipient>
|
||||||
$0 alias list
|
${0} alias list
|
||||||
|
|
||||||
quota:
|
quota:
|
||||||
$0 quota set <email> [<quota>]
|
${0} quota set <email> [<quota>]
|
||||||
$0 quota del <email>
|
${0} quota del <email>
|
||||||
|
|
||||||
config:
|
config:
|
||||||
|
|
||||||
$0 config dkim <keysize> (default: 2048)
|
${0} config dkim <keysize> (default: 2048)
|
||||||
$0 config ssl <fqdn>
|
${0} config ssl <fqdn>
|
||||||
|
|
||||||
relay:
|
relay:
|
||||||
|
|
||||||
$0 relay add-domain <domain> <host> [<port>]
|
${0} relay add-domain <domain> <host> [<port>]
|
||||||
$0 relay add-auth <domain> <username> [<password>]
|
${0} relay add-auth <domain> <username> [<password>]
|
||||||
$0 relay exclude-domain <domain>
|
${0} relay exclude-domain <domain>
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
|
|
||||||
$0 debug fetchmail
|
${0} debug fetchmail
|
||||||
$0 debug fail2ban [<unban> <ip-address>]
|
${0} debug fail2ban [<unban> <ip-address>]
|
||||||
$0 debug show-mail-logs
|
${0} debug show-mail-logs
|
||||||
$0 debug inspect
|
${0} debug inspect
|
||||||
$0 debug login <commands>
|
${0} debug login <commands>
|
||||||
"
|
|
||||||
|
|
||||||
return 1
|
"
|
||||||
}
|
}
|
||||||
|
|
||||||
function _docker_image_exists()
|
function _docker_image_exists()
|
||||||
{
|
{
|
||||||
if $CRI history -q "$1" >/dev/null 2>&1
|
if ${CRI} history -q "${1}" >/dev/null 2>&1
|
||||||
then
|
then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
|
@ -140,36 +153,36 @@ function _docker_image_exists()
|
||||||
|
|
||||||
function _docker_image()
|
function _docker_image()
|
||||||
{
|
{
|
||||||
if $USE_CONTAINER
|
if ${USE_CONTAINER}
|
||||||
then
|
then
|
||||||
# reuse existing container specified on command line
|
# reuse existing container specified on command line
|
||||||
$CRI exec "$USE_TTY" "$CONTAINER_NAME" "$@"
|
${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" "${@}"
|
||||||
else
|
else
|
||||||
# start temporary container with specified image
|
# start temporary container with specified image
|
||||||
if ! _docker_image_exists "$IMAGE_NAME"
|
if ! _docker_image_exists "${IMAGE_NAME}"
|
||||||
then
|
then
|
||||||
echo "Image '$IMAGE_NAME' not found. Pulling ..."
|
echo "Image '${IMAGE_NAME}' not found. Pulling ..."
|
||||||
$CRI pull "$IMAGE_NAME"
|
${CRI} pull "${IMAGE_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${CRI} run --rm \
|
${CRI} run --rm \
|
||||||
-v "$CONFIG_PATH":/tmp/docker-mailserver \
|
-v "${CONFIG_PATH}":/tmp/docker-mailserver \
|
||||||
"$USE_TTY" "$IMAGE_NAME" "$@"
|
"${USE_TTY}" "${IMAGE_NAME}" "${@}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function _docker_container()
|
function _docker_container()
|
||||||
{
|
{
|
||||||
if [[ -n $CONTAINER_NAME ]]
|
if [[ -n ${CONTAINER_NAME} ]]
|
||||||
then
|
then
|
||||||
$CRI exec "$USE_TTY" "$CONTAINER_NAME" "$@"
|
${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" "${@}"
|
||||||
else
|
else
|
||||||
echo "The docker-mailserver is not running!"
|
echo "The docker-mailserver is not running!"
|
||||||
exit 1
|
exit 5
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function main()
|
function _main()
|
||||||
{
|
{
|
||||||
if [[ -n $(command -v docker) ]]
|
if [[ -n $(command -v docker) ]]
|
||||||
then
|
then
|
||||||
|
@ -180,10 +193,10 @@ function main()
|
||||||
_check_root
|
_check_root
|
||||||
else
|
else
|
||||||
echo "No supported Container Runtime Interface detected."
|
echo "No supported Container Runtime Interface detected."
|
||||||
exit 1
|
exit 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INFO=$($CRI ps \
|
INFO=$(${CRI} ps \
|
||||||
--no-trunc \
|
--no-trunc \
|
||||||
--format "{{.Image}};{{.Names}}" \
|
--format "{{.Image}};{{.Names}}" \
|
||||||
--filter label=org.label-schema.name="docker-mailserver" | \
|
--filter label=org.label-schema.name="docker-mailserver" | \
|
||||||
|
@ -192,12 +205,12 @@ function main()
|
||||||
IMAGE_NAME=${INFO%;*}
|
IMAGE_NAME=${INFO%;*}
|
||||||
CONTAINER_NAME=${INFO#*;}
|
CONTAINER_NAME=${INFO#*;}
|
||||||
|
|
||||||
if [[ -z $IMAGE_NAME ]]
|
if [[ -z ${IMAGE_NAME} ]]
|
||||||
then
|
then
|
||||||
if [[ $CRI == "docker" ]]
|
if [[ ${CRI} == "docker" ]]
|
||||||
then
|
then
|
||||||
IMAGE_NAME=tvial/docker-mailserver:latest
|
IMAGE_NAME=tvial/docker-mailserver:latest
|
||||||
elif [[ $CRI == "podman" ]]
|
elif [[ ${CRI} == "podman" ]]
|
||||||
then
|
then
|
||||||
IMAGE_NAME=docker.io/tvial/docker-mailserver:latest
|
IMAGE_NAME=docker.io/tvial/docker-mailserver:latest
|
||||||
fi
|
fi
|
||||||
|
@ -211,38 +224,38 @@ function main()
|
||||||
local OPTIND
|
local OPTIND
|
||||||
while getopts ":c:i:p:" OPT
|
while getopts ":c:i:p:" OPT
|
||||||
do
|
do
|
||||||
case $OPT in
|
case ${OPT} in
|
||||||
c) CONTAINER_NAME="$OPTARG" ; USE_CONTAINER=true ;; # container specified, connect to running instance
|
c) CONTAINER_NAME="${OPTARG}" ; USE_CONTAINER=true ;; # container specified, connect to running instance
|
||||||
i) IMAGE_NAME="$OPTARG" ;;
|
i) IMAGE_NAME="${OPTARG}" ;;
|
||||||
p)
|
p)
|
||||||
case "$OPTARG" in
|
case "${OPTARG}" in
|
||||||
/*) WISHED_CONFIG_PATH="$OPTARG" ;;
|
/*) WISHED_CONFIG_PATH="${OPTARG}" ;;
|
||||||
* ) WISHED_CONFIG_PATH="$CDIR/$OPTARG" ;;
|
* ) WISHED_CONFIG_PATH="${CDIR}/${OPTARG}" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ ! -d $WISHED_CONFIG_PATH ]]
|
if [[ ! -d ${WISHED_CONFIG_PATH} ]]
|
||||||
then
|
then
|
||||||
echo "Directory doesn't exist"
|
echo "Directory doesn't exist"
|
||||||
_usage
|
_usage
|
||||||
exit 1
|
exit 40
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*) echo "Invalid option: -$OPTARG" >&2 ;;
|
*) echo "Invalid option: -${OPTARG}" >&2 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
shift $((OPTIND-1))
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
if [[ -z $WISHED_CONFIG_PATH ]]
|
if [[ -z ${WISHED_CONFIG_PATH} ]]
|
||||||
then
|
then
|
||||||
# no wished config path
|
# no wished config path
|
||||||
_update_config_path
|
_update_config_path
|
||||||
|
|
||||||
if [[ -z $CONFIG_PATH ]]
|
if [[ -z ${CONFIG_PATH} ]]
|
||||||
then
|
then
|
||||||
CONFIG_PATH=$DEFAULT_CONFIG_PATH
|
CONFIG_PATH=${DEFAULT_CONFIG_PATH}
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
CONFIG_PATH=$WISHED_CONFIG_PATH
|
CONFIG_PATH=${WISHED_CONFIG_PATH}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,10 +263,10 @@ function main()
|
||||||
|
|
||||||
email)
|
email)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
add ) shift ; _docker_image addmailuser "$@" ;;
|
add ) shift ; _docker_image addmailuser "${@}" ;;
|
||||||
update ) shift ; _docker_image updatemailuser "$@" ;;
|
update ) shift ; _docker_image updatemailuser "${@}" ;;
|
||||||
del ) shift ; _docker_image delmailuser "$@" ;;
|
del ) shift ; _docker_image delmailuser "${@}" ;;
|
||||||
restrict ) shift ; _docker_container restrict-access "$@" ;;
|
restrict ) shift ; _docker_container restrict-access "${@}" ;;
|
||||||
list ) _docker_image listmailuser ;;
|
list ) _docker_image listmailuser ;;
|
||||||
* ) _usage ;;
|
* ) _usage ;;
|
||||||
esac
|
esac
|
||||||
|
@ -261,17 +274,17 @@ function main()
|
||||||
|
|
||||||
alias)
|
alias)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
add ) shift ; _docker_image addalias "$@" ;;
|
add ) shift ; _docker_image addalias "${1}" "${2}" ;;
|
||||||
del ) shift ; _docker_image delalias "$@" ;;
|
del ) shift ; _docker_image delalias "${1}" "${2}" ;;
|
||||||
list ) shift ; _docker_image listalias "$@" ;;
|
list ) shift ; _docker_image listalias ;;
|
||||||
* ) _usage ;;
|
* ) _usage ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|
||||||
quota)
|
quota)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
set ) shift ; _docker_image setquota "$@" ;;
|
set ) shift ; _docker_image setquota "${@}" ;;
|
||||||
del ) shift ; _docker_image delquota "$@" ;;
|
del ) shift ; _docker_image delquota "${@}" ;;
|
||||||
* ) _usage ;;
|
* ) _usage ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
@ -279,16 +292,16 @@ function main()
|
||||||
config)
|
config)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
dkim ) _docker_image generate-dkim-config "${2:-2048}" ;;
|
dkim ) _docker_image generate-dkim-config "${2:-2048}" ;;
|
||||||
ssl ) _docker_image generate-ssl-certificate "$2" ;;
|
ssl ) _docker_image generate-ssl-certificate "${2}" ;;
|
||||||
* ) _usage ;;
|
* ) _usage ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|
||||||
relay)
|
relay)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
add-domain ) shift ; _docker_image addrelayhost "$@" ;;
|
add-domain ) shift ; _docker_image addrelayhost "${@}" ;;
|
||||||
add-auth ) shift ; _docker_image addsaslpassword "$@" ;;
|
add-auth ) shift ; _docker_image addsaslpassword "${@}" ;;
|
||||||
exclude-domain ) shift ; _docker_image excluderelaydomain "$@" ;;
|
exclude-domain ) shift ; _docker_image excluderelaydomain "${@}" ;;
|
||||||
* ) _usage ;;
|
* ) _usage ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
@ -296,7 +309,7 @@ function main()
|
||||||
debug)
|
debug)
|
||||||
shift ; case ${1:-} in
|
shift ; case ${1:-} in
|
||||||
fetchmail ) _docker_image debug-fetchmail ;;
|
fetchmail ) _docker_image debug-fetchmail ;;
|
||||||
fail2ban ) shift ; _docker_container fail2ban "$@" ;;
|
fail2ban ) shift ; _docker_container fail2ban "${@}" ;;
|
||||||
show-mail-logs ) _docker_container cat /var/log/mail/mail.log ;;
|
show-mail-logs ) _docker_container cat /var/log/mail/mail.log ;;
|
||||||
inspect ) _inspect ;;
|
inspect ) _inspect ;;
|
||||||
login )
|
login )
|
||||||
|
@ -305,16 +318,16 @@ function main()
|
||||||
then
|
then
|
||||||
_docker_container /bin/bash
|
_docker_container /bin/bash
|
||||||
else
|
else
|
||||||
_docker_container /bin/bash -c "$@"
|
_docker_container /bin/bash -c "${@}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
* ) _usage ;;
|
* ) _usage ; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* ) _usage ;;
|
* ) _usage ; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
_main "${@}"
|
||||||
_unset_vars
|
_unset_vars
|
||||||
|
|
|
@ -1,91 +1,108 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# version 0.1.0
|
||||||
|
#
|
||||||
|
# <INSERT TASK HERE>
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
. /usr/local/bin/helper_functions.sh
|
. /usr/local/bin/helper_functions.sh
|
||||||
|
|
||||||
# create date for log output
|
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
||||||
log_date=$(date +"%Y-%m-%d %H:%M:%S ")
|
echo "${LOG_DATE} Start check-for-changes script."
|
||||||
echo "${log_date} Start check-for-changes script."
|
|
||||||
|
|
||||||
# change directory
|
# ? Checks ------------------------------------------------
|
||||||
cd /tmp/docker-mailserver
|
|
||||||
|
cd /tmp/docker-mailserver || exit 1
|
||||||
|
|
||||||
# Check postfix-accounts.cf exist else break
|
# Check postfix-accounts.cf exist else break
|
||||||
if [ ! -f postfix-accounts.cf ]; then
|
if [[ ! -f postfix-accounts.cf ]]
|
||||||
echo "${log_date} postfix-accounts.cf is missing! This should not run! Exit!"
|
then
|
||||||
|
echo "${LOG_DATE} postfix-accounts.cf is missing! This should not run! Exit!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify checksum file exists; must be prepared by start-mailserver.sh
|
# Verify checksum file exists; must be prepared by start-mailserver.sh
|
||||||
if [ ! -f $CHKSUM_FILE ]; then
|
if [[ ! -f ${CHKSUM_FILE} ]]
|
||||||
echo "${log_date} ${CHKSUM_FILE} is missing! Start script failed? Exit!"
|
then
|
||||||
|
echo "${LOG_DATE} ${CHKSUM_FILE} is missing! Start script failed? Exit!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ? Actual script begins ----------------------------------
|
||||||
|
|
||||||
# Determine postmaster address, duplicated from start-mailserver.sh
|
# Determine postmaster address, duplicated from start-mailserver.sh
|
||||||
# This script previously didn't work when POSTMASTER_ADDRESS was empty
|
# This script previously didn't work when POSTMASTER_ADDRESS was empty
|
||||||
if [[ -n "${OVERRIDE_HOSTNAME}" ]]; then
|
if [[ -n ${OVERRIDE_HOSTNAME} ]]
|
||||||
DOMAINNAME=$(echo "${OVERRIDE_HOSTNAME}" | sed s/[^.]*.//)
|
then
|
||||||
|
DOMAINNAME="${OVERRIDE_HOSTNAME#*.}"
|
||||||
else
|
else
|
||||||
DOMAINNAME="$(hostname -d)"
|
DOMAINNAME="$(hostname -d)"
|
||||||
fi
|
fi
|
||||||
PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"
|
PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"
|
||||||
echo "${log_date} Using postmaster address ${PM_ADDRESS}"
|
echo "${LOG_DATE} Using postmaster address ${PM_ADDRESS}"
|
||||||
|
|
||||||
# Wait to make sure server is up before we start
|
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Run forever
|
while true
|
||||||
while true; do
|
do
|
||||||
|
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
||||||
|
|
||||||
# recreate logdate
|
# get chksum and check it, no need to lock config yet
|
||||||
log_date=$(date +"%Y-%m-%d %H:%M:%S ")
|
_monitored_files_checksums >"${CHKSUM_FILE}.new"
|
||||||
|
|
||||||
# Get chksum and check it, no need to lock config yet
|
if ! cmp --silent -- "${CHKSUM_FILE}" "${CHKSUM_FILE}.new"
|
||||||
monitored_files_checksums >"$CHKSUM_FILE.new"
|
then
|
||||||
|
echo "${LOG_DATE} Change detected"
|
||||||
if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then
|
changed=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
|
||||||
echo "${log_date} Change detected"
|
mv "${CHKSUM_FILE}.new" "${CHKSUM_FILE}"
|
||||||
changed=$(grep -Fxvf "$CHKSUM_FILE" "$CHKSUM_FILE.new" | sed 's/^[^ ]\+ //')
|
|
||||||
mv "$CHKSUM_FILE.new" "$CHKSUM_FILE"
|
|
||||||
|
|
||||||
# Bug alert! This overwrites the alias set by start-mailserver.sh
|
# Bug alert! This overwrites the alias set by start-mailserver.sh
|
||||||
# Take care that changes in one script are propagated to the other
|
# Take care that changes in one script are propagated to the other
|
||||||
|
|
||||||
|
# ! NEEDS FIX -----------------------------------------
|
||||||
|
# TODO FIX --------------------------------------------
|
||||||
|
# ! NEEDS EXTENSIONS ----------------------------------
|
||||||
|
# TODO Perform updates below conditionally too --------
|
||||||
# Also note that changes are performed in place and are not atomic
|
# Also note that changes are performed in place and are not atomic
|
||||||
# We should fix that and write to temporary files, stop, swap and start
|
# We should fix that and write to temporary files, stop, swap and start
|
||||||
|
|
||||||
# Lock configuration while working
|
# Lock configuration while working
|
||||||
# Not fixing indentation yet to reduce diff (fix later in separate commit)
|
|
||||||
(
|
(
|
||||||
flock -e 200
|
flock -e 200
|
||||||
|
|
||||||
for file in $changed; do
|
for file in ${changed}
|
||||||
case $file in
|
do
|
||||||
|
case ${file} in
|
||||||
/etc/letsencrypt/acme.json)
|
/etc/letsencrypt/acme.json)
|
||||||
for certdomain in $SSL_DOMAIN $HOSTNAME $DOMAINNAME; do
|
for certdomain in ${SSL_DOMAIN} ${HOSTNAME} ${DOMAINNAME}
|
||||||
if extractCertsFromAcmeJson "$certdomain"; then
|
do
|
||||||
|
if _extract_certs_from_acme "${certdomain}"
|
||||||
|
then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
#TODO: Perform updates below conditionally as well.
|
* ) _notify 'warn' 'file not found for certificate in check_for_changes.sh' ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
#regen postix aliases.
|
# regenerate postix aliases
|
||||||
echo "root: ${PM_ADDRESS}" > /etc/aliases
|
echo "root: ${PM_ADDRESS}" >/etc/aliases
|
||||||
if [ -f /tmp/docker-mailserver/postfix-aliases.cf ]; then
|
if [[ -f /tmp/docker-mailserver/postfix-aliases.cf ]]
|
||||||
cat /tmp/docker-mailserver/postfix-aliases.cf>>/etc/aliases
|
then
|
||||||
|
cat /tmp/docker-mailserver/postfix-aliases.cf >>/etc/aliases
|
||||||
fi
|
fi
|
||||||
postalias /etc/aliases
|
postalias /etc/aliases
|
||||||
|
|
||||||
#regen postfix accounts.
|
# regenerate postfix accounts
|
||||||
echo -n > /etc/postfix/vmailbox
|
echo -n >/etc/postfix/vmailbox
|
||||||
echo -n > /etc/dovecot/userdb
|
echo -n >/etc/dovecot/userdb
|
||||||
|
|
||||||
if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then
|
if [[ -f /tmp/docker-mailserver/postfix-accounts.cf ]] && [[ ${ENABLE_LDAP} -ne 1 ]]
|
||||||
|
then
|
||||||
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
|
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox
|
echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." >/etc/postfix/vmailbox
|
||||||
|
|
||||||
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
|
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
|
||||||
|
# shellcheck disable=SC1003
|
||||||
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
|
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
chown dovecot:dovecot /etc/dovecot/userdb
|
chown dovecot:dovecot /etc/dovecot/userdb
|
||||||
chmod 640 /etc/dovecot/userdb
|
chmod 640 /etc/dovecot/userdb
|
||||||
|
@ -93,111 +110,128 @@ if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then
|
||||||
sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf
|
sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
|
||||||
# rebuild relay host
|
# rebuild relay host
|
||||||
if [ ! -z "$RELAY_HOST" ]; then
|
if [[ -n ${RELAY_HOST} ]]
|
||||||
|
then
|
||||||
# keep old config
|
# keep old config
|
||||||
echo -n > /etc/postfix/sasl_passwd
|
echo -n >/etc/postfix/sasl_passwd
|
||||||
if [ ! -z "$SASL_PASSWD" ]; then
|
if [[ -n ${SASL_PASSWD} ]]
|
||||||
echo "$SASL_PASSWD" >> /etc/postfix/sasl_passwd
|
then
|
||||||
|
echo "${SASL_PASSWD}" >>/etc/postfix/sasl_passwd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# add domain-specific auth from config file
|
# add domain-specific auth from config file
|
||||||
if [ -f /tmp/docker-mailserver/postfix-sasl-password.cf ]; then
|
if [[ -f /tmp/docker-mailserver/postfix-sasl-password.cf ]]
|
||||||
(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-sasl-password.cf || true) | while read line; do
|
then
|
||||||
if ! echo "$line" | grep -q -e "\s*#"; then
|
(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-sasl-password.cf || true) | while read -r line
|
||||||
echo "$line" >> /etc/postfix/sasl_passwd
|
do
|
||||||
|
if ! echo "${line}" | grep -q -e "\s*#"
|
||||||
|
then
|
||||||
|
echo "${line}" >>/etc/postfix/sasl_passwd
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# add default relay
|
# add default relay
|
||||||
if [ ! -z "$RELAY_USER" ] && [ ! -z "$RELAY_PASSWORD" ]; then
|
if [[ -n "${RELAY_USER}" ]] && [[ -n "${RELAY_PASSWORD}" ]]
|
||||||
echo "[$RELAY_HOST]:$RELAY_PORT $RELAY_USER:$RELAY_PASSWORD" >> /etc/postfix/sasl_passwd
|
then
|
||||||
|
echo "[${RELAY_HOST}]:${RELAY_PORT} ${RELAY_USER}:${RELAY_PASSWORD}" >>/etc/postfix/sasl_passwd
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Creating users
|
# creating users ; 'pass' is encrypted
|
||||||
# 'pass' is encrypted
|
|
||||||
# comments and empty lines are ignored
|
# comments and empty lines are ignored
|
||||||
grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf | while IFS=$'|' read login pass
|
grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf | while IFS=$'|' read -r login pass
|
||||||
do
|
do
|
||||||
# Setting variables for better readability
|
user=$(echo "${login}" | cut -d @ -f1)
|
||||||
user=$(echo ${login} | cut -d @ -f1)
|
domain=$(echo "${login}" | cut -d @ -f2)
|
||||||
domain=$(echo ${login} | cut -d @ -f2)
|
|
||||||
|
|
||||||
user_attributes=""
|
user_attributes=""
|
||||||
# test if user has a defined quota
|
# test if user has a defined quota
|
||||||
if [ -f /tmp/docker-mailserver/dovecot-quotas.cf ]; then
|
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]
|
||||||
user_quota=($(grep "${user}@${domain}:" -i /tmp/docker-mailserver/dovecot-quotas.cf | tr ':' '\n'))
|
then
|
||||||
|
declare -a USER_QUOTA
|
||||||
|
IFS=':' ; read -r -a USER_QUOTA < <(grep "${user}@${domain}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
|
||||||
|
unset IFS
|
||||||
|
|
||||||
if [ ${#user_quota[@]} -eq 2 ]; then
|
[[ ${#USER_QUOTA[@]} -eq 2 ]] && user_attributes="${user_attributes}userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
|
||||||
user_attributes="${user_attributes}userdb_quota_rule=*:bytes=${user_quota[1]}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Let's go!
|
echo "${login} ${domain}/${user}/" >>/etc/postfix/vmailbox
|
||||||
echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox
|
|
||||||
# User database for dovecot has the following format:
|
# user database for dovecot has the following format:
|
||||||
# user:password:uid:gid:(gecos):home:(shell):extra_fields
|
# user:password:uid:gid:(gecos):home:(shell):extra_fields
|
||||||
# Example :
|
# example :
|
||||||
# ${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::userdb_mail=maildir:/var/mail/${domain}/${user}
|
# ${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::userdb_mail=maildir:/var/mail/${domain}/${user}
|
||||||
echo "${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::${user_attributes}" >> /etc/dovecot/userdb
|
echo "${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::${user_attributes}" >>/etc/dovecot/userdb
|
||||||
mkdir -p /var/mail/${domain}/${user}
|
mkdir -p "/var/mail/${domain}/${user}"
|
||||||
|
|
||||||
# Copy user provided sieve file, if present
|
if [[ -e /tmp/docker-mailserver/${login}.dovecot.sieve ]]
|
||||||
test -e /tmp/docker-mailserver/${login}.dovecot.sieve && cp /tmp/docker-mailserver/${login}.dovecot.sieve /var/mail/${domain}/${user}/.dovecot.sieve
|
then
|
||||||
echo ${domain} >> /tmp/vhost.tmp
|
cp "/tmp/docker-mailserver/${login}.dovecot.sieve" "/var/mail/${domain}/${user}/.dovecot.sieve"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${domain}" >>/tmp/vhost.tmp
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [ ! -z "$RELAY_HOST" ]; then
|
|
||||||
populate_relayhost_map
|
[[ -n ${RELAY_HOST} ]] && _populate_relayhost_map
|
||||||
fi
|
|
||||||
if [ -f /etc/postfix/sasl_passwd ]; then
|
|
||||||
|
if [[ -f /etc/postfix/sasl_passwd ]]
|
||||||
|
then
|
||||||
chown root:root /etc/postfix/sasl_passwd
|
chown root:root /etc/postfix/sasl_passwd
|
||||||
chmod 0600 /etc/postfix/sasl_passwd
|
chmod 0600 /etc/postfix/sasl_passwd
|
||||||
fi
|
fi
|
||||||
if [ -f postfix-virtual.cf ]; then
|
|
||||||
# regen postfix aliases
|
if [[ -f postfix-virtual.cf ]]
|
||||||
echo -n > /etc/postfix/virtual
|
then
|
||||||
echo -n > /etc/postfix/regexp
|
# regenerate postfix aliases
|
||||||
if [ -f /tmp/docker-mailserver/postfix-virtual.cf ]; then
|
echo -n >/etc/postfix/virtual
|
||||||
# Copying virtual file
|
echo -n >/etc/postfix/regexp
|
||||||
|
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-virtual.cf ]]
|
||||||
|
then
|
||||||
cp -f /tmp/docker-mailserver/postfix-virtual.cf /etc/postfix/virtual
|
cp -f /tmp/docker-mailserver/postfix-virtual.cf /etc/postfix/virtual
|
||||||
(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-virtual.cf || true) | while read from to
|
|
||||||
|
# the `to` seems to be important; don't delete it
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-virtual.cf || true) | while read -r from to
|
||||||
do
|
do
|
||||||
# Setting variables for better readability
|
uname=$(echo "${from}" | cut -d @ -f1)
|
||||||
uname=$(echo ${from} | cut -d @ -f1)
|
domain=$(echo "${from}" | cut -d @ -f2)
|
||||||
domain=$(echo ${from} | cut -d @ -f2)
|
|
||||||
# if they are equal it means the line looks like: "user1 other@domain.tld"
|
# if they are equal it means the line looks like: "user1 other@domain.tld"
|
||||||
test "$uname" != "$domain" && echo ${domain} >> /tmp/vhost.tmp
|
[ "${uname}" != "${domain}" ] && echo "${domain}" >>/tmp/vhost.tmp
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [ -f /tmp/docker-mailserver/postfix-regexp.cf ]; then
|
|
||||||
# Copying regexp alias file
|
if [[ -f /tmp/docker-mailserver/postfix-regexp.cf ]]
|
||||||
|
then
|
||||||
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
|
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
|
||||||
sed -i -e '/^virtual_alias_maps/{
|
sed -i -e '/^virtual_alias_maps/{
|
||||||
s/ regexp:.*//
|
s/ regexp:.*//
|
||||||
s/$/ regexp:\/etc\/postfix\/regexp/
|
s/$/ regexp:\/etc\/postfix\/regexp/
|
||||||
}' /etc/postfix/main.cf
|
}' /etc/postfix/main.cf
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# Set vhost
|
|
||||||
if [ -f /tmp/vhost.tmp ]; then
|
|
||||||
cat /tmp/vhost.tmp | sort | uniq > /etc/postfix/vhost && rm /tmp/vhost.tmp
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set right new if needed
|
if [[ -f /tmp/vhost.tmp ]]
|
||||||
if [ `find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | grep -c .` != 0 ]; then
|
then
|
||||||
|
# shellcheck disable=SC2002
|
||||||
|
cat /tmp/vhost.tmp | sort | uniq >/etc/postfix/vhost && rm /tmp/vhost.tmp
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | grep -c .) -ne 0 ]]
|
||||||
|
then
|
||||||
chown -R 5000:5000 /var/mail
|
chown -R 5000:5000 /var/mail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Restart of the postfix
|
|
||||||
supervisorctl restart postfix
|
supervisorctl restart postfix
|
||||||
|
|
||||||
# Prevent restart of dovecot when smtp_only=1
|
# prevent restart of dovecot when smtp_only=1
|
||||||
if [ ! $SMTP_ONLY = 1 ]; then
|
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
|
||||||
supervisorctl restart dovecot
|
) 200<postfix-accounts.cf # end lock
|
||||||
fi
|
fi
|
||||||
|
|
||||||
) 200<postfix-accounts.cf # end lock
|
sleep 1
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 1
|
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# fail2ban-wrapper.sh, version 0.0.1
|
|
||||||
|
# version 0.1.0
|
||||||
#
|
#
|
||||||
# You cannot start fail2ban in some foreground mode and
|
# You cannot start fail2ban in some foreground mode and
|
||||||
# it's more or less important that docker doesn't kill
|
# it's more or less important that docker doesn't kill
|
||||||
|
@ -21,14 +22,12 @@ trap "/usr/bin/fail2ban-client stop" SIGINT
|
||||||
trap "/usr/bin/fail2ban-client stop" SIGTERM
|
trap "/usr/bin/fail2ban-client stop" SIGTERM
|
||||||
trap "/usr/bin/fail2ban-client reload" SIGHUP
|
trap "/usr/bin/fail2ban-client reload" SIGHUP
|
||||||
|
|
||||||
# start fail2ban
|
|
||||||
/usr/bin/fail2ban-client start
|
/usr/bin/fail2ban-client start
|
||||||
|
|
||||||
# lets give fail2ban some time to start
|
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# wait until fail2ban is dead (triggered by trap)
|
# wait until fail2ban is dead (triggered by trap)
|
||||||
while kill -0 "`cat /var/run/fail2ban/fail2ban.pid`"; do
|
while kill -0 "$(cat /var/run/fail2ban/fail2ban.pid)"
|
||||||
|
do
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,62 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# expects mask prefix length and the digit
|
# version 0.1.1
|
||||||
function _mask_ip_digit() {
|
#
|
||||||
if [[ $1 -ge 8 ]]; then
|
# Provides varous helpers.
|
||||||
|
|
||||||
|
|
||||||
|
# ? IP and CIDR -------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function _mask_ip_digit()
|
||||||
|
{
|
||||||
|
if [[ ${1} -ge 8 ]]
|
||||||
|
then
|
||||||
MASK=255
|
MASK=255
|
||||||
else
|
elif [[ ${1} -le 0 ]]
|
||||||
if [[ $1 -le 0 ]]; then
|
then
|
||||||
MASK=0
|
MASK=0
|
||||||
else
|
else
|
||||||
VALUES=('0' '128' '192' '224' '240' '248' '252' '254' '255')
|
VALUES=(0 128 192 224 240 248 252 254 255)
|
||||||
MASK=${VALUES[$1]}
|
MASK=${VALUES[${1}]}
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
echo $(($2 & $MASK))
|
local DVAL=${2}
|
||||||
|
((DVAL&=MASK))
|
||||||
|
|
||||||
|
echo "${DVAL}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# transforms a specific ip with CIDR suffix like 1.2.3.4/16
|
# Transforms a specific IP with CIDR suffix
|
||||||
# to subnet with cidr suffix like 1.2.0.0/16
|
# like 1.2.3.4/16 to subnet with cidr suffix
|
||||||
function _sanitize_ipv4_to_subnet_cidr() {
|
# like 1.2.0.0/16.
|
||||||
IP=${1%%/*}
|
# Assumes correct IP and subnet are provided.
|
||||||
PREFIX_LENGTH=${1#*/}
|
function _sanitize_ipv4_to_subnet_cidr()
|
||||||
|
{
|
||||||
|
local DIGIT_PREFIX_LENGTH="${1#*/}"
|
||||||
|
|
||||||
# split IP by . into digits
|
declare -a MASKED_DIGITS
|
||||||
DIGITS=(${IP//./ })
|
declare -a DIGITS
|
||||||
|
IFS='.' ; read -r -a DIGITS < <(echo "${1%%/*}") ; unset IFS
|
||||||
|
|
||||||
# mask digits according to prefix length
|
for ((i = 0 ; i < 4 ; i++))
|
||||||
MASKED_DIGITS=()
|
do
|
||||||
DIGIT_PREFIX_LENGTH="$PREFIX_LENGTH"
|
MASKED_DIGITS[i]=$(_mask_ip_digit "${DIGIT_PREFIX_LENGTH}" "${DIGITS[i]}")
|
||||||
for DIGIT in "${DIGITS[@]}"; do
|
DIGIT_PREFIX_LENGTH=$((DIGIT_PREFIX_LENGTH - 8))
|
||||||
MASKED_DIGITS+=($(_mask_ip_digit $DIGIT_PREFIX_LENGTH $DIGIT))
|
|
||||||
DIGIT_PREFIX_LENGTH=$(($DIGIT_PREFIX_LENGTH - 8))
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# output masked ip plus prefix length
|
echo "${MASKED_DIGITS[0]}.${MASKED_DIGITS[1]}.${MASKED_DIGITS[2]}.${MASKED_DIGITS[3]}/${1#*/}"
|
||||||
echo ${MASKED_DIGITS[0]}.${MASKED_DIGITS[1]}.${MASKED_DIGITS[2]}.${MASKED_DIGITS[3]}/$PREFIX_LENGTH
|
|
||||||
}
|
}
|
||||||
|
export -f _sanitize_ipv4_to_subnet_cidr
|
||||||
|
|
||||||
# extracts certificates from acme.json and returns 0 if found
|
|
||||||
function extractCertsFromAcmeJson() {
|
|
||||||
WHAT=$1
|
|
||||||
|
|
||||||
|
# ? ACME certs --------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function _extract_certs_from_acme()
|
||||||
|
{
|
||||||
|
local KEY
|
||||||
|
# shellcheck disable=SC2002
|
||||||
KEY=$(cat /etc/letsencrypt/acme.json | python -c "
|
KEY=$(cat /etc/letsencrypt/acme.json | python -c "
|
||||||
import sys,json
|
import sys,json
|
||||||
acme = json.load(sys.stdin)
|
acme = json.load(sys.stdin)
|
||||||
|
@ -47,10 +64,13 @@ for key, value in acme.items():
|
||||||
certs = value['Certificates']
|
certs = value['Certificates']
|
||||||
for cert in certs:
|
for cert in certs:
|
||||||
if 'domain' in cert and 'key' in cert:
|
if 'domain' in cert and 'key' in cert:
|
||||||
if 'main' in cert['domain'] and cert['domain']['main'] == '$WHAT' or 'sans' in cert['domain'] and '$WHAT' in cert['domain']['sans']:
|
if 'main' in cert['domain'] and cert['domain']['main'] == '${1}' or 'sans' in cert['domain'] and '${1}' in cert['domain']['sans']:
|
||||||
print cert['key']
|
print cert['key']
|
||||||
break
|
break
|
||||||
")
|
")
|
||||||
|
|
||||||
|
local CERT
|
||||||
|
# shellcheck disable=SC2002
|
||||||
CERT=$(cat /etc/letsencrypt/acme.json | python -c "
|
CERT=$(cat /etc/letsencrypt/acme.json | python -c "
|
||||||
import sys,json
|
import sys,json
|
||||||
acme = json.load(sys.stdin)
|
acme = json.load(sys.stdin)
|
||||||
|
@ -58,26 +78,35 @@ for key, value in acme.items():
|
||||||
certs = value['Certificates']
|
certs = value['Certificates']
|
||||||
for cert in certs:
|
for cert in certs:
|
||||||
if 'domain' in cert and 'certificate' in cert:
|
if 'domain' in cert and 'certificate' in cert:
|
||||||
if 'main' in cert['domain'] and cert['domain']['main'] == '$WHAT' or 'sans' in cert['domain'] and '$WHAT' in cert['domain']['sans']:
|
if 'main' in cert['domain'] and cert['domain']['main'] == '${1}' or 'sans' in cert['domain'] and '${1}' in cert['domain']['sans']:
|
||||||
print cert['certificate']
|
print cert['certificate']
|
||||||
break
|
break
|
||||||
")
|
")
|
||||||
|
|
||||||
if [[ -n "${KEY}${CERT}" ]]; then
|
if [[ -n "${KEY}${CERT}" ]]
|
||||||
mkdir -p /etc/letsencrypt/live/"$HOSTNAME"/
|
then
|
||||||
echo $KEY | base64 -d >/etc/letsencrypt/live/"$HOSTNAME"/key.pem || exit 1
|
mkdir -p "/etc/letsencrypt/live/${HOSTNAME}/"
|
||||||
echo $CERT | base64 -d >/etc/letsencrypt/live/"$HOSTNAME"/fullchain.pem || exit 1
|
|
||||||
echo "Cert found in /etc/letsencrypt/acme.json for $WHAT"
|
echo "${KEY}" | base64 -d >/etc/letsencrypt/live/"${HOSTNAME}"/key.pem || exit 1
|
||||||
|
echo "${CERT}" | base64 -d >/etc/letsencrypt/live/"${HOSTNAME}"/fullchain.pem || exit 1
|
||||||
|
echo "Cert found in /etc/letsencrypt/acme.json for ${1}"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
export -f _extract_certs_from_acme
|
||||||
|
|
||||||
|
|
||||||
|
# ? Notification ------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
declare -A DEFAULT_VARS
|
declare -A DEFAULT_VARS
|
||||||
DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}"
|
DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:=0}"
|
||||||
|
|
||||||
function notify () {
|
function _notify()
|
||||||
|
{
|
||||||
c_red="\e[0;31m"
|
c_red="\e[0;31m"
|
||||||
c_green="\e[0;32m"
|
c_green="\e[0;32m"
|
||||||
c_brown="\e[0;33m"
|
c_brown="\e[0;33m"
|
||||||
|
@ -85,101 +114,101 @@ function notify () {
|
||||||
c_bold="\033[1m"
|
c_bold="\033[1m"
|
||||||
c_reset="\e[0m"
|
c_reset="\e[0m"
|
||||||
|
|
||||||
notification_type=$1
|
notification_type=${1}
|
||||||
notification_msg=$2
|
notification_msg=${2}
|
||||||
notification_format=$3
|
notification_format=${3}
|
||||||
msg=""
|
msg=""
|
||||||
|
|
||||||
case "${notification_type}" in
|
case "${notification_type}" in
|
||||||
'taskgrp')
|
'taskgrp' ) msg="${c_bold}${notification_msg}${c_reset}" ;;
|
||||||
msg="${c_bold}${notification_msg}${c_reset}"
|
'task' )
|
||||||
;;
|
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} -eq 1 ]]
|
||||||
'task')
|
then
|
||||||
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
|
|
||||||
msg=" ${notification_msg}${c_reset}"
|
msg=" ${notification_msg}${c_reset}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
'inf')
|
'inf' )
|
||||||
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
|
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} -eq 1 ]]
|
||||||
|
then
|
||||||
msg="${c_green} * ${notification_msg}${c_reset}"
|
msg="${c_green} * ${notification_msg}${c_reset}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
'started')
|
'started' ) msg="${c_green} ${notification_msg}${c_reset}" ;;
|
||||||
msg="${c_green} ${notification_msg}${c_reset}"
|
'warn' ) msg="${c_brown} Warning ${notification_msg}${c_reset}" ;;
|
||||||
;;
|
'err' ) msg="${c_blue} Error ${notification_msg}${c_reset}" ;;
|
||||||
'warn')
|
'fatal' ) msg="${c_red} Fatal Error: ${notification_msg}${c_reset}" ;;
|
||||||
msg="${c_brown} * ${notification_msg}${c_reset}"
|
* ) msg="" ;;
|
||||||
;;
|
|
||||||
'err')
|
|
||||||
msg="${c_red} * ${notification_msg}${c_reset}"
|
|
||||||
;;
|
|
||||||
'fatal')
|
|
||||||
msg="${c_red}Error: ${notification_msg}${c_reset}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
msg=""
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
case "${notification_format}" in
|
case "${notification_format}" in
|
||||||
'n')
|
'n' ) options="-ne" ;;
|
||||||
options="-ne"
|
* ) options="-e" ;;
|
||||||
;;
|
|
||||||
*)
|
|
||||||
options="-e"
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
[[ ! -z "${msg}" ]] && echo $options "${msg}"
|
[[ -n "${msg}" ]] && echo "${options}" "${msg}"
|
||||||
}
|
}
|
||||||
|
export -f _notify
|
||||||
|
|
||||||
|
|
||||||
|
# ? Relay Host Map ----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
# setup /etc/postfix/relayhost_map
|
# setup /etc/postfix/relayhost_map
|
||||||
# --
|
# --
|
||||||
# @domain1.com [smtp.mailgun.org]:587
|
# @domain1.com [smtp.mailgun.org]:587
|
||||||
# @domain2.com [smtp.mailgun.org]:587
|
# @domain2.com [smtp.mailgun.org]:587
|
||||||
# @domain3.com [smtp.mailgun.org]:587
|
# @domain3.com [smtp.mailgun.org]:587
|
||||||
function populate_relayhost_map() {
|
function _populate_relayhost_map()
|
||||||
|
{
|
||||||
echo -n > /etc/postfix/relayhost_map
|
echo -n > /etc/postfix/relayhost_map
|
||||||
chown root:root /etc/postfix/relayhost_map
|
chown root:root /etc/postfix/relayhost_map
|
||||||
chmod 0600 /etc/postfix/relayhost_map
|
chmod 0600 /etc/postfix/relayhost_map
|
||||||
|
|
||||||
if [ -f /tmp/docker-mailserver/postfix-relaymap.cf ]; then
|
if [[ -f /tmp/docker-mailserver/postfix-relaymap.cf ]]
|
||||||
notify 'inf' "Adding relay mappings from postfix-relaymap.cf"
|
then
|
||||||
# Keep lines which are not a comment *and* have a destination.
|
_notify 'inf' "Adding relay mappings from postfix-relaymap.cf"
|
||||||
sed -n '/^\s*[^#[:space:]]\S*\s\+\S/p' /tmp/docker-mailserver/postfix-relaymap.cf \
|
# keep lines which are not a comment *and* have a destination.
|
||||||
>> /etc/postfix/relayhost_map
|
sed -n '/^\s*[^#[:space:]]\S*\s\+\S/p' /tmp/docker-mailserver/postfix-relaymap.cf >> /etc/postfix/relayhost_map
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{
|
{
|
||||||
# Note: Won't detect domains when lhs has spaces (but who does that?!).
|
# note: won't detect domains when lhs has spaces (but who does that?!)
|
||||||
sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf
|
sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
[ -f /tmp/docker-mailserver/postfix-virtual.cf ] &&
|
|
||||||
sed -n '/^\s*[^#[:space:]]/ s/^\s*[^@[:space:]]*@\(\S\+\)\s.*/\1/p' /tmp/docker-mailserver/postfix-virtual.cf
|
[ -f /tmp/docker-mailserver/postfix-virtual.cf ] && sed -n '/^\s*[^#[:space:]]/ s/^\s*[^@[:space:]]*@\(\S\+\)\s.*/\1/p' /tmp/docker-mailserver/postfix-virtual.cf
|
||||||
} | while read domain; do
|
} | while read -r domain
|
||||||
if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map &&
|
do
|
||||||
! grep -qs -e "^\s*@${domain}\s*$" /tmp/docker-mailserver/postfix-relaymap.cf; then
|
# domain not already present *and* not ignored
|
||||||
# Domain not already present *and* not ignored.
|
if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map && ! grep -qs -e "^\s*@${domain}\s*$" /tmp/docker-mailserver/postfix-relaymap.cf
|
||||||
notify 'inf' "Adding relay mapping for ${domain}"
|
then
|
||||||
echo "@${domain} [$RELAY_HOST]:$RELAY_PORT" >> /etc/postfix/relayhost_map
|
_notify 'inf' "Adding relay mapping for ${domain}"
|
||||||
|
echo "@${domain} [${RELAY_HOST}]:${RELAY_PORT}" >> /etc/postfix/relayhost_map
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
export -f _populate_relayhost_map
|
||||||
|
|
||||||
# File storing the checksums of the monitored files.
|
|
||||||
|
# ? File checksums ----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# file storing the checksums of the monitored files.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
||||||
|
|
||||||
# Compute checksums of monitored files.
|
# Compute checksums of monitored files.
|
||||||
function monitored_files_checksums() {
|
function _monitored_files_checksums()
|
||||||
|
{
|
||||||
(
|
(
|
||||||
cd /tmp/docker-mailserver
|
cd /tmp/docker-mailserver || exit 1
|
||||||
# (2>/dev/null to ignore warnings about files that don't exist)
|
|
||||||
exec sha512sum 2>/dev/null -- \
|
exec sha512sum 2>/dev/null -- \
|
||||||
postfix-accounts.cf \
|
postfix-accounts.cf \
|
||||||
postfix-virtual.cf \
|
postfix-virtual.cf \
|
||||||
postfix-aliases.cf \
|
postfix-aliases.cf \
|
||||||
dovecot-quotas.cf \
|
dovecot-quotas.cf \
|
||||||
/etc/letsencrypt/acme.json \
|
/etc/letsencrypt/acme.json \
|
||||||
"/etc/letsencrypt/live/$HOSTNAME/key.pem" \
|
"/etc/letsencrypt/live/${HOSTNAME}/key.pem" \
|
||||||
"/etc/letsencrypt/live/$HOSTNAME/fullchain.pem"
|
"/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem"
|
||||||
)
|
)
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
export -f _monitored_files_checksums
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# postfix-wrapper.sh, version 0.1.0
|
|
||||||
|
# version 0.1.0
|
||||||
#
|
#
|
||||||
# You cannot start postfix in some foreground mode and
|
# You cannot start postfix in some foreground mode and
|
||||||
# it's more or less important that docker doesn't kill
|
# it's more or less important that docker doesn't kill
|
||||||
|
@ -21,14 +22,11 @@ trap "service postfix stop" SIGINT
|
||||||
trap "service postfix stop" SIGTERM
|
trap "service postfix stop" SIGTERM
|
||||||
trap "service postfix reload" SIGHUP
|
trap "service postfix reload" SIGHUP
|
||||||
|
|
||||||
# start postfix
|
|
||||||
service postfix start
|
service postfix start
|
||||||
|
|
||||||
# lets give postfix some time to start
|
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# wait until postfix is dead (triggered by trap)
|
# wait until postfix is dead (triggered by trap)
|
||||||
while kill -0 "`cat /var/spool/postfix/pid/master.pid`"; do
|
while kill -0 "$(cat /var/spool/postfix/pid/master.pid)"
|
||||||
|
do
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,53 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# postsrsd-wrapper.sh, version 0.2.2
|
|
||||||
|
|
||||||
if [ -n "$SRS_DOMAINNAME" ]; then
|
# version 0.1.0
|
||||||
domain_name="$SRS_DOMAINNAME"
|
|
||||||
elif [ -n "$OVERRIDE_HOSTNAME" ]; then
|
|
||||||
domain_name="${OVERRIDE_HOSTNAME#*.}"
|
|
||||||
elif [ -n "$DOMAINNAME" ]; then
|
|
||||||
domain_name="$DOMAINNAME"
|
|
||||||
else
|
|
||||||
domain_name=$(hostname -d)
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i -e "s/localdomain/${domain_name}/g" /etc/default/postsrsd
|
function _generate_secret()
|
||||||
|
{
|
||||||
postsrsd_secret_file='/etc/postsrsd.secret'
|
( umask 0077 ; dd if=/dev/urandom bs=24 count=1 2>/dev/null | base64 -w0 > "${1}" )
|
||||||
postsrsd_state_dir='/var/mail-state/etc-postsrsd'
|
|
||||||
postsrsd_state_secret_file="${postsrsd_state_dir}/postsrsd.secret"
|
|
||||||
|
|
||||||
generate_secret() {
|
|
||||||
( umask 0077
|
|
||||||
dd if=/dev/urandom bs=24 count=1 2>/dev/null | base64 -w0 > "$1" )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -n "$SRS_SECRET" ]; then
|
if [[ -n ${SRS_DOMAINNAME} ]]
|
||||||
( umask 0077
|
then
|
||||||
echo "$SRS_SECRET" | tr ',' '\n' > "$postsrsd_secret_file" )
|
NEW_DOMAIN_NAME="${SRS_DOMAINNAME}"
|
||||||
|
elif [[ -n ${OVERRIDE_HOSTNAME} ]]
|
||||||
|
then
|
||||||
|
NEW_DOMAIN_NAME="${OVERRIDE_HOSTNAME#*.}"
|
||||||
|
elif [[ -n ${DOMAINNAME} ]]
|
||||||
|
then
|
||||||
|
NEW_DOMAIN_NAME="${DOMAINNAME}"
|
||||||
else
|
else
|
||||||
if [ "$ONE_DIR" = 1 ]; then
|
NEW_DOMAIN_NAME=$(hostname -d)
|
||||||
if [ ! -f "$postsrsd_state_secret_file" ]; then
|
fi
|
||||||
install -d -m 0775 "$postsrsd_state_dir"
|
|
||||||
generate_secret "$postsrsd_state_secret_file"
|
sed -i -e "s/localdomain/${NEW_DOMAIN_NAME}/g" /etc/default/postsrsd
|
||||||
|
|
||||||
|
POSTSRSD_SECRET_FILE='/etc/postsrsd.secret'
|
||||||
|
POSTSRSD_STATE_DIR='/var/mail-state/etc-postsrsd'
|
||||||
|
POSTSRSD_STATE_SECRET_FILE="${POSTSRSD_STATE_DIR}/postsrsd.secret"
|
||||||
|
|
||||||
|
if [[ -n ${SRS_SECRET} ]]
|
||||||
|
then
|
||||||
|
( umask 0077 ; echo "${SRS_SECRET}" | tr ',' '\n' > "${POSTSRSD_SECRET_FILE}" )
|
||||||
|
else
|
||||||
|
if [[ ${ONE_DIR} -eq 1 ]]
|
||||||
|
then
|
||||||
|
if [[ ! -f ${POSTSRSD_STATE_SECRET_FILE} ]]
|
||||||
|
then
|
||||||
|
install -d -m 0775 "${POSTSRSD_STATE_DIR}"
|
||||||
|
_generate_secret "${POSTSRSD_STATE_SECRET_FILE}"
|
||||||
fi
|
fi
|
||||||
install -m 0400 "$postsrsd_state_secret_file" "$postsrsd_secret_file"
|
|
||||||
elif [ ! -f "$postsrsd_secret_file" ]; then
|
install -m 0400 "${POSTSRSD_STATE_SECRET_FILE}" "${POSTSRSD_SECRET_FILE}"
|
||||||
generate_secret "$postsrsd_secret_file"
|
elif [[ ! -f ${POSTSRSD_SECRET_FILE} ]]
|
||||||
|
then
|
||||||
|
_generate_secret "${POSTSRSD_SECRET_FILE}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$SRS_EXCLUDE_DOMAINS" ]; then
|
if [[ -n ${SRS_EXCLUDE_DOMAINS} ]]
|
||||||
sed -i -e "s/^#\?SRS_EXCLUDE_DOMAINS=.*$/SRS_EXCLUDE_DOMAINS=$SRS_EXCLUDE_DOMAINS/g" /etc/default/postsrsd
|
then
|
||||||
|
sed -i -e "s/^#\?SRS_EXCLUDE_DOMAINS=.*$/SRS_EXCLUDE_DOMAINS=${SRS_EXCLUDE_DOMAINS}/g" /etc/default/postsrsd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/etc/init.d/postsrsd start
|
/etc/init.d/postsrsd start
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
[supervisord]
|
[supervisord]
|
||||||
nodaemon=true
|
nodaemon=true
|
||||||
|
strip_ansi=true
|
||||||
|
|
||||||
[program:mailserver]
|
[program:mailserver]
|
||||||
startsecs=0
|
startsecs=0
|
||||||
|
|
Loading…
Reference in a new issue