Git initial commit

This commit is contained in:
Lars Hahn 2023-09-17 10:55:54 +02:00
commit 25259ab8e1
9 changed files with 453 additions and 0 deletions

9
LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-mailcow
Ansible role to setup mailcow on a node.

50
defaults/main.yml Executable file
View File

@ -0,0 +1,50 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
domain_external: "my-domain.tld"
mailcow_instance: "{{ domain_external.split('.')[:-1] | join('') | regex_replace('[^a-zA-Z0-9]+','') }}"
mailcow_db_name: mailcow
mailcow_db_root_pass: rootpass
mailcow_db_user: mailcow
mailcow_db_pass: userpass
mailcow_cert_subjects:
CN: "mail.{{ domain_external }}"
C: "DE"
L: "Willich"
O: "mailcow"
OU: "mailcow"
ST: "NRW"
mailcow_http: 80
mailcow_https: 443
mailcow_docker_ipv4_cidr: 172.22.1
mailcow_docker_ipv6_cidr: fd4d:6169:6c63:6f77::/64
mailcow_dovecot_target: 127.0.0.1:19991
mailcow_sql_target: 127.0.0.1:13306
mailcow_solr_target: 127.0.0.1:18983
mailcow_redis_target: 127.0.0.1:7654
mailcow_sieve_port: 4190
mailcow_other_configs: []
mailcow_timezone: Europe/Berlin
mailcow_gc_time: 7200
mailcow_solr_heap_mb: 1024
mailcow_redis_log_count: 9999
mailcow_sogo_timeout_m: 480
mailcow_use_letsencrypt: true
mailcow_use_clamav: true
mailcow_use_sogo: true
mailcow_use_solr: true
mailcow_ip_check: true
mailcow_http_check: true
mailcow_no_http: true

9
handlers/main.yml Executable file
View File

@ -0,0 +1,9 @@
---
- name: restart mailcow docker containers
command:
cmd: "{{ item }}"
chdir: "{{ mailcow_folder }}/"
loop:
- docker-compose down
- docker-compose up -d
when: not mailcow_start.changed

17
meta/main.yml Executable file
View File

@ -0,0 +1,17 @@
---
galaxy_info:
role_name: mailcow
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup mailcow based on docker.
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 10
galaxy_tags:
- mailcow
dependencies:
- docker

112
tasks/main.yml Executable file
View File

@ -0,0 +1,112 @@
---
# Basic
- name: install requirements for mailcow
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- python3-openssl
# Mailcow Setup
- name: clone mailcow repository
git:
repo: https://github.com/mailcow/mailcow-dockerized
dest: "{{ mailcow_folder }}"
update: no
# Mailcow Config
- name: setup mailcow config
template:
src: opt/mailcow/mailcow.conf.j2
dest: "{{ mailcow_folder }}/mailcow.conf"
mode: 0600
notify: restart mailcow docker containers
- name: setup env link to mailcow conf
file:
src: "{{ mailcow_folder }}/mailcow.conf"
dest: "{{ mailcow_folder }}/.env"
state: link
- name: setup ssl folder
file:
path: "{{ mailcow_ssl_path }}"
state: directory
- name: generate dh params
openssl_dhparam:
path: "{{ mailcow_ssl_path }}/dhparams.pem"
size: 2048
notify: restart mailcow docker containers
when: not (mailcow_use_letsencrypt | default('false'))
- name: use predefined dh params
copy:
remote_src: yes
src: "{{ mailcow_folder }}/data/assets/ssl-example/dhparams.pem"
dest: "{{ mailcow_ssl_path }}/dhparams.pem"
notify: restart mailcow docker containers
when: (mailcow_use_letsencrypt | default('false'))
- name: generate ssl private key
openssl_privatekey:
path: "{{ mailcow_ssl_path }}/key.pem"
size: 4096
register: key_generation
notify: restart mailcow docker containers
- name: generate ssl cert request
openssl_csr:
path: "{{ mailcow_ssl_path }}/csr.pem"
privatekey_path: "{{ mailcow_ssl_path }}/key.pem"
common_name: "{{ mailcow_cert_subjects.CN }}"
country_name: "{{ mailcow_cert_subjects.C }}"
locality_name: "{{ mailcow_cert_subjects.L }}"
organization_name: "{{ mailcow_cert_subjects.O }}"
organizational_unit_name: "{{ mailcow_cert_subjects.OU }}"
state_or_province_name: "{{ mailcow_cert_subjects.ST }}"
when: key_generation.changed
register: cert_request
- name: generate selfsigned certificate
openssl_certificate:
provider: selfsigned
path: "{{ mailcow_ssl_path }}/cert.pem"
privatekey_path: "{{ mailcow_ssl_path }}/key.pem"
csr_path: "{{ mailcow_ssl_path }}/csr.pem"
when: cert_request.changed
notify: restart mailcow docker containers
- name: set http redirect to https
template:
src: opt/mailcow/data/conf/nginx/redirect.conf.j2
dest: "{{ mailcow_folder }}/data/conf/nginx/redirect.conf"
notify: restart mailcow docker containers
when: mailcow_no_http
# Mailcow build
- name: check mailcow image availability
command: docker image list
changed_when: false
register: docker_image_list
- name: pull images for mailcow containers
command:
cmd: docker-compose pull
chdir: "{{ mailcow_folder }}/"
when: "'mailcow' not in docker_image_list.stdout"
- name: find running mailcow containers
command:
cmd: "{% raw %}docker ps --format '{{.Image}}'{% endraw %}"
chdir: "{{ mailcow_folder }}/"
changed_when: false
register: docker_running_list
- name: start mailcow containers if not running
command:
cmd: docker-compose up -d
chdir: "{{ mailcow_folder }}/"
when: "'mailcow' not in docker_running_list.stdout"
register: mailcow_start

View File

@ -0,0 +1,14 @@
server {
root /web;
listen 80 default_server;
listen [::]:80 default_server;
include /etc/nginx/conf.d/server_name.active;
if ( $request_uri ~* "%0A|%0D" ) { return 403; }
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
location / {
return 301 https://$host$uri$is_args$args;
}
}

View File

@ -0,0 +1,236 @@
# ------------------------------
# mailcow web ui configuration
# ------------------------------
# example.org is _not_ a valid hostname, use a fqdn here.
# Default admin user is "admin"
# Default password is "moohoo"
MAILCOW_HOSTNAME=mail.{{ domain_external }}
# Password hash algorithm
# Only certain password hash algorithm are supported. For a fully list of supported schemes,
# see https://mailcow.github.io/mailcow-dockerized-docs/model-passwd/
MAILCOW_PASS_SCHEME=BLF-CRYPT
# ------------------------------
# SQL database configuration
# ------------------------------
DBNAME={{ mailcow_db_name }}
DBUSER={{ mailcow_db_user }}
# Please use long, random alphanumeric strings (A-Za-z0-9)
DBPASS={{ mailcow_db_pass }}
DBROOT={{ mailcow_db_root_pass }}
# ------------------------------
# HTTP/S Bindings
# ------------------------------
# You should use HTTPS, but in case of SSL offloaded reverse proxies:
# Might be important: This will also change the binding within the container.
# If you use a proxy within Docker, point it to the ports you set below.
# Do _not_ use IP:PORT in HTTP(S)_BIND or HTTP(S)_PORT
# IMPORTANT: Do not use port 8081, 9081 or 65510!
# Example: HTTP_BIND=1.2.3.4
# For IPv4 and IPv6 leave it empty: HTTP_BIND= & HTTPS_PORT=
# For IPv6 see https://mailcow.github.io/mailcow-dockerized-docs/firststeps-ip_bindings/
HTTP_PORT={{ mailcow_http }}
HTTP_BIND=
HTTPS_PORT={{ mailcow_https }}
HTTPS_BIND=
# ------------------------------
# Other bindings
# ------------------------------
# You should leave that alone
# Format: 11.22.33.44:25 or 12.34.56.78:465 etc.
SMTP_PORT=25
SMTPS_PORT=465
SUBMISSION_PORT=587
IMAP_PORT=143
IMAPS_PORT=993
POP_PORT=110
POPS_PORT=995
SIEVE_PORT={{ mailcow_sieve_port }}
DOVEADM_PORT={{ mailcow_dovecot_target }}
SQL_PORT={{ mailcow_sql_target }}
SOLR_PORT={{ mailcow_solr_target }}
REDIS_PORT={{ mailcow_redis_target }}
# Your timezone
# See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones
# Use the row named 'TZ database name' + pay attention for 'Notes' row
TZ={{ mailcow_timezone }}
# Fixed project name
# Please use lowercase letters only
COMPOSE_PROJECT_NAME={{ mailcow_instance }}
# Set this to "allow" to enable the anyone pseudo user. Disabled by default.
# When enabled, ACL can be created, that apply to "All authenticated users"
# This should probably only be activated on mail hosts, that are used exclusivly by one organisation.
# Otherwise a user might share data with too many other users.
ACL_ANYONE=disallow
# Garbage collector cleanup
# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring
# How long should objects remain in the garbage until they are being deleted? (value in minutes)
# Check interval is hourly
MAILDIR_GC_TIME={{ mailcow_gc_time }}
# Additional SAN for the certificate
#
# You can use wildcard records to create specific names for every domain you add to mailcow.
# Example: Add domains "example.com" and "example.net" to mailcow, change ADDITIONAL_SAN to a value like:
#ADDITIONAL_SAN=imap.*,smtp.*
# This will expand the certificate to "imap.example.com", "smtp.example.com", "imap.example.net", "imap.example.net"
# plus every domain you add in the future.
#
# You can also just add static names...
#ADDITIONAL_SAN=srv1.example.net
# ...or combine wildcard and static names:
#ADDITIONAL_SAN=imap.*,srv1.example.com
#
ADDITIONAL_SAN=
# Additional server names for mailcow UI
#
# Specify alternative addresses for the mailcow UI to respond to
# This is useful when you set mail.* as ADDITIONAL_SAN and want to make sure mail.maildomain.com will always point to the mailcow UI.
# If the server name does not match a known site, Nginx decides by best-guess and may redirect users to the wrong web root.
# You can understand this as server_name directive in Nginx.
# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f
ADDITIONAL_SERVER_NAMES=
# Skip running ACME (acme-mailcow, Let's Encrypt certs) - y/n
SKIP_LETS_ENCRYPT={{ 'n' if (mailcow_use_letsencrypt | default('true') | bool) else 'y' }}
# Create seperate certificates for all domains - y/n
# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames
# see https://wiki.dovecot.org/SSL/SNIClientSupport
ENABLE_SSL_SNI=n
# Skip IPv4 check in ACME container - y/n
SKIP_IP_CHECK={{ 'n' if (mailcow_ip_check | default('true') | bool) else 'y' }}
# Skip HTTP verification in ACME container - y/n
SKIP_HTTP_VERIFICATION={{ 'n' if (mailcow_http_check | default('true') | bool) else 'y' }}
# Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n
SKIP_CLAMD={{ 'n' if (mailcow_use_clamav | default('true') | bool) else 'y' }}
# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n
SKIP_SOGO={{ 'n' if (mailcow_use_sogo | default('true') | bool) else 'y' }}
# Skip Solr on low-memory systems or if you do not want to store a readable index of your mails in solr-vol-1.
SKIP_SOLR={{ 'n' if (mailcow_use_solr | default('true') | bool) else 'y' }}
# Solr heap size in MB, there is no recommendation, please see Solr docs.
# Solr is a prone to run OOM and should be monitored. Unmonitored Solr setups are not recommended.
SOLR_HEAP={{ mailcow_solr_heap_mb | default(1024) }}
# Allow admins to log into SOGo as email user (without any password)
ALLOW_ADMIN_EMAIL_LOGIN=n
# Enable watchdog (watchdog-mailcow) to restart unhealthy containers
USE_WATCHDOG=y
# Send watchdog notifications by mail (sent from watchdog@MAILCOW_HOSTNAME)
# CAUTION:
# 1. You should use external recipients
# 2. Mails are sent unsigned (no DKIM)
# 3. If you use DMARC, create a separate DMARC policy ("v=DMARC1; p=none;" in _dmarc.MAILCOW_HOSTNAME)
# Multiple rcpts allowed, NO quotation marks, NO spaces
#WATCHDOG_NOTIFY_EMAIL=a@example.com,b@example.com,c@example.com
#WATCHDOG_NOTIFY_EMAIL=
# Notify about banned IP (includes whois lookup)
WATCHDOG_NOTIFY_BAN=n
# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message.
#WATCHDOG_SUBJECT=
# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.
# https://www.servercow.de/mailcow?lang=en
# https://www.servercow.de/mailcow?lang=de
# No data is collected. Opt-in and anonymous.
# Will only work with unmodified mailcow setups.
WATCHDOG_EXTERNAL_CHECKS=n
# Max log lines per service to keep in Redis logs
LOG_LINES={{ mailcow_redis_log_count }}
# Internal IPv4 /24 subnet, format n.n.n (expands to n.n.n.0/24)
# Use private IPv4 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses
IPV4_NETWORK={{ mailcow_docker_ipv4_cidr }}
# Internal IPv6 subnet in fc00::/7
# Use private IPv6 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses
IPV6_NETWORK={{ mailcow_docker_ipv6_cidr }}
# Use this IPv4 for outgoing connections (SNAT)
#SNAT_TO_SOURCE=
# Use this IPv6 for outgoing connections (SNAT)
#SNAT6_TO_SOURCE=
# Create or override an API key for the web UI
# You _must_ define API_ALLOW_FROM, which is a comma separated list of IPs
# An API key defined as API_KEY has read-write access
# An API key defined as API_KEY_READ_ONLY has read-only access
# Allowed chars for API_KEY and API_KEY_READ_ONLY: a-z, A-Z, 0-9, -
# You can define API_KEY and/or API_KEY_READ_ONLY
#API_KEY=
#API_KEY_READ_ONLY=
#API_ALLOW_FROM=172.22.1.1,127.0.0.1
# mail_home is ~/Maildir
MAILDIR_SUB=Maildir
# SOGo session timeout in minutes
SOGO_EXPIRE_SESSION={{ mailcow_sogo_timeout_m }}
# DOVECOT_MASTER_USER and DOVECOT_MASTER_PASS must both be provided. No special chars.
# Empty by default to auto-generate master user and password on start.
# User expands to DOVECOT_MASTER_USER@mailcow.local
# LEAVE EMPTY IF UNSURE
DOVECOT_MASTER_USER=
# LEAVE EMPTY IF UNSURE
DOVECOT_MASTER_PASS=
# Let's Encrypt registration contact information
# Optional: Leave empty for none
# This value is only used on first order!
# Setting it at a later point will require the following steps:
# https://mailcow.github.io/mailcow-dockerized-docs/debug-reset-tls/
ACME_CONTACT=
{% for config_line in mailcow_other_configs %}
{{ config_line }}
{% endfor %}

3
vars/main.yml Executable file
View File

@ -0,0 +1,3 @@
---
mailcow_folder: "{{ cloud_apps }}/mailcow"
mailcow_ssl_path: "{{ mailcow_folder }}/data/assets/ssl"