Add config option for ipv6 usage (#312)

* add allow_ipv6 config option

* add ipv6 config changes to cmdeploy

* fix name of config option for ipv6 in config.py

* move configure ipv6 before service start

* Use templates for disabling ipv6

* lint

* fix parameters in _configure_dovecot

* dont pass domain to _configure_nginx

* make disable_ipv6 boolean

Co-authored-by: missytake <missytake@systemli.org>

* implement namis suggestions reg boolean for ipv6

* Update chatmaild/src/chatmaild/config.py

Co-authored-by: missytake <missytake@systemli.org>

* ruff

* ruff again :)

* fix merge conflict

* CI: add CI machine with IPv6 disabled

* CI: fix sed statement

* CI: fix ubuntu reset

* CI: separate cert storage for staging2 and staging-ipv4

* add DNS records to proper zone

* CI: ignore if folders are missing

* CI: renames are not needed like this

* CI: fix default DNS zone for ipv4

* CI: use debian 12 instead of ubuntu, tired of trying to guess the correct image

* remove duplicared listen on 8443

* use jinja templates for disable_ipv6

* remove unused variable

* add missing % sign in jinja tempalte

* more fun with jinja syntax

* CI: proper rsync paths for acme & DKIM caching

* Changelog: add disable_ipv6 config option

---------

Co-authored-by: missytake <missytake@systemli.org>
Co-authored-by: holger krekel <holger@merlinux.eu>
This commit is contained in:
Christian Hagenest
2024-07-28 20:06:24 +02:00
committed by GitHub
parent ac1f2dadad
commit 1331e7e77a
9 changed files with 149 additions and 5 deletions

View File

@@ -0,0 +1,20 @@
;; Zone file for staging-ipv4.testrun.org
$ORIGIN staging-ipv4.testrun.org.
$TTL 300
@ IN SOA ns.testrun.org. root.nine.testrun.org (
2023010101 ; Serial
7200 ; Refresh
3600 ; Retry
1209600 ; Expire
3600 ; Negative response caching TTL
)
;; Nameservers.
@ IN NS ns.testrun.org.
;; DNS records.
@ IN A 37.27.95.249
mta-sts.staging-ipv4.testrun.org. CNAME staging-ipv4.testrun.org.
www.staging-ipv4.testrun.org. CNAME staging-ipv4.testrun.org.

View File

@@ -0,0 +1,98 @@
name: deploy on staging-ipv4.testrun.org, and run tests
on:
push:
branches:
- main
pull_request:
paths-ignore:
- 'scripts/**'
- '**/README.md'
- 'CHANGELOG.md'
- 'LICENSE'
jobs:
deploy:
name: deploy on staging-ipv4.testrun.org, and run tests
runs-on: ubuntu-latest
timeout-minutes: 30
concurrency:
group: ci-ipv4-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !contains(github.ref, '$GITHUB_REF') }}
steps:
- uses: jsok/serialize-workflow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
- name: prepare SSH
run: |
mkdir ~/.ssh
echo "${{ secrets.STAGING_SSH_KEY }}" >> ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan staging-ipv4.testrun.org > ~/.ssh/known_hosts
# save previous acme & dkim state
rsync -avz root@staging-ipv4.testrun.org:/var/lib/acme acme-ipv4 || true
rsync -avz root@staging-ipv4.testrun.org:/etc/dkimkeys dkimkeys-ipv4 || true
# store previous acme & dkim state on ns.testrun.org, if it contains useful certs
if [ -f dkimkeys-ipv4/dkimkeys/opendkim.private ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" dkimkeys-ipv4 root@ns.testrun.org:/tmp/ || true; fi
if [ "$(ls -A acme-ipv4/acme/certs)" ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" acme-ipv4 root@ns.testrun.org:/tmp/ || true; fi
# make sure CAA record isn't set
ssh -o StrictHostKeyChecking=accept-new root@ns.testrun.org sed -i '/CAA/d' /etc/nsd/staging-ipv4.testrun.org.zone
ssh root@ns.testrun.org systemctl reload nsd
- name: rebuild staging-ipv4.testrun.org to have a clean VPS
run: |
curl -X POST \
-H "Authorization: Bearer ${{ secrets.HETZNER_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"image":"debian-12"}' \
"https://api.hetzner.cloud/v1/servers/${{ secrets.STAGING_SERVER_ID }}/actions/rebuild"
- run: scripts/initenv.sh
- name: append venv/bin to PATH
run: echo venv/bin >>$GITHUB_PATH
- name: upload TLS cert after rebuilding
run: |
echo " --- wait until staging-ipv4.testrun.org VPS is rebuilt --- "
rm ~/.ssh/known_hosts
while ! ssh -o ConnectTimeout=180 -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org id -u ; do sleep 1 ; done
ssh -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org id -u
# download acme & dkim state from ns.testrun.org
rsync -e "ssh -o StrictHostKeyChecking=accept-new" -avz root@ns.testrun.org:/tmp/acme-ipv4 acme-restore || true
rsync -avz root@ns.testrun.org:/tmp/dkimkeys-ipv4 dkimkeys-restore || true
# restore acme & dkim state to staging2.testrun.org
rsync -avz acme-restore/acme-ipv4/acme root@staging-ipv4.testrun.org:/var/lib/acme || true
rsync -avz dkimkeys-restore/dkimkeys-ipv4/dkimkeys root@staging-ipv4.testrun.org:/etc/dkimkeys || true
ssh -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org chown root:root -R /var/lib/acme || true
- name: run formatting checks
run: cmdeploy fmt -v
- name: run deploy-chatmail offline tests
run: pytest --pyargs cmdeploy
- run: |
cmdeploy init staging-ipv4.testrun.org
sed -i 's#disable_ipv6 = False#disable_ipv6 = True#' chatmail.ini
- run: cmdeploy run
- name: set DNS entries
run: |
ssh -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org chown opendkim:opendkim -R /etc/dkimkeys
cmdeploy dns --zonefile staging-generated.zone
cat staging-generated.zone >> .github/workflows/staging-ipv4.testrun.org-default.zone
cat .github/workflows/staging-ipv4.testrun.org-default.zone
scp .github/workflows/staging-ipv4.testrun.org-default.zone root@ns.testrun.org:/etc/nsd/staging-ipv4.testrun.org.zone
ssh root@ns.testrun.org nsd-checkzone staging-ipv4.testrun.org /etc/nsd/staging-ipv4.testrun.org.zone
ssh root@ns.testrun.org systemctl reload nsd
- name: cmdeploy test
run: CHATMAIL_DOMAIN2=nine.testrun.org cmdeploy test --slow
- name: cmdeploy dns (try 3 times)
run: cmdeploy dns || cmdeploy dns || cmdeploy dns

View File

@@ -2,6 +2,10 @@
## untagged ## untagged
- Add `disable_ipv6` config option to chatmail.ini.
Required if the server doesn't have IPv6 connectivity.
([#312](https://github.com/deltachat/chatmail/pull/312))
- allow current K9/Thunderbird-mail releases to send encrypted messages - allow current K9/Thunderbird-mail releases to send encrypted messages
outside by accepting their localized "encrypted subject" strings. outside by accepting their localized "encrypted subject" strings.
([#370](https://github.com/deltachat/chatmail/pull/370)) ([#370](https://github.com/deltachat/chatmail/pull/370))

View File

@@ -30,6 +30,9 @@ class Config:
self.passthrough_recipients = params["passthrough_recipients"].split() self.passthrough_recipients = params["passthrough_recipients"].split()
self.filtermail_smtp_port = int(params["filtermail_smtp_port"]) self.filtermail_smtp_port = int(params["filtermail_smtp_port"])
self.postfix_reinject_port = int(params["postfix_reinject_port"]) self.postfix_reinject_port = int(params["postfix_reinject_port"])
self.disable_ipv6 = (
True if params.get("disable_ipv6").lower() == "true" else False
)
self.iroh_relay = params.get("iroh_relay") self.iroh_relay = params.get("iroh_relay")
self.privacy_postal = params.get("privacy_postal") self.privacy_postal = params.get("privacy_postal")
self.privacy_mail = params.get("privacy_mail") self.privacy_mail = params.get("privacy_mail")

View File

@@ -51,6 +51,9 @@ filtermail_smtp_port = 10080
# postfix accepts on the localhost reinject SMTP port # postfix accepts on the localhost reinject SMTP port
postfix_reinject_port = 10025 postfix_reinject_port = 10025
# if set to "True" IPv6 is disabled
disable_ipv6 = False
# #
# Privacy Policy # Privacy Policy
# #

View File

@@ -268,6 +268,7 @@ def _configure_postfix(config: Config, debug: bool = False) -> bool:
group="root", group="root",
mode="644", mode="644",
config=config, config=config,
disable_ipv6=config.disable_ipv6,
) )
need_restart |= main_config.changed need_restart |= main_config.changed
@@ -318,6 +319,7 @@ def _configure_dovecot(config: Config, debug: bool = False) -> bool:
mode="644", mode="644",
config=config, config=config,
debug=debug, debug=debug,
disable_ipv6=config.disable_ipv6,
) )
need_restart |= main_config.changed need_restart |= main_config.changed
auth_config = files.put( auth_config = files.put(
@@ -362,7 +364,7 @@ def _configure_dovecot(config: Config, debug: bool = False) -> bool:
return need_restart return need_restart
def _configure_nginx(domain: str, debug: bool = False) -> bool: def _configure_nginx(config: Config, debug: bool = False) -> bool:
"""Configures nginx HTTP server.""" """Configures nginx HTTP server."""
need_restart = False need_restart = False
@@ -372,7 +374,8 @@ def _configure_nginx(domain: str, debug: bool = False) -> bool:
user="root", user="root",
group="root", group="root",
mode="644", mode="644",
config={"domain_name": domain}, config={"domain_name": config.mail_domain},
disable_ipv6=config.disable_ipv6,
) )
need_restart |= main_config.changed need_restart |= main_config.changed
@@ -382,7 +385,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> bool:
user="root", user="root",
group="root", group="root",
mode="644", mode="644",
config={"domain_name": domain}, config={"domain_name": config.mail_domain},
) )
need_restart |= autoconfig.changed need_restart |= autoconfig.changed
@@ -392,7 +395,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> bool:
user="root", user="root",
group="root", group="root",
mode="644", mode="644",
config={"domain_name": domain}, config={"domain_name": config.mail_domain},
) )
need_restart |= mta_sts_config.changed need_restart |= mta_sts_config.changed
@@ -556,7 +559,7 @@ def deploy_chatmail(config_path: Path) -> None:
dovecot_need_restart = _configure_dovecot(config, debug=debug) dovecot_need_restart = _configure_dovecot(config, debug=debug)
postfix_need_restart = _configure_postfix(config, debug=debug) postfix_need_restart = _configure_postfix(config, debug=debug)
mta_sts_need_restart = _install_mta_sts_daemon() mta_sts_need_restart = _install_mta_sts_daemon()
nginx_need_restart = _configure_nginx(mail_domain) nginx_need_restart = _configure_nginx(config)
_remove_rspamd() _remove_rspamd()
opendkim_need_restart = _configure_opendkim(mail_domain, "opendkim") opendkim_need_restart = _configure_opendkim(mail_domain, "opendkim")

View File

@@ -1,5 +1,9 @@
## Dovecot configuration file ## Dovecot configuration file
{% if disable_ipv6 %}
listen = *
{% endif %}
protocols = imap lmtp protocols = imap lmtp
auth_mechanisms = plain auth_mechanisms = plain

View File

@@ -43,8 +43,11 @@ http {
gzip on; gzip on;
server { server {
listen 8443 ssl default_server; listen 8443 ssl default_server;
{% if not disable_ipv6 %}
listen [::]:8443 ssl default_server; listen [::]:8443 ssl default_server;
{% endif %}
root /var/www/html; root /var/www/html;
@@ -96,7 +99,9 @@ http {
# Redirect www. to non-www # Redirect www. to non-www
server { server {
listen 8443 ssl; listen 8443 ssl;
{% if not disable_ipv6 %}
listen [::]:8443 ssl; listen [::]:8443 ssl;
{% endif %}
server_name www.{{ config.domain_name }}; server_name www.{{ config.domain_name }};
return 301 $scheme://{{ config.domain_name }}$request_uri; return 301 $scheme://{{ config.domain_name }}$request_uri;
access_log syslog:server=unix:/dev/log,facility=local7; access_log syslog:server=unix:/dev/log,facility=local7;

View File

@@ -65,7 +65,11 @@ mailbox_size_limit = 0
message_size_limit = {{config.max_message_size}} message_size_limit = {{config.max_message_size}}
recipient_delimiter = + recipient_delimiter = +
inet_interfaces = all inet_interfaces = all
{% if disable_ipv6 %}
inet_protocols = ipv4
{% else %}
inet_protocols = all inet_protocols = all
{% endif %}
virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = {{ config.mail_domain }} virtual_mailbox_domains = {{ config.mail_domain }}