<inputclass="md-option"data-md-color-media="(prefers-color-scheme: light)"data-md-color-scheme="default"data-md-color-primary="indigo"data-md-color-accent="indigo"aria-label="Switch to dark mode"type="radio"name="__palette"id="__palette_0">
<labelclass="md-header__button md-icon"title="Switch to dark mode"for="__palette_1"hidden>
<inputclass="md-option"data-md-color-media="(prefers-color-scheme: dark)"data-md-color-scheme="slate"data-md-color-primary="indigo"data-md-color-accent="blue"aria-label="Switch to light mode"type="radio"name="__palette"id="__palette_1">
<labelclass="md-header__button md-icon"title="Switch to light mode"for="__palette_0"hidden>
<ahref="https://github.com/docker-mailserver/docker-mailserver/edit/master/docs/content/config/security/ssl.md"title="Edit this page"class="md-content__button md-icon">
<ahref="https://github.com/docker-mailserver/docker-mailserver/raw/master/docs/content/config/security/ssl.md"title="View source of this page"class="md-content__button md-icon">
<pclass="admonition-title">Exposure of DNS labels through Certificate Transparency</p>
<p>All public Certificate Authorities (CAs) are required to log certificates they issue publicly via <ahref="https://certificate.transparency.dev/">Certificate Transparency</a>. This helps to better establish trust.</p>
<p>When using a public CA for certificates used in private networks, be aware that the associated DNS labels in the certificate are logged publicly and <ahref="https://crt.sh/">easily searchable</a>. These logs are <em>append only</em>, you <strong>cannot</strong> redact this information.</p>
<p>You could use a <ahref="https://en.wikipedia.org/wiki/Wildcard_certificate#Examples">wildcard certificate</a>. This avoids accidentally leaking information to the internet, but keep in mind the <ahref="https://gist.github.com/joepie91/7e5cad8c0726fd6a5e90360a754fc568">potential security risks</a> of wildcard certs.</p>
<p>An <ahref="https://en.wikipedia.org/wiki/Fully_qualified_domain_name">FQDN</a> (<em>Fully Qualified Domain Name</em>) such as <code>mail.example.com</code> is required for DMS to function correctly, especially for looking up the correct SSL certificate to use.</p>
<ul>
<li><code>mail.example.com</code> will still use <code>user@example.com</code> as the mail address. You do not need a bare domain for that.</li>
<li>We usually discourage assigning a bare domain (<em>When your DNS MX record does not point to a subdomain</em>) to represent DMS. However, an FQDN of <ahref="../../../faq/#can-i-use-a-nakedbare-domain-ie-no-hostname">just <code>example.com</code> is also supported</a>.</li>
<li>Internally, <code>hostname -f</code> will be used to retrieve the FQDN as configured in the below examples.</li>
<li>Wildcard certificates (eg: <code>*.example.com</code>) are supported for <code>SSL_TYPE=letsencrypt</code>. Your configured FQDN below may be <code>mail.example.com</code>, and your wildcard certificate provisioned to <code>/etc/letsencrypt/live/example.com</code> which will be checked as a fallback FQDN by DMS.</li>
</ul>
<divclass="admonition example">
<pclass="admonition-title">Setting the hostname correctly</p>
<p>Change <code>mail.example.com</code> below to your own FQDN.</p>
<p>To enable <em>Let's Encrypt</em> for DMS, you have to:</p>
<ol>
<li>Get your certificate using the <em>Let's Encrypt</em> client <ahref="https://github.com/certbot/certbot">Certbot</a>.</li>
<li>
<p>For your DMS container:</p>
<ul>
<li>Add the environment variable <code>SSL_TYPE=letsencrypt</code>.</li>
<li>Mount <ahref="https://certbot.eff.org/docs/using.html#where-are-my-certificates">your local <code>letsencrypt</code> folder</a> as a volume to <code>/etc/letsencrypt</code>.</li>
</ul>
</li>
</ol>
<p>You don't have to do anything else. Enjoy!</p>
<divclass="admonition note">
<pclass="admonition-title">Note</p>
<p><code>/etc/letsencrypt/live</code> stores provisioned certificates in individual folders named by their FQDN.</p>
<p>Make sure that the entire folder is mounted to DMS as there are typically symlinks from <code>/etc/letsencrypt/live/mail.example.com</code> to <code>/etc/letsencrypt/archive</code>.</p>
</div>
<divclass="admonition example">
<pclass="admonition-title">Example</p>
<p>Add these additions to the <code>mailserver</code> service in your <ahref="https://github.com/docker-mailserver/docker-mailserver/blob/master/compose.yaml"><code>compose.yaml</code></a>:</p>
<h4id="example-using-docker-for-lets-encrypt"><aclass="toclink"href="#example-using-docker-for-lets-encrypt">Example using Docker for <em>Let's Encrypt</em></a></h4>
<p>Certbot provisions certificates to <code>/etc/letsencrypt</code>. Add a volume to store these, so that they can later be accessed by DMS container. You may also want to persist Certbot <ahref="https://certbot.eff.org/docs/using.html#log-rotation">logs</a>, just in case you need to troubleshoot.</p>
<ol>
<li>
<p>Getting a certificate is this simple! (<em>Referencing: <ahref="https://certbot.eff.org/docs/install.html#running-with-docker">Certbot docker instructions</a> and <ahref="https://certbot.eff.org/docs/using.html#standalone"><code>certonly --standalone</code> mode</a></em>):</p>
<divclass="highlight"><pre><span></span><code><spanclass="c1"># Requires access to port 80 from the internet, adjust your firewall if needed.</span>
<p>Add a volume for DMS that maps the <em>local <code>certbot/certs/</code> folder</em> to the container path <code>/etc/letsencrypt/</code>.</p>
<divclass="admonition example">
<pclass="admonition-title">Example</p>
<p>Add these additions to the <code>mailserver</code> service in your <ahref="https://github.com/docker-mailserver/docker-mailserver/blob/master/compose.yaml"><code>compose.yaml</code></a>:</p>
<p>When running the above <code>certonly --standalone</code> snippet again, the existing certificate is renewed if it would expire within 30 days.</p>
<p>Alternatively, Certbot can look at all the certificates it manages, and only renew those nearing their expiry via the <ahref="https://certbot.eff.org/docs/using.html#renewing-certificates"><code>renew</code> command</a>:</p>
<divclass="highlight"><pre><span></span><code><spanclass="c1"># This will need access to port 443 from the internet, adjust your firewall if needed.</span>
<p>This process can also be <ahref="https://certbot.eff.org/docs/using.html#automated-renewals">automated via <em>cron</em> or <em>systemd timers</em></a>.</p>
</div>
<divclass="admonition note">
<pclass="admonition-title">Using a different ACME CA</p>
<p>Certbot does support <ahref="https://certbot.eff.org/docs/using.htmlchanging-the-acme-server">alternative certificate providers via the <code>--server</code></a> option. In most cases you'll want to use the default <em>Let's Encrypt</em>.</p>
</div>
<h4id="example-using-certbot-dns-cloudflare-with-docker"><aclass="toclink"href="#example-using-certbot-dns-cloudflare-with-docker">Example using <code>certbot-dns-cloudflare</code> with Docker</a></h4>
<p>If you are unable get a certificate via the <code>HTTP-01</code> (port 80) or <code>TLS-ALPN-01</code> (port 443) <ahref="https://letsencrypt.org/docs/challenge-types/">challenge types</a>, the <code>DNS-01</code> challenge can be useful (<em>this challenge can additionally issue wildcard certificates</em>). This guide shows how to use the <code>DNS-01</code> challenge with Cloudflare as your DNS provider.</p>
<p>Obtain a Cloudflare API token:</p>
<ol>
<li>Login into your Cloudflare dashboard.</li>
<li>Navigate to the <ahref="https://dash.cloudflare.com/profile/api-tokens">API Tokens page</a>.</li>
<li>
<p>Click "Create Token", and choose the <code>Edit zone DNS</code> template (<em>Certbot <ahref="https://certbot-dns-cloudflare.readthedocs.io/en/stable/#credentials">requires the <code>ZONE:DNS:Edit</code> permission</a></em>).</p>
<divclass="admonition warning">
<pclass="admonition-title">Only include the necessary Zone resource configuration</p>
<p>Be sure to configure "Zone Resources" section on this page to <code>Include -> Specific zone -><your zone here></code>.</p>
<p>This restricts the API token to only this zone (domain) which is an important security measure.</p>
</div>
</li>
<li>
<p>Store the <em>API token</em> you received in a file <code>cloudflare.ini</code> with content:</p>
<divclass="highlight"><pre><span></span><code><spanclass="go">Saving debug log to /var/log/letsencrypt/letsencrypt. log | Requesting a certificate for mail.example.com</span>
<spanclass="go">Waiting 10 seconds for DNS changes to propagate</span>
<spanclass="go">Successfully received certificate.</span>
<spanclass="go">Certificate is saved at: /etc/letsencrypt/live/mail.example.com/fullchain.pem</span>
<spanclass="go">Key is saved at: /etc/letsencrypt/live/mail.example.com/privkey.pem</span>
<spanclass="go">This certificate expires on YYYY-MM-DD.</span>
<spanclass="go">These files will be updated when the certificate renews.</span>
<spanclass="go">NEXT STEPS:</span>
<spanclass="go">- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal instructions.</span>
</code></pre></div>
</li>
</ol>
<p>After completing the steps above, your certificate should be ready to use.</p>
<detailsclass="tip">
<summary>Renewing a certificate (Optional)</summary>
<p>We've only demonstrated how to provision a certificate, but it will expire in 90 days and need to be renewed before then.</p>
<p>In the following example, add a new service (<code>certbot-cloudflare-renew</code>) into <code>compose.yaml</code> that will handle certificate renewals:</p>
<h4id="example-using-nginx-proxy-and-acme-companion-with-docker"><aclass="toclink"href="#example-using-nginx-proxy-and-acme-companion-with-docker">Example using <code>nginx-proxy</code> and <code>acme-companion</code> with Docker</a></h4>
<p>If you are running a web server already, port 80 will be in use which Certbot requires. You could use the <ahref="https://certbot.eff.org/docs/using.html#webroot">Certbot <code>--webroot</code></a> feature, but it is more common to leverage a <em>reverse proxy</em> that manages the provisioning and renewal of certificates for your services automatically.</p>
<p>In the following example, we show how DMS can be run alongside the docker containers <ahref="https://github.com/nginx-proxy/nginx-proxy"><code>nginx-proxy</code></a> and <ahref="https://github.com/nginx-proxy/acme-companion"><code>acme-companion</code></a> (<em>Referencing: <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs"><code>acme-companion</code> documentation</a></em>):</p>
<ol>
<li>
<p>Start the <em>reverse proxy</em> (<code>nginx-proxy</code>):</p>
<p>Then start the <em>certificate provisioner</em> (<code>acme-companion</code>), which will provide certificates to <code>nginx-proxy</code>:</p>
<divclass="highlight"><pre><span></span><code><spanclass="c1"># Inherit `nginx-proxy` volumes via `--volumes-from`, but make `certs/` writeable:</span>
<p>Start the rest of your web server containers as usual.</p>
</li>
<li>
<p>Start a <em>dummy container</em> to provision certificates for your FQDN (eg: <code>mail.example.com</code>). <code>acme-companion</code> will detect the container and generate a <em>Let's Encrypt</em> certificate for your domain, which can be used by DMS:</p>
<p>You may want to add <code>--env LETSENCRYPT_TEST=true</code> to the above while testing, to avoid the <em>Let's Encrypt</em> certificate generation rate limits.</p>
</li>
<li>
<p>Make sure your mount path to the <code>letsencrypt</code> certificates directory is correct. Edit your <code>compose.yaml</code> for the <code>mailserver</code> service to have volumes added like below:</p>
<p>Then from the <code>compose.yaml</code> project directory, run: <code>docker compose up -d mailserver</code>.</p>
</li>
</ol>
<h4id="example-using-nginx-proxy-and-acme-companion-with-docker-compose"><aclass="toclink"href="#example-using-nginx-proxy-and-acme-companion-with-docker-compose">Example using <code>nginx-proxy</code> and <code>acme-companion</code> with <code>docker-compose</code></a></h4>
<p>The following example is the <ahref="https://github.com/nginx-proxy/acme-companion#basic-usage-with-the-nginx-proxy-container">basic setup</a> you need for using <code>nginx-proxy</code> and <code>acme-companion</code> with DMS (<em>Referencing: <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs"><code>acme-companion</code> documentation</a></em>):</p>
<p>You should have an existing <code>compose.yaml</code> with a <code>mailserver</code> service. Below are the modifications to add for integrating with <code>nginx-proxy</code> and <code>acme-companion</code> services:</p>
<spanclass="w"></span><spanclass="c1"># Port 80: Required for HTTP-01 challenges to `acme-companion`.</span>
<spanclass="w"></span><spanclass="c1"># Port 443: Only required for containers that need access over HTTPS. TLS-ALPN-01 challenge not supported.</span>
<pclass="admonition-title">Optional ENV vars worth knowing about</p>
<p><ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Let's-Encrypt-and-ACME.md">Per container ENV</a> that <code>acme-companion</code> will detect to override default provisioning settings:</p>
<ul>
<li><code>LETSENCRYPT_TEST=true</code>: <em>Recommended during initial setup</em>. Otherwise the default production endpoint has a <ahref="https://letsencrypt.org/docs/rate-limits/">rate limit of 5 duplicate certificates per week</a>. Overrides <code>ACME_CA_URI</code> to use the <em>Let's Encrypt</em> staging endpoint.</li>
<li><code>LETSENCRYPT_EMAIL</code>: For when you don't use <code>DEFAULT_EMAIL</code> on <code>acme-companion</code>, or want to assign a different email contact for this container.</li>
<li><code>LETSENCRYPT_KEYSIZE</code>: Allows you to configure the type (RSA or ECDSA) and size of the private key for your certificate. Default is RSA 4096.</li>
<li><code>LETSENCRYPT_RESTART_CONTAINER=true</code>: When the certificate is renewed, the entire container will be restarted to ensure the new certificate is used.</li>
</ul>
<p><ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Container-configuration.md"><code>acme-companion</code> ENV for default settings</a> that apply to all containers using <code>LETSENCRYPT_HOST</code>:</p>
<ul>
<li><code>DEFAULT_EMAIL</code>: An email address that the CA (<em>eg: Let's Encrypt</em>) can contact you about expiring certificates, failed renewals, or for account recovery. You may want to use an email address not handled by your mail server to ensure deliverability in the event your mail server breaks.</li>
<li><code>CERTS_UPDATE_INTERVAL</code>: If you need to adjust the frequency to check for renewals. 3600 seconds (1 hour) by default.</li>
<li><code>DEBUG=1</code>: Should be helpful when <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Invalid-authorizations.md">troubleshooting provisioning issues</a> from <code>acme-companion</code> logs.</li>
<li><code>ACME_CA_URI</code>: Useful in combination with <code>CA_BUNDLE</code> to use a private CA. To change the default <em>Let's Encrypt</em> endpoint to the staging endpoint, use <code>https://acme-staging-v02.api.letsencrypt.org/directory</code>.</li>
<li><code>CA_BUNDLE</code>: If you want to use a private CA instead of <em>Let's Encrypt</em>.</li>
</ul>
</div>
<divclass="admonition tip">
<pclass="admonition-title">Alternative to required ENV on <code>mailserver</code> service</p>
<p>While you will still need both <code>nginx-proxy</code> and <code>acme-companion</code> containers, you can manage certificates without adding ENV vars to containers. Instead the ENV is moved into a file and uses the <code>acme-companion</code> feature <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Standalone-certificates.md">Standalone certificates</a>.</p>
<p>This requires adding another shared volume between <code>nginx-proxy</code> and <code>acme-companion</code>:</p>
<p>Unlike with the equivalent ENV for containers, <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Standalone-certificates.md#picking-up-changes-to-letsencrypt_user_data">changes to this file will <strong>not</strong> be detected automatically</a>. You would need to wait until the next renewal check by <code>acme-companion</code> (<em>every hour by default</em>), restart <code>acme-companion</code>, or <ahref="https://github.com/nginx-proxy/acme-companion/blob/main/docs/Container-utilities.md">manually invoke the <em>service loop</em></a>:</p>
<h4id="example-using-lets-encrypt-certificates-with-a-synology-nas"><aclass="toclink"href="#example-using-lets-encrypt-certificates-with-a-synology-nas">Example using <em>Let's Encrypt</em> Certificates with a <em>Synology NAS</em></a></h4>
<p>Version 6.2 and later of the Synology NAS DSM OS now come with an interface to generate and renew letencrypt certificates. Navigation into your DSM control panel and go to Security, then click on the tab Certificate to generate and manage letsencrypt certificates.</p>
<p>Amongst other things, you can use these to secure your mail server. DSM locates the generated certificates in a folder below <code>/usr/syno/etc/certificate/_archive/</code>.</p>
<p>Navigate to that folder and note the 6 character random folder name of the certificate you'd like to use. Then, add the following to your <code>compose.yaml</code> declaration file:</p>
<p>For Caddy v2 you can specify the <code>key_type</code> in your server's global settings, which would end up looking something like this if you're using a <code>Caddyfile</code>:</p>
<divclass="highlight"><pre><span></span><code>{
debug
admin localhost:2019
http_port 80
https_port 443
default_sni example.com
key_type rsa4096
}
</code></pre></div>
<p>If you are instead using a json config for Caddy v2, you can set it in your site's TLS automation policies:</p>
<p><ahref="https://github.com/containous/traefik">Traefik</a> is an open-source application proxy using the <ahref="https://datatracker.ietf.org/doc/html/rfc8555">ACME protocol</a>. <ahref="https://github.com/containous/traefik">Traefik</a> can request certificates for domains and subdomains, and it will take care of renewals, challenge negotiations, etc. We strongly recommend to use <ahref="https://github.com/containous/traefik">Traefik</a>'s major version 2.</p>
<p><ahref="https://github.com/containous/traefik">Traefik</a>'s storage format is natively supported if the <code>acme.json</code> store is mounted into the container at <code>/etc/letsencrypt/acme.json</code>. The file is also monitored for changes and will trigger a reload of the mail services (Postfix and Dovecot).</p>
<p>Wildcard certificates are supported. If your FQDN is <code>mail.example.com</code> and your wildcard certificate is <code>*.example.com</code>, add the ENV: <codeclass="highlight"><spanclass="nv">SSL_DOMAIN</span><spanclass="o">=</span>example.com</code>.</p>
<p>DMS will select it's certificate from <code>acme.json</code> checking these ENV for a matching FQDN (<em>in order of priority</em>):</p>
<p>This setup only comes with one caveat: The domain has to be configured on another service for <ahref="https://github.com/containous/traefik">Traefik</a> to actually request it from <em>Let's Encrypt</em>, i.e. <ahref="https://github.com/containous/traefik">Traefik</a> will not issue a certificate without a service / router demanding it.</p>
<detailsclass="example"open="open">
<summary>Example Code</summary>
<p>Here is an example setup for <ahref="https://docs.docker.com/compose/"><code>docker-compose</code></a>:</p>
<p>Use self-signed certificates only for testing purposes!</p>
</div>
<p>This feature requires you to provide the following files into your <ahref="../../advanced/optional-config/"><code>docker-data/dms/config/ssl/</code> directory</a> (<em>internal location: <code>/tmp/docker-mailserver/ssl/</code></em>):</p>
<ul>
<li><code><FQDN>-key.pem</code></li>
<li><code><FQDN>-cert.pem</code></li>
<li><code>demoCA/cacert.pem</code></li>
</ul>
<p>Where <code><FQDN></code> is the FQDN you've configured for your DMS container.</p>
<p>Add <code>SSL_TYPE=self-signed</code> to your DMS environment variables. Postfix and Dovecot will be configured to use the provided certificate (<em><code>.pem</code> files above</em>) during container startup.</p>
<h4id="generating-a-self-signed-certificate"><aclass="toclink"href="#generating-a-self-signed-certificate">Generating a self-signed certificate</a></h4>
<p>One way to generate self-signed certificates is with <ahref="https://smallstep.com/docs/step-cli">Smallstep's <code>step</code> CLI</a>. This is exactly what <ahref="https://github.com/docker-mailserver/docker-mailserver/blob/3b8059f2daca80d967635e04d8d81e9abb755a4d/test/test-files/ssl/example.test/README.md">DMS does for creating test certificates</a>.</p>
<p>For example with the FQDN <code>mail.example.test</code>, you can generate the required files by running:</p>
<p>If you'd rather not install the CLI tool locally to run the <code>step</code> commands above; you can save the script above to a file such as <code>generate-certs.sh</code> (<em>and make it executable <code>chmod +x generate-certs.sh</code></em>) in a directory that you want the certs to be placed (eg: <code>docker-data/dms/custom-certs/</code>), then use docker to run that script in a container:</p>
<divclass="highlight"><pre><span></span><code><spanclass="c1"># '--user' is to keep ownership of the files written to</span>
<spanclass="c1"># the local volume to use your systems User and Group ID values.</span>
<p>This will mount the path where your certificate files reside locally into the <em>read-only</em> container folder: <code>/tmp/dms/custom-certs</code>.</p>
<p>The local and internal paths may be whatever you prefer, so long as both <code>SSL_CERT_PATH</code> and <code>SSL_KEY_PATH</code> point to the correct internal file paths. The certificate files may also be named to your preference, but should be PEM encoded.</p>
<p><code>SSL_ALT_CERT_PATH</code> and <code>SSL_ALT_KEY_PATH</code> are additional ENV vars to support a 2nd certificate as a fallback. Commonly known as hybrid or dual certificate support. This is useful for using a modern ECDSA as your primary certificate, and RSA as your fallback for older connections. They work in the same manner as the non-<code>ALT</code> versions.</p>
<divclass="admonition info">
<pclass="admonition-title">Info</p>
<p>You may have to restart DMS once the certificates change.</p>
</div>
<h2id="testing-a-certificate-is-valid"><aclass="toclink"href="#testing-a-certificate-is-valid">Testing a Certificate is Valid</a></h2>
<li>SSL/TLS is offered to the client, but the client isn't required to use it.</li>
<li>The client is allowed to login with plaintext authentication even when SSL/TLS isn't enabled on the connection.</li>
<li><strong>This is insecure</strong>, because the plaintext password is exposed to the internet.</li>
</ul>
<h2id="importing-certificates-obtained-via-another-source"><aclass="toclink"href="#importing-certificates-obtained-via-another-source">Importing Certificates Obtained via Another Source</a></h2>
<p>If you have another source for SSL/TLS certificates you can import them into the server via an external script. The external script can be found here: <ahref="https://github.com/hanscees/dockerscripts/blob/master/scripts/tomav-renew-certs">external certificate import script</a>.</p>
<p>This is a community contributed script, and in most cases you will have better support via our <em>Change Detection</em> service (<em>automatic for <code>SSL_TYPE</code> of <code>manual</code> and <code>letsencrypt</code></em>) - Unless you're using LDAP which disables the service.</p>
<li>Relies on private filepaths <code>/etc/dms/tls/cert</code> and <code>/etc/dms/tls/key</code> intended for internal use only.</li>
<li>Only supports hard-coded <code>fullchain.key</code> + <code>privkey.pem</code> as your mounted file names. That may not align with your provisioning method.</li>
<li>No support for <code>ALT</code> fallback certificates (<em>for supporting dual/hybrid, RSA + ECDSA</em>).</li>
</ul>
</div>
<p>The steps to follow are these:</p>
<ol>
<li>Transfer the new certificates to <code>./docker-data/dms/custom-certs/</code> (volume mounted to: <code>/tmp/ssl/</code>)</li>
<li>You should provide <code>fullchain.key</code> and <code>privkey.pem</code></li>
<li>Place the script in <code>./docker-data/dms/config/</code> (volume mounted to: <code>/tmp/docker-mailserver/</code>)</li>
<li>Make the script executable (<code>chmod +x tomav-renew-certs.sh</code>)</li>
<li>Run the script: <code>docker exec mailserver /tmp/docker-mailserver/tomav-renew-certs.sh</code></li>
</ol>
<p>If an error occurs the script will inform you. If not you will see both postfix and dovecot restart.</p>
<p>After the certificates have been loaded you can check the certificate:</p>
<spanclass="nb">export</span><spanclass="w"></span><spanclass="nv">SITE_IP_URL</span><spanclass="o">=</span><spanclass="s2">"192.168.0.72"</span><spanclass="w"></span><spanclass="c1"># can also use `mail.example.com`</span>
<spanclass="nb">export</span><spanclass="w"></span><spanclass="nv">SITE_SSL_PORT</span><spanclass="o">=</span><spanclass="s2">"993"</span><spanclass="w"></span><spanclass="c1"># imap port dovecot</span>
<spanclass="c1">##works: check if certificate will expire in two weeks</span>
<spanclass="c1">#2 weeks is 1209600 seconds</span>
<spanclass="c1">#notes: output could be either:</span>
<spanclass="c1">#Certificate will not expire</span>
<spanclass="c1">#Certificate will expire</span>
<spanclass="c1">####################</span>
</code></pre></div>
<p>What does the script that imports the certificates do:</p>
<ol>
<li>Check if there are new certs in the internal container folder: <code>/tmp/ssl</code>.</li>
<li>Check with the ssl cert fingerprint if they differ from the current certificates.</li>
<li>If so it will copy the certs to the right places.</li>
<li>And restart postfix and dovecot.</li>
</ol>
<p>You can of course run the script by cron once a week or something. In that way you could automate cert renewal. If you do so it is probably wise to run an automated check on certificate expiry as well. Such a check could look something like this:</p>
<divclass="highlight"><pre><span></span><code><spanclass="c1"># This script is run inside docker-mailserver via 'docker exec ...', using the 'mail' command to send alerts.</span>
<spanclass="c1">## code below will alert if certificate expires in less than two weeks</span>
<spanclass="nb">export</span><spanclass="w"></span><spanclass="nv">SITE_IP_URL</span><spanclass="o">=</span><spanclass="s2">"192.168.2.72"</span><spanclass="w"></span><spanclass="c1"># can also use `mail.example.com`</span>
<spanclass="nb">export</span><spanclass="w"></span><spanclass="nv">SITE_SSL_PORT</span><spanclass="o">=</span><spanclass="s2">"993"</span><spanclass="w"></span><spanclass="c1"># imap port dovecot</span>
<spanclass="c1"># Below can be from a different domain; like your personal email, not handled by this docker-mailserver:</span>
<spanclass="c1">##automated check you might run by cron or something</span>
<spanclass="c1">## does the certificate expire within two weeks?</span>
<spanclass="k">if</span><spanclass="w"></span><spanclass="o">[</span><spanclass="w"></span><spanclass="s2">"</span><spanclass="nv">$certcheck_2weeks</span><spanclass="s2">"</span><spanclass="w"></span><spanclass="o">=</span><spanclass="w"></span><spanclass="s2">"Certificate will not expire"</span><spanclass="w"></span><spanclass="o">]</span><spanclass="p">;</span><spanclass="w"></span><spanclass="k">then</span>
<spanclass="w"></span><spanclass="nb">echo</span><spanclass="w"></span><spanclass="s2">"all is well, certwatch 2 weeks says </span><spanclass="nv">$certcheck_2weeks</span><spanclass="s2">"</span>
<spanclass="w"></span><spanclass="k">else</span>
<spanclass="w"></span><spanclass="nb">echo</span><spanclass="w"></span><spanclass="s2">"Cert seems to be expiring pretty soon, within two weeks: </span><spanclass="nv">$certcheck_2weeks</span><spanclass="s2">"</span>
<spanclass="w"></span><spanclass="nb">echo</span><spanclass="w"></span><spanclass="s2">"we will send an alert email and log as well"</span>
<spanclass="w"></span><spanclass="nb">echo</span><spanclass="w"></span><spanclass="s2">"Certwatch: cert </span><spanclass="nv">$SITE_URL</span><spanclass="s2"> will expire in two weeks"</span><spanclass="w"></span><spanclass="p">|</span><spanclass="w"></span>mail<spanclass="w"></span>-s<spanclass="w"></span><spanclass="s2">"cert </span><spanclass="nv">$SITE_URL</span><spanclass="s2"> expires in two weeks "</span><spanclass="w"></span><spanclass="nv">$ALERT_EMAIL_ADDR</span>
<p>By default DMS uses <ahref="https://github.com/internetstandards/dhe_groups"><code>ffdhe4096</code></a> from <ahref="https://datatracker.ietf.org/doc/html/rfc7919">IETF RFC 7919</a>. These are standardized pre-defined DH groups and the only available DH groups for TLS 1.3. It is <ahref="https://crypto.stackexchange.com/questions/29926/what-diffie-hellman-parameters-should-i-use">discouraged to generate your own DH parameters</a> as it is often less secure.</p>
<p>Despite this, if you must use non-standard DH parameters or you would like to swap <code>ffdhe4096</code> for a different group (eg <code>ffdhe2048</code>); Add your own PEM encoded DH params file via a volume to <code>/tmp/docker-mailserver/dhparams.pem</code>. This will replace DH params for both Dovecot and Postfix services during container startup.</p>
<scriptid="__config"type="application/json">{"base":"../../..","features":["navigation.tabs","navigation.top","navigation.expand","navigation.instant","content.action.edit","content.action.view","content.code.annotate"],"search":"../../../assets/javascripts/workers/search.b8dbb3d2.min.js","translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":{"provider":"mike"}}</script>