first commit
This commit is contained in:
commit
9f5e2946f5
325
mailcow.yml
Normal file
325
mailcow.yml
Normal file
@ -0,0 +1,325 @@
|
||||
---
|
||||
|
||||
- name: mailcow
|
||||
hosts: ds9.dedyn.io jarvis.olmusic.de
|
||||
tasks:
|
||||
|
||||
- name: Clone mailcow git repo
|
||||
become: yes
|
||||
git:
|
||||
repo: 'https://github.com/mailcow/mailcow-dockerized.git'
|
||||
version: "master"
|
||||
umask: '022'
|
||||
update: false
|
||||
dest: "/home/docker/mailcow-dockerized"
|
||||
|
||||
- name: disable Postfix Port
|
||||
ansible.builtin.replace:
|
||||
path: /etc/postfix/master.cf
|
||||
regexp: '^smtp *inet'
|
||||
replace: '#smtp inet'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart postfix
|
||||
|
||||
- name: Generate mailcow.conf file
|
||||
shell: ./generate_config.sh
|
||||
environment:
|
||||
MAILCOW_HOSTNAME: "mail.{{inventory_hostname}}"
|
||||
MAILCOW_TZ: "Europe/Berlin"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
chdir: "/home/docker/mailcow-dockerized"
|
||||
creates: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
notify: Restart mailcow
|
||||
|
||||
- name: disable mailcow letsencrypt (done by traefik)
|
||||
ansible.builtin.replace:
|
||||
path: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
regexp: '^SKIP_LETS_ENCRYPT=n'
|
||||
replace: 'SKIP_LETS_ENCRYPT=y'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart mailcow
|
||||
|
||||
- name: change http port 80->9080 (needed by traefik)
|
||||
ansible.builtin.replace:
|
||||
path: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
regexp: '^HTTP_PORT=80'
|
||||
replace: 'HTTP_PORT=9080'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart mailcow
|
||||
|
||||
- name: change http bind to localhost (needed by traefik)
|
||||
ansible.builtin.replace:
|
||||
path: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
regexp: '^HTTP_BIND=.*'
|
||||
replace: 'HTTP_BIND=192.168.41.1'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart mailcow
|
||||
|
||||
- name: change http port 443->9443 (needed by traefik)
|
||||
ansible.builtin.replace:
|
||||
path: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
regexp: '^HTTPS_PORT=443'
|
||||
replace: 'HTTPS_PORT=9443'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart mailcow
|
||||
|
||||
- name: change httpd bind to localhost (needed by traefik)
|
||||
ansible.builtin.replace:
|
||||
path: /home/docker/mailcow-dockerized/mailcow.conf
|
||||
regexp: '^HTTPS_BIND=.*'
|
||||
replace: 'HTTPS_BIND=192.168.41.1'
|
||||
backup: yes
|
||||
notify:
|
||||
- Restart mailcow
|
||||
|
||||
- name: Start/initialize mailcow
|
||||
ansible.builtin.shell: docker-compose up -d
|
||||
args:
|
||||
chdir: /home/docker/mailcow-dockerized
|
||||
creates: /home/docker/var-lib-docker/volumes/mailcowdockerized_vmail-vol-1/_data/sieve/global_sieve_after.sieve
|
||||
|
||||
- wait_for:
|
||||
path: /home/docker/var-lib-docker/volumes/mailcowdockerized_vmail-vol-1/_data/sieve/global_sieve_after.sieve
|
||||
|
||||
- name: /home/docker/mailcow-dockerized/adminpw.sh
|
||||
blockinfile:
|
||||
path: /home/docker/mailcow-dockerized/adminpw.sh
|
||||
create: yes
|
||||
mode: 0750
|
||||
owner: root
|
||||
group: docker
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
source /home/docker/mailcow-dockerized/mailcow.conf
|
||||
if [[ -z ${DBUSER} ]] || [[ -z ${DBPASS} ]] || [[ -z ${DBNAME} ]]
|
||||
then
|
||||
echo "Cannot find mailcow.conf, make sure this script is run from within the mailcow folder."
|
||||
exit 1
|
||||
fi
|
||||
# Change password
|
||||
random=$(pwgen -s 32 1)
|
||||
password=$(docker exec -it $(docker ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r')
|
||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';"
|
||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
|
||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, active) VALUES ('admin', '${password}', 1, 1);"
|
||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';"
|
||||
|
||||
echo "${random}" >/home/docker/mailcow-dockerized/.adminpw
|
||||
chmod 400 /home/docker/mailcow-dockerized/.adminpw
|
||||
backup: yes
|
||||
validate: /bin/bash -n %s
|
||||
|
||||
- name: /home/docker/mailcow-dockerized/adminpw.sh shebang
|
||||
lineinfile:
|
||||
path: /home/docker/mailcow-dockerized/adminpw.sh
|
||||
insertbefore: BOF
|
||||
line: "#!/bin/bash"
|
||||
|
||||
- name: Generate mailcow admin password
|
||||
ansible.builtin.shell: /home/docker/mailcow-dockerized/adminpw.sh
|
||||
args:
|
||||
chdir: /home/docker/mailcow-dockerized
|
||||
creates: /home/docker/mailcow-dockerized/.adminpw
|
||||
|
||||
- name: /home/docker/traefik/providers/mailcow.yml Mailcow<->Traefik provider
|
||||
blockinfile:
|
||||
path: /home/docker/traefik/providers/mailcow.yml
|
||||
create: yes
|
||||
mode: 0444
|
||||
owner: root
|
||||
group: docker
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
http:
|
||||
routers:
|
||||
mailcow:
|
||||
rule: "Host(`mail.{{inventory_hostname}}`)"
|
||||
service: mailcow
|
||||
entryPoints:
|
||||
- "https"
|
||||
tls:
|
||||
certresolver:
|
||||
- "letsencrypt"
|
||||
middlewares: secHeaders@file
|
||||
services:
|
||||
mailcow:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.41.1:9080"
|
||||
|
||||
- name: /usr/local/sbin/autoupdate.d/mailcow.update
|
||||
blockinfile:
|
||||
path: /usr/local/sbin/autoupdate.d/mailcow.update
|
||||
mode: "0400"
|
||||
owner: root
|
||||
group: root
|
||||
create: yes
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
# mailcow-dockerized
|
||||
if [ -f /home/docker/mailcow-dockerized/update.sh ]
|
||||
then
|
||||
g_echo_ok "Prüfe MailCow Update"
|
||||
cd /home/docker/mailcow-dockerized
|
||||
if ./update.sh -c
|
||||
then
|
||||
g_echo_warn "Installiere MailCow Update $(./update.sh -c)"
|
||||
./update.sh --no-update-compose -f 2>&1 | sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/" | tee $g_tmp/mailcow-update || g_echo_error "MailCow Update fehlgeschlagen $(cat $g_tmp/mailcow-update)"
|
||||
fi
|
||||
fi
|
||||
# take letsencrypt-certs from traefik
|
||||
. /home/docker/mailcow-dockerized/mailcow.conf
|
||||
cat /home/docker/traefik/letsencrypt/acme.json | jq -r ".letsencrypt.Certificates[] | select(.domain.main==\"$MAILCOW_HOSTNAME\") | .key" | base64 -d >/home/docker/mailcow-dockerized/data/assets/ssl/key.pem
|
||||
cat /home/docker/traefik/letsencrypt/acme.json | jq -r ".letsencrypt.Certificates[] | select(.domain.main==\"$MAILCOW_HOSTNAME\") | .certificate" | base64 -d >/home/docker/mailcow-dockerized/data/assets/ssl/cert.pem
|
||||
docker restart $(docker ps -qaf name=postfix-mailcow)
|
||||
docker restart $(docker ps -qaf name=dovecot-mailcow)
|
||||
backup: yes
|
||||
validate: /bin/bash -n %s
|
||||
|
||||
- name: /usr/local/sbin/backup.d/mailcow.backup
|
||||
blockinfile:
|
||||
path: /usr/local/sbin/backup.d/mailcow.backup
|
||||
mode: "0400"
|
||||
owner: root
|
||||
group: root
|
||||
create: yes
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
cd /home/docker/mailcow-dockerized
|
||||
mkdir -p ${BACKUPDIR}/mailcow-backup_script
|
||||
BACKUP_LOCATION=${BACKUPDIR}/mailcow-backup_script /home/docker/mailcow-dockerized/helper-scripts/backup_and_restore.sh backup all --delete-days 3 || g_echo_error "MailCow-Backup (mysql crypt redis) war nicht erfolgreich"
|
||||
backup: yes
|
||||
validate: /bin/bash -n %s
|
||||
|
||||
- name: /home/docker/autoconfig.{{inventory_hostname}}/docker-compose.yml Container Configuration
|
||||
blockinfile:
|
||||
path: /home/docker/autoconfig.{{inventory_hostname}}/docker-compose.yml
|
||||
create: yes
|
||||
mode: 0440
|
||||
owner: root
|
||||
group: docker
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
||||
block: |
|
||||
version: '3.6'
|
||||
services:
|
||||
autoconfig.{{inventory_hostname}}:
|
||||
image: nginx:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./htdocs:/usr/share/nginx/html:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
# HTTPS
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.rule=Host(`autoconfig.{{ ansible_facts['nodename'] }}`) || Host(`autodiscover.{{ ansible_facts['nodename'] }}`)
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.entrypoints=https
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.tls=true
|
||||
# Proxy to service-port
|
||||
- traefik.http.services.autoconfig-{{ ansible_facts['hostname'] }}.loadbalancer.server.port=80
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.service=autoconfig-{{ ansible_facts['hostname'] }}
|
||||
# cert via letsencrypt
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.tls.certresolver=letsencrypt
|
||||
# Traefik network
|
||||
- traefik.docker.network=traefik
|
||||
# activate secHeaders@file
|
||||
- traefik.http.routers.autoconfig-{{ ansible_facts['hostname'] }}.middlewares=secHeaders@file
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
backup: yes
|
||||
notify: Restart autoconfig
|
||||
|
||||
- name: /home/docker/autoconfig.{{inventory_hostname}}/htdocs/index.html
|
||||
blockinfile:
|
||||
path: /home/docker/autoconfig.{{inventory_hostname}}/htdocs/index.html
|
||||
create: yes
|
||||
mode: 0444
|
||||
owner: root
|
||||
group: root
|
||||
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
|
||||
block: |
|
||||
OK
|
||||
backup: yes
|
||||
|
||||
- name: /home/docker/autoconfig.{{inventory_hostname}}/htdocs/mail/config-v1.1.xml
|
||||
blockinfile:
|
||||
path: /home/docker/autoconfig.{{inventory_hostname}}/htdocs/mail/config-v1.1.xml
|
||||
create: yes
|
||||
mode: 0444
|
||||
owner: root
|
||||
group: root
|
||||
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
|
||||
block: |
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="mail.{{inventory_hostname}}">
|
||||
<domain>{{inventory_hostname}}</domain>
|
||||
<displayName>{{inventory_hostname}}</displayName>
|
||||
<displayShortName>{{ ansible_facts['hostname'] }}</displayShortName>
|
||||
<incomingServer type="imap">
|
||||
<hostname>mail.{{inventory_hostname}}</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>mail.{{inventory_hostname}}</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>
|
||||
backup: yes
|
||||
|
||||
- name: Allow all access to tcp port 25 (smtp)
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: '25'
|
||||
proto: tcp
|
||||
|
||||
- name: Allow all access to tcp port 465 (submission/tls)
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: '465'
|
||||
proto: tcp
|
||||
|
||||
- name: Allow all access to tcp port 587 (submission)
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: '587'
|
||||
proto: tcp
|
||||
|
||||
- name: Allow all access to tcp port 993 (imaps)
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: '993'
|
||||
proto: tcp
|
||||
|
||||
|
||||
handlers:
|
||||
- name: Restart mailcow
|
||||
ansible.builtin.shell: docker-compose up -d
|
||||
args:
|
||||
chdir: /home/docker/mailcow-dockerized
|
||||
|
||||
- name: Restart autoconfig
|
||||
ansible.builtin.shell: docker-compose up -d
|
||||
args:
|
||||
chdir: /home/docker/autoconfig.{{inventory_hostname}}
|
||||
|
||||
|
||||
- name: Restart postfix
|
||||
service:
|
||||
name: postfix
|
||||
state: restarted
|
||||
|
Loading…
Reference in New Issue
Block a user