Add Stalwart mailserver.
This commit is contained in:
parent
bb4bdfca70
commit
03cf2817a4
10 changed files with 206 additions and 5 deletions
48
README.md
48
README.md
|
@ -3,14 +3,29 @@ This repository contains all the files I use to manage services hosted on [viyur
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
Ansible:
|
### Ansible
|
||||||
|
Install Ansible:
|
||||||
```
|
```
|
||||||
sudo apt install -y ansible
|
sudo apt install -y ansible
|
||||||
```
|
```
|
||||||
|
|
||||||
Setup SSL certificates with Certbot beforehand:
|
### SSL certificates
|
||||||
|
Install Certbot:
|
||||||
```
|
```
|
||||||
sudo apt install -y certbot python3-certbot-dns-ovh
|
sudo apt install -y certbot python3-certbot-dns-ovh python3-certbot-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Request certificates:
|
||||||
|
```
|
||||||
|
# For the NGINX reverse proxy
|
||||||
|
sudo certbot certonly --nginx -d viyurz.fr,*.viyurz.fr
|
||||||
|
|
||||||
|
# For Coturn
|
||||||
|
bash <(wget -q -O - https://github.com/zerossl/zerossl-bot/raw/master/get-zerosslbot.sh)
|
||||||
|
sudo zerossl-bot certonly --nginx -m viyurz@viyurz.fr -d turn.viyurz.fr
|
||||||
|
|
||||||
|
# For the mailserver
|
||||||
|
sudo certbot certonly --nginx -d mail.viyurz.fr
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,3 +45,30 @@ After that, you can create a root cronjob to run this playbook without requiring
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we leave `selected_projects` empty to backup all projects.
|
Here we leave `selected_projects` empty to backup all projects.
|
||||||
|
|
||||||
|
|
||||||
|
## Mailserver
|
||||||
|
When starting the container for the first time, run the initial setup:
|
||||||
|
```
|
||||||
|
docker exec -it mailserver /bin/sh /usr/local/bin/configure.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
After that you need to tell Stalwart where the SSL certificate files are in:
|
||||||
|
```
|
||||||
|
/opt/stalwart-mail/etc/common/tls.toml
|
||||||
|
|
||||||
|
[certificate."default"]
|
||||||
|
cert = "file:///etc/fullchain.pem"
|
||||||
|
private-key = "file:///etc/privkey.pem"
|
||||||
|
```
|
||||||
|
|
||||||
|
And configure the user Stalwart will run as:
|
||||||
|
```
|
||||||
|
/opt/stalwart-mail/etc/common/server.toml
|
||||||
|
|
||||||
|
[server.run-as]
|
||||||
|
user = "mail"
|
||||||
|
group = "mail"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then follow the end of the [Official Installation Guide](https://stalw.art/docs/install/docker#take-note-of-the-administrator-password).
|
||||||
|
|
10
env.yml
10
env.yml
|
@ -42,6 +42,7 @@ projects:
|
||||||
- etebase
|
- etebase
|
||||||
- hedgedoc
|
- hedgedoc
|
||||||
- homepage
|
- homepage
|
||||||
|
- mailserver
|
||||||
- reverse-proxy
|
- reverse-proxy
|
||||||
- searxng
|
- searxng
|
||||||
- synapse
|
- synapse
|
||||||
|
@ -53,6 +54,7 @@ projects:
|
||||||
projects_to_backup:
|
projects_to_backup:
|
||||||
- etebase
|
- etebase
|
||||||
- hedgedoc
|
- hedgedoc
|
||||||
|
- mailserver
|
||||||
- synapse
|
- synapse
|
||||||
- uptime-kuma
|
- uptime-kuma
|
||||||
- vaultwarden
|
- vaultwarden
|
||||||
|
@ -79,6 +81,10 @@ ports:
|
||||||
etebase: 3735
|
etebase: 3735
|
||||||
hedgedoc: 8086
|
hedgedoc: 8086
|
||||||
homepage: 8082
|
homepage: 8082
|
||||||
|
mailserver_smtp: 1025
|
||||||
|
mailserver_smtps: 1465
|
||||||
|
mailserver_imaps: 1993
|
||||||
|
mailserver_jmap: 1443
|
||||||
searxng: 8083
|
searxng: 8083
|
||||||
synapse: 8008
|
synapse: 8008
|
||||||
syncthing_discosrv: 8443
|
syncthing_discosrv: 8443
|
||||||
|
@ -98,6 +104,7 @@ users:
|
||||||
hedgedoc: 1004
|
hedgedoc: 1004
|
||||||
hedgedoc_mysql: 1005
|
hedgedoc_mysql: 1005
|
||||||
homepage: 8686
|
homepage: 8686
|
||||||
|
mailserver: 8
|
||||||
searxng: 977
|
searxng: 977
|
||||||
searxng_redis: 999
|
searxng_redis: 999
|
||||||
synapse: 991
|
synapse: 991
|
||||||
|
@ -115,6 +122,9 @@ volumes:
|
||||||
etebase_datadir: /mnt/etebasedata
|
etebase_datadir: /mnt/etebasedata
|
||||||
hedgedoc_mysql_datadir: /mnt/hedgedoc/mysql-data
|
hedgedoc_mysql_datadir: /mnt/hedgedoc/mysql-data
|
||||||
hedgedoc_configdir: /mnt/hedgedoc/config
|
hedgedoc_configdir: /mnt/hedgedoc/config
|
||||||
|
mailserver_datadir: /mnt/mailserverdata
|
||||||
|
mailserver_tls_certificate_file: "/etc/letsencrypt/live/mail.{{ domain }}/fullchain.pem"
|
||||||
|
mailserver_tls_certificate_key_file: "/etc/letsencrypt/live/mail.{{ domain }}/privkey.pem"
|
||||||
synapse_datadir: /mnt/synapsedata
|
synapse_datadir: /mnt/synapsedata
|
||||||
synapse_postgres_datadir: /mnt/synapsepgdata
|
synapse_postgres_datadir: /mnt/synapsepgdata
|
||||||
syncthing_datadir: "{{ cifs_mounts['syncthing']['path'] }}"
|
syncthing_datadir: "{{ cifs_mounts['syncthing']['path'] }}"
|
||||||
|
|
22
roles/mailserver/tasks/backup.yml
Normal file
22
roles/mailserver/tasks/backup.yml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
- name:
|
||||||
|
become: true
|
||||||
|
block:
|
||||||
|
- name: Create borg backup
|
||||||
|
command:
|
||||||
|
cmd: |
|
||||||
|
borg create
|
||||||
|
--compression=lzma
|
||||||
|
"{{ borg_repodir }}::{{ role_name }}-{now:%Y-%m-%d_%H-%M-%S}"
|
||||||
|
{{ volumes['mailserver_datadir'] }}
|
||||||
|
environment:
|
||||||
|
BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}"
|
||||||
|
|
||||||
|
- name: Prune borg repository
|
||||||
|
command:
|
||||||
|
cmd: |
|
||||||
|
borg prune
|
||||||
|
--glob-archives='{{ role_name }}-*'
|
||||||
|
{{ borg_prune_options }}
|
||||||
|
{{ borg_repodir }}
|
||||||
|
environment:
|
||||||
|
BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}"
|
9
roles/mailserver/tasks/main.yml
Normal file
9
roles/mailserver/tasks/main.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
- name: Include backup tasks
|
||||||
|
include_tasks:
|
||||||
|
file: backup.yml
|
||||||
|
when: run_backup | default(false) | bool
|
||||||
|
|
||||||
|
- name: Include update tasks
|
||||||
|
include_tasks:
|
||||||
|
file: update.yml
|
||||||
|
when: run_update | default(false) | bool
|
78
roles/mailserver/tasks/update.yml
Normal file
78
roles/mailserver/tasks/update.yml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
- name: "Create {{ mailserver_project_dir }} project directory"
|
||||||
|
file:
|
||||||
|
path: "{{ mailserver_project_dir }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Template docker-compose.yaml to project directory
|
||||||
|
template:
|
||||||
|
src: docker-compose.yaml
|
||||||
|
dest: "{{ mailserver_project_dir }}/docker-compose.yaml"
|
||||||
|
owner: "{{ ansible_env['USER'] }}"
|
||||||
|
group: "{{ ansible_env['USER'] }}"
|
||||||
|
mode: '640'
|
||||||
|
|
||||||
|
- name: "Create directory {{ volumes['mailserver_datadir'] }} with correct permissions"
|
||||||
|
file:
|
||||||
|
path: "{{ volumes['mailserver_datadir'] }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ users['mailserver'] + uid_shift }}"
|
||||||
|
group: "{{ users['mailserver'] + uid_shift }}"
|
||||||
|
mode: '770'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Set limited permissions on certificate directories
|
||||||
|
file:
|
||||||
|
path: "/etc/{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '751'
|
||||||
|
become: true
|
||||||
|
loop:
|
||||||
|
- letsencrypt
|
||||||
|
- letsencrypt/live
|
||||||
|
- letsencrypt/archive
|
||||||
|
|
||||||
|
- name: Set limited permissions on certificate directories
|
||||||
|
file:
|
||||||
|
path: "/etc/letsencrypt/{{ item }}/mail.{{ domain }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: "{{ host_uid }}"
|
||||||
|
mode: '550'
|
||||||
|
become: true
|
||||||
|
loop:
|
||||||
|
- live
|
||||||
|
- archive
|
||||||
|
|
||||||
|
- name: Set limited permissions on certificate key file
|
||||||
|
file:
|
||||||
|
path: "/etc/letsencrypt/live/mail.{{ domain }}/privkey.pem"
|
||||||
|
owner: root
|
||||||
|
group: "{{ host_uid }}"
|
||||||
|
mode: '640'
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Pull project services
|
||||||
|
community.docker.docker_compose:
|
||||||
|
project_src: "{{ mailserver_project_dir }}"
|
||||||
|
recreate: never
|
||||||
|
pull: true
|
||||||
|
debug: true
|
||||||
|
when: docker_pull_images | bool
|
||||||
|
register: mailserver_docker_compose_pull_result
|
||||||
|
|
||||||
|
- name: Display pulled image(s) name
|
||||||
|
set_fact:
|
||||||
|
mailserver_pulled_images: "{{ mailserver_pulled_images | default([]) + [item.pulled_image.name] }}"
|
||||||
|
loop: "{{ mailserver_docker_compose_pull_result['actions'] | default([]) | selectattr('pulled_image', 'defined') }}"
|
||||||
|
|
||||||
|
- name: Include backup tasks
|
||||||
|
include_tasks:
|
||||||
|
file: backup.yml
|
||||||
|
# Make a backup if we didn't already make one and we pulled a new image
|
||||||
|
when: not run_backup and mailserver_pulled_images is defined
|
||||||
|
|
||||||
|
- name: Create/Restart project services
|
||||||
|
community.docker.docker_compose:
|
||||||
|
project_src: "{{ mailserver_project_dir }}"
|
14
roles/mailserver/templates/docker-compose.yaml
Normal file
14
roles/mailserver/templates/docker-compose.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
services:
|
||||||
|
mailserver:
|
||||||
|
image: docker.io/stalwartlabs/mail-server:latest
|
||||||
|
container_name: mailserver
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "{{ ports['mailserver_smtp'] }}:25"
|
||||||
|
- {{ ports['mailserver_smtps'] }}:465
|
||||||
|
- {{ ports['mailserver_imaps'] }}:993
|
||||||
|
- {{ ports['mailserver_jmap'] }}:443
|
||||||
|
volumes:
|
||||||
|
- {{ volumes['mailserver_tls_certificate_file'] }}:/etc/fullchain.pem
|
||||||
|
- {{ volumes['mailserver_tls_certificate_key_file'] }}:/etc/privkey.pem
|
||||||
|
- {{ volumes['mailserver_datadir' ] }}:/opt/stalwart-mail
|
1
roles/mailserver/vars/main.yml
Normal file
1
roles/mailserver/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
mailserver_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
flush ruleset
|
flush ruleset
|
||||||
|
|
||||||
# Forward Syncthing relay traffic from port {{ ports['syncthing_relaysrv'] }} to 22067
|
|
||||||
table inet nat {
|
table inet nat {
|
||||||
chain prerouting {
|
chain prerouting {
|
||||||
type nat hook prerouting priority dstnat;
|
type nat hook prerouting priority dstnat;
|
||||||
iif eth0 tcp dport {{ ports['syncthing_relaysrv'] }} redirect to :22067
|
iif eth0 tcp dport {{ ports['syncthing_relaysrv'] }} redirect to :22067
|
||||||
|
iif eth0 tcp dport 25 redirect to :{{ ports['mailserver_smtp'] }}
|
||||||
|
iif eth0 tcp dport 465 redirect to :{{ ports['mailserver_smtps'] }}
|
||||||
|
iif eth0 tcp dport 993 redirect to :{{ ports['mailserver_imaps'] }}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +59,10 @@ table inet filter {
|
||||||
tcp dport { http, https } accept
|
tcp dport { http, https } accept
|
||||||
|
|
||||||
# SSH
|
# SSH
|
||||||
tcp dport 995 accept
|
tcp dport ssh accept
|
||||||
|
|
||||||
|
# SMTP/IMAP
|
||||||
|
tcp dport { {{ ports['mailserver_smtp'] }}, {{ ports['mailserver_smtps'] }}, {{ ports['mailserver_imaps'] }} } accept
|
||||||
|
|
||||||
# Syncthing
|
# Syncthing
|
||||||
tcp dport { {{ ports['syncthing_tcp'] }}, 22067 } accept
|
tcp dport { {{ ports['syncthing_tcp'] }}, 22067 } accept
|
||||||
|
|
|
@ -113,6 +113,24 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# JMAP
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
|
server_name mail.{{ domain }};
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass https://127.0.0.1:{{ ports['mailserver_jmap'] }};
|
||||||
|
|
||||||
|
# Websocket
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# SearXNG
|
# SearXNG
|
||||||
server {
|
server {
|
||||||
listen 443 ssl http2;
|
listen 443 ssl http2;
|
||||||
|
|
|
@ -25,3 +25,5 @@ synapse_secrets:
|
||||||
vaultwarden_secrets:
|
vaultwarden_secrets:
|
||||||
# Generate with: docker exec --rm -ti docker.io/vaultwarden/server:alpine /vaultwarden hash
|
# Generate with: docker exec --rm -ti docker.io/vaultwarden/server:alpine /vaultwarden hash
|
||||||
admin_token_hash:
|
admin_token_hash:
|
||||||
|
smtp_username:
|
||||||
|
smtp_password:
|
||||||
|
|
Loading…
Reference in a new issue