Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# replatform

![replatform logo](img/replatform.jpeg)
![replatform logo](img/replatform_logo.jpg)

Run your own websites and email accounts using a platform you control.

Expand Down
3 changes: 1 addition & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
- [ ] Allow only necessary ports via ufw
- [ ] investigate ssl cert expiry
- [ ] Add mail-tester.com to docs
- [ ] Migrate to Debian 12 (Bookworm)
- [ ] Add fail2ban to stop brute force attacks

### In Progress



### Done

- [x] Migrate to Debian 12 (Bookworm)
- [x] Fix mail server reload after cert update
- Add to certbot post hook
- systemctl reload postfix
Expand Down
1 change: 1 addition & 0 deletions configure_dovecot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
template:
src: templates/etc_dovecot_passwd.j2
dest: /etc/dovecot/passwd
notify: reload dovecot

- name: Ensure sieve directories exist
file:
Expand Down
2 changes: 1 addition & 1 deletion configure_postfix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
line: "myorigin = /etc/mailname"

- regexp: "^mydestination"
line: "mydestination = $myhostname, myplatform.dataengineering.co.ke, localhost.dataengineering.co.ke, localhost"
line: "mydestination = $myhostname, localhost.$mydomain, localhost"

- regexp: "^mynetworks" # Relay mail from host only
line: "mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128"
Expand Down
29 changes: 19 additions & 10 deletions configure_spamassassin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,26 @@
state: present
notify: restart spamass-milter

- name: Configure spamd via /etc/default/spamassassin
- name: Configure spamd via /etc/default/{{ spamassassin_service_name }}
lineinfile:
dest: "/etc/default/spamassassin"
dest: "/etc/default/{{ spamassassin_service_name }}"
state: present
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
with_items:
- regexp: "^CRON=" # Update spam rules nightly
line: "CRON=1"
regexp: "^OPTIONS=" # run spamd with non-root debian-spamd user
line: 'OPTIONS="--create-prefs --max-children 5 --helper-home-dir=/var/lib/spamassassin -u debian-spamd -g debian-spamd -x"'
notify: restart spamassassin daemon

- regexp: "^OPTIONS=" # run spamd with non-root debian-spamd user
line: 'OPTIONS="--create-prefs --max-children 5 --helper-home-dir=/var/lib/spamassassin -u debian-spamd -g debian-spamd -x"'

- name: Enable nightly spam rule updates via CRON (Bullseye only, superseded by spamassassin-maintenance.timer on Bookworm)
lineinfile:
dest: "/etc/default/{{ spamassassin_service_name }}"
state: present
regexp: "^CRON="
line: "CRON=1"
when: ansible_distribution_major_version | int < 12
notify: restart spamassassin daemon

- name: Enable and start the systemd timer that updates spam rules nightly (Bookworm only)
service:
name: spamassassin-maintenance.timer
state: started
enabled: yes
when: ansible_distribution_major_version | int >= 12
39 changes: 39 additions & 0 deletions generate_hostname_records.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
- name: Extract dkim record value for the server hostname
shell:
cmd: "tr -d '\n' < /etc/dkimkeys/{{ server_hostname }}/default.txt | sed -E 's/.+IN\\s+TXT\\s+//' | tr -d '()\"[:blank:]' | sed -E s/\\;--.+//"
register: extract_hostname_dkim_result
changed_when: false

- name: Create file to hold dkim txt record for the server hostname
template:
src: templates/txt_record_template.j2
dest: "~/dns_txt_records/{{ server_hostname }}_dkim.txt"
vars:
key: "default._domainkey.{{ server_hostname }}"
value: "{{ extract_hostname_dkim_result.stdout }}"

- name: Create file to hold spf txt record for the server hostname
template:
src: templates/txt_record_template.j2
dest: "~/dns_txt_records/{{ server_hostname }}_spf.txt"
vars:
key: "{{ server_hostname }}"
value: "v=spf1 a -all"

- name: Create file to hold A record for the server hostname
template:
src: templates/txt_record_template.j2
dest: "~/dns_txt_records/{{ server_hostname }}_a.txt"
vars:
key: "{{ server_hostname }}"
value: "{{ ipv4_address }}"

- name: Create file to hold AAAA record for the server hostname
template:
src: templates/txt_record_template.j2
dest: "~/dns_txt_records/{{ server_hostname }}_aaaa.txt"
vars:
key: "{{ server_hostname }}"
value: "{{ ipv6_address }}"
when: (ipv6_address is defined) and (ipv6_address | length > 0)
8 changes: 8 additions & 0 deletions generate_txt_records.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@
vars:
key: "_dmarc.{{ domain }}"
value: "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@{{ domain }}; ruf=mailto:dmarc-reports@{{ domain }}; fo=1"

- name: Create file to hold mx record
template:
src: templates/txt_record_template.j2
dest: "~/dns_txt_records/{{ domain }}_mx.txt"
vars:
key: "{{ domain }}"
value: "10 {{ server_hostname }}."
Binary file added img/replatform_logo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions mail_server_setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@
- opendkim
- opendkim-tools
- spamass-milter
- spamassassin

- name: Determine the SpamAssassin daemon systemd unit name for this OS
set_fact:
spamassassin_service_name: "{{ 'spamd' if ansible_distribution_major_version | int >= 12 else 'spamassassin' }}"

- name: Ensure that mail system servers are running and start at boot
service: "name={{ item }} state=started enabled=yes"
loop:
- postfix
- dovecot
- spamassassin
- "{{ spamassassin_service_name }}"
- spamass-milter

- name: Combine all mail domains
Expand Down Expand Up @@ -90,8 +95,11 @@
path: ~/dns_txt_records
state: directory

- name: Generate TXT records for DKIM, DMARC, SPF for hosted domains
- name: Generate TXT records for DKIM, DMARC, SPF, MX for hosted domains
include_tasks: generate_txt_records.yml
loop: "{{ mail_domains.keys() | list }}"
loop_control:
loop_var: domain

- name: Generate SPF, DKIM, A/AAAA records for the server hostname
include_tasks: generate_hostname_records.yml
5 changes: 3 additions & 2 deletions site.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
- hosts: myplatform
remote_user: root
force_handlers: true

vars_files:
- vars.yml
Expand Down Expand Up @@ -50,7 +51,7 @@
user:
name: admin
create_home: yes
password: "{{ admin_mail_password | password_hash('blowfish', ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' | shuffle(seed=server_hostname) | join)[:21] + ('Oeu' | shuffle(seed=server_hostname) | join)[1], rounds=11) }}"
password: "{{ admin_mail_password | password_hash('blowfish', rounds=11) }}"
groups: adm
append: true

Expand Down Expand Up @@ -96,7 +97,7 @@
service: name=spamass-milter state=restarted

- name: restart spamassassin daemon
service: name=spamassassin state=restarted
service: "name={{ spamassassin_service_name }} state=restarted"

- name: restart opendkim
service: name=opendkim state=restarted
Expand Down
2 changes: 1 addition & 1 deletion templates/etc_dovecot_passwd.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% for domain, info in mail_domains.items() %}
{% for username, passwd in info.items() %}
{{ username }}@{{ domain }}:{BLF-CRYPT}{{ passwd | password_hash('blowfish', ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' | shuffle(seed=server_hostname) | join)[:21] + ('Oeu' | shuffle(seed=server_hostname) | join)[1], rounds=11) }}::::::
{{ username }}@{{ domain }}:{BLF-CRYPT}{{ passwd | password_hash('blowfish', rounds=11) }}::::::
{% endfor %}
{% endfor %}
12 changes: 1 addition & 11 deletions templates/nginx_site.j2
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,4 @@ server {

# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /etc/letsencrypt/live/{{ server_hostname }}/chain.pem;

# Using Google's DNS server as the resolver
resolver 8.8.8.8;
}
}
5 changes: 3 additions & 2 deletions templates/start_services.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ echo "starting service nginx"
systemctl start nginx

echo "restarting mail services to reload certificates"
systemctl reload postfix
systemctl reload dovecot
systemctl restart postfix
systemctl restart dovecot
systemctl restart {{ 'spamd' if ansible_distribution_major_version | int >= 12 else 'spamassassin' }}