docker-mailserver/edge/config/advanced/kubernetes/index.html

2988 lines
125 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="A fullstack but simple mail-server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.) using Docker.">
<meta name="author" content="docker-mailserver (Github Organization)">
<link rel="canonical" href="https://docker-mailserver.github.io/docker-mailserver/edge/config/advanced/kubernetes/">
<link rel="prev" href="../full-text-search/">
<link rel="next" href="../ipv6/">
<link rel="icon" href="../../../assets/logo/favicon-32x32.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.18">
<title>Advanced | Kubernetes - Docker Mailserver</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.66ac8b77.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../../assets/css/customizations.css">
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#introduction" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<div data-md-color-scheme="default" data-md-component="outdated" hidden>
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../.." title="Docker Mailserver" class="md-header__button md-logo" aria-label="Docker Mailserver" data-md-component="logo">
<img src="../../../assets/logo/dmo-logo-white.min.svg" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Docker Mailserver
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Advanced | Kubernetes
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="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">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3 3.19.09m3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95 2.06.05m-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31Z"/></svg>
</label>
<input class="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">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5c-.84 0-1.65.15-2.39.42L12 2M3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29L3.34 7m.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14L3.36 17M20.65 7l-1.77 3.79a7.023 7.023 0 0 0-2.38-4.15l4.15.36m-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29L20.64 17M12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44L12 22Z"/></svg>
</label>
</form>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/docker-mailserver/docker-mailserver" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
</div>
<div class="md-source__repository">
docker-mailserver
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../../introduction/" class="md-tabs__link">
Introduction
</a>
</li>
<li class="md-tabs__item">
<a href="../../../usage/" class="md-tabs__link">
Usage
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../environment/" class="md-tabs__link">
Configuration
</a>
</li>
<li class="md-tabs__item">
<a href="../../../examples/tutorials/basic-installation/" class="md-tabs__link">
Examples
</a>
</li>
<li class="md-tabs__item">
<a href="../../../faq/" class="md-tabs__link">
FAQ
</a>
</li>
<li class="md-tabs__item">
<a href="../../../contributing/general/" class="md-tabs__link">
Contributing
</a>
</li>
<li class="md-tabs__item">
<a href="https://hub.docker.com/r/mailserver/docker-mailserver/" class="md-tabs__link">
<span class="icon-external-link"></span>DockerHub
</a>
</li>
<li class="md-tabs__item">
<a href="https://github.com/docker-mailserver/docker-mailserver/pkgs/container/docker-mailserver" class="md-tabs__link">
<span class="icon-external-link"></span>GHCR
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../.." title="Docker Mailserver" class="md-nav__button md-logo" aria-label="Docker Mailserver" data-md-component="logo">
<img src="../../../assets/logo/dmo-logo-white.min.svg" alt="logo">
</a>
Docker Mailserver
</label>
<div class="md-nav__source">
<a href="https://github.com/docker-mailserver/docker-mailserver" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
</div>
<div class="md-source__repository">
docker-mailserver
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../introduction/" class="md-nav__link">
<span class="md-ellipsis">
Introduction
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../usage/" class="md-nav__link">
<span class="md-ellipsis">
Usage
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" checked>
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="">
<span class="md-ellipsis">
Configuration
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../environment/" class="md-nav__link">
<span class="md-ellipsis">
Environment Variables
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-management/" class="md-nav__link">
<span class="md-ellipsis">
User Management
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_3" >
<label class="md-nav__link" for="__nav_4_3" id="__nav_4_3_label" tabindex="0">
<span class="md-ellipsis">
Best Practices
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_3">
<span class="md-nav__icon md-icon"></span>
Best Practices
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../best-practices/autodiscover/" class="md-nav__link">
<span class="md-ellipsis">
Auto-discovery
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../best-practices/dkim_dmarc_spf/" class="md-nav__link">
<span class="md-ellipsis">
DKIM, DMARC & SPF
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../best-practices/mta-sts/" class="md-nav__link">
<span class="md-ellipsis">
MTA-STS
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_4" >
<label class="md-nav__link" for="__nav_4_4" id="__nav_4_4_label" tabindex="0">
<span class="md-ellipsis">
Security
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_4">
<span class="md-nav__icon md-icon"></span>
Security
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../security/understanding-the-ports/" class="md-nav__link">
<span class="md-ellipsis">
Understanding the Ports
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/ssl/" class="md-nav__link">
<span class="md-ellipsis">
SSL/TLS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/fail2ban/" class="md-nav__link">
<span class="md-ellipsis">
Fail2Ban
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/mail_crypt/" class="md-nav__link">
<span class="md-ellipsis">
Mail Encryption
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../security/rspamd/" class="md-nav__link">
<span class="md-ellipsis">
Rspamd
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../debugging/" class="md-nav__link">
<span class="md-ellipsis">
Debugging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../pop3/" class="md-nav__link">
<span class="md-ellipsis">
Mail Delivery with POP3
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../setup.sh/" class="md-nav__link">
<span class="md-ellipsis">
About setup.sh
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_8" checked>
<label class="md-nav__link" for="__nav_4_8" id="__nav_4_8_label" tabindex="0">
<span class="md-ellipsis">
Advanced Configuration
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_8_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_4_8">
<span class="md-nav__icon md-icon"></span>
Advanced Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../optional-config/" class="md-nav__link">
<span class="md-ellipsis">
Optional Configuration
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_8_2" >
<label class="md-nav__link" for="__nav_4_8_2" id="__nav_4_8_2_label" tabindex="0">
<span class="md-ellipsis">
Maintenance
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_8_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8_2">
<span class="md-nav__icon md-icon"></span>
Maintenance
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../maintenance/update-and-cleanup/" class="md-nav__link">
<span class="md-ellipsis">
Update and Cleanup
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_8_3" >
<label class="md-nav__link" for="__nav_4_8_3" id="__nav_4_8_3_label" tabindex="0">
<span class="md-ellipsis">
Override the Default Configs
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_8_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8_3">
<span class="md-nav__icon md-icon"></span>
Override the Default Configs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../override-defaults/dovecot/" class="md-nav__link">
<span class="md-ellipsis">
Dovecot
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../override-defaults/postfix/" class="md-nav__link">
<span class="md-ellipsis">
Postfix
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../override-defaults/user-patches/" class="md-nav__link">
<span class="md-ellipsis">
Modifications via Script
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../auth-ldap/" class="md-nav__link">
<span class="md-ellipsis">
LDAP Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../auth-oauth2/" class="md-nav__link">
<span class="md-ellipsis">
OAuth2 Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mail-sieve/" class="md-nav__link">
<span class="md-ellipsis">
Email Filtering with Sieve
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mail-fetchmail/" class="md-nav__link">
<span class="md-ellipsis">
Email Gathering with Fetchmail
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mail-getmail/" class="md-nav__link">
<span class="md-ellipsis">
Email Gathering with Getmail
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_8_9" >
<label class="md-nav__link" for="__nav_4_8_9" id="__nav_4_8_9_label" tabindex="0">
<span class="md-ellipsis">
Email Forwarding
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_8_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8_9">
<span class="md-nav__icon md-icon"></span>
Email Forwarding
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../mail-forwarding/relay-hosts/" class="md-nav__link">
<span class="md-ellipsis">
Relay Hosts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mail-forwarding/aws-ses/" class="md-nav__link">
<span class="md-ellipsis">
AWS SES
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mail-forwarding/gmail-smtp/" class="md-nav__link">
<span class="md-ellipsis">
Configure Gmail as a relay host
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../full-text-search/" class="md-nav__link">
<span class="md-ellipsis">
Full-Text Search
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Kubernetes
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Kubernetes
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#introduction" class="md-nav__link">
<span class="md-ellipsis">
Introduction
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#manually-writing-manifests" class="md-nav__link">
<span class="md-ellipsis">
Manually Writing Manifests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#exposing-your-mail-server-to-the-outside-world" class="md-nav__link">
<span class="md-ellipsis">
Exposing your Mail Server to the Outside World
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../ipv6/" class="md-nav__link">
<span class="md-ellipsis">
IPv6
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../podman/" class="md-nav__link">
<span class="md-ellipsis">
Podman
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../dovecot-master-accounts/" class="md-nav__link">
<span class="md-ellipsis">
Dovecot Master Accounts
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Examples
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Examples
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5_1" >
<label class="md-nav__link" for="__nav_5_1" id="__nav_5_1_label" tabindex="0">
<span class="md-ellipsis">
Tutorials
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_1">
<span class="md-nav__icon md-icon"></span>
Tutorials
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../examples/tutorials/basic-installation/" class="md-nav__link">
<span class="md-ellipsis">
Basic Installation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/tutorials/mailserver-behind-proxy/" class="md-nav__link">
<span class="md-ellipsis">
Mailserver behind Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/tutorials/crowdsec/" class="md-nav__link">
<span class="md-ellipsis">
Crowdsec
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/tutorials/docker-build/" class="md-nav__link">
<span class="md-ellipsis">
Building your own Docker image
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/tutorials/blog-posts/" class="md-nav__link">
<span class="md-ellipsis">
Blog Posts
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5_2" >
<label class="md-nav__link" for="__nav_5_2" id="__nav_5_2_label" tabindex="0">
<span class="md-ellipsis">
Use Cases
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_2">
<span class="md-nav__icon md-icon"></span>
Use Cases
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../examples/use-cases/forward-only-mailserver-with-ldap-authentication/" class="md-nav__link">
<span class="md-ellipsis">
Forward-Only Mail-Server with LDAP
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/use-cases/imap-folders/" class="md-nav__link">
<span class="md-ellipsis">
Customize IMAP Folders
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/use-cases/ios-mail-push-support/" class="md-nav__link">
<span class="md-ellipsis">
iOS Mail Push Support
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/use-cases/auth-lua/" class="md-nav__link">
<span class="md-ellipsis">
Lua Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/use-cases/bind-smtp-network-interface/" class="md-nav__link">
<span class="md-ellipsis">
Bind outbound SMTP to a specific network
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../examples/use-cases/external-relay-only-mailserver/" class="md-nav__link">
<span class="md-ellipsis">
Relay inbound and outbound mail for an internal DMS
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../../faq/" class="md-nav__link">
<span class="md-ellipsis">
FAQ
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="0">
<span class="md-ellipsis">
Contributing
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Contributing
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../contributing/general/" class="md-nav__link">
<span class="md-ellipsis">
General Information
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../contributing/tests/" class="md-nav__link">
<span class="md-ellipsis">
Tests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../contributing/issues-and-pull-requests/" class="md-nav__link">
<span class="md-ellipsis">
Issues and Pull Requests
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="https://hub.docker.com/r/mailserver/docker-mailserver/" class="md-nav__link">
<span class="md-ellipsis">
<span class="icon-external-link"></span>DockerHub
</span>
</a>
</li>
<li class="md-nav__item">
<a href="https://github.com/docker-mailserver/docker-mailserver/pkgs/container/docker-mailserver" class="md-nav__link">
<span class="md-ellipsis">
<span class="icon-external-link"></span>GHCR
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#introduction" class="md-nav__link">
<span class="md-ellipsis">
Introduction
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#manually-writing-manifests" class="md-nav__link">
<span class="md-ellipsis">
Manually Writing Manifests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#exposing-your-mail-server-to-the-outside-world" class="md-nav__link">
<span class="md-ellipsis">
Exposing your Mail Server to the Outside World
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<a href="https://github.com/docker-mailserver/docker-mailserver/edit/master/docs/content/config/advanced/kubernetes.md" title="Edit this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4v-2m10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1 2.1 2.1Z"/></svg>
</a>
<a href="https://github.com/docker-mailserver/docker-mailserver/raw/master/docs/content/config/advanced/kubernetes.md" title="View source of this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.15 8.15 0 0 1-1.23-2Z"/></svg>
</a>
<h1>Kubernetes</h1>
<h2 id="introduction"><a class="toclink" href="#introduction">Introduction</a></h2>
<p>This article describes how to deploy DMS to Kubernetes. We highly recommend everyone to use our community <a href="https://github.com/docker-mailserver/docker-mailserver-helm">DMS Helm chart</a>.</p>
<div class="admonition note">
<p class="admonition-title">Requirements</p>
<ol>
<li>Basic knowledge about Kubernetes from the reader.</li>
<li>A basic understanding of mail servers.</li>
<li>Ideally, the reader has already deployed DMS before with a simpler setup (<em><code>docker run</code> or Docker Compose</em>).</li>
</ol>
</div>
<div class="admonition warning">
<p class="admonition-title">Limited Support</p>
<p>DMS <strong>does not officially support Kubernetes</strong>. This content is entirely community-supported. If you find errors, please open an issue and raise a PR.</p>
</div>
<h2 id="manually-writing-manifests"><a class="toclink" href="#manually-writing-manifests">Manually Writing Manifests</a></h2>
<p>If using our Helm chart is not viable for you, here is some guidance to start with your own manifests.</p>
<!-- This empty quote block is purely for a visual border -->
<div class="admonition quote">
<div class="tabbed-set tabbed-alternate" data-tabs="1:5"><input checked="checked" id="configmap" name="__tabbed_1" type="radio" /><input id="persistentvolumeclaim" name="__tabbed_1" type="radio" /><input id="service" name="__tabbed_1" type="radio" /><input id="certificate" name="__tabbed_1" type="radio" /><input id="deployment" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="configmap"><code>ConfigMap</code></label><label for="persistentvolumeclaim"><code>PersistentVolumeClaim</code></label><label for="service"><code>Service</code></label><label for="certificate"><code>Certificate</code></label><label for="deployment"><code>Deployment</code></label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<p>Provide the basic configuration via environment variables with a <code>ConfigMap</code>.</p>
<div class="admonition example">
<p class="admonition-title">Example</p>
<p>Below is only an example configuration, adjust the <code>ConfigMap</code> to your own needs.</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ConfigMap</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver.environment</span>
<span class="nt">immutable</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">data</span><span class="p">:</span>
<span class="w"> </span><span class="nt">TLS_LEVEL</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">modern</span>
<span class="w"> </span><span class="nt">POSTSCREEN_ACTION</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">drop</span>
<span class="w"> </span><span class="nt">OVERRIDE_HOSTNAME</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail.example.com</span>
<span class="w"> </span><span class="nt">FAIL2BAN_BLOCKTYPE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">drop</span>
<span class="w"> </span><span class="nt">POSTMASTER_ADDRESS</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">postmaster@example.com</span>
<span class="w"> </span><span class="nt">UPDATE_CHECK_INTERVAL</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10d</span>
<span class="w"> </span><span class="nt">POSTFIX_INET_PROTOCOLS</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ipv4</span>
<span class="w"> </span><span class="nt">ENABLE_CLAMAV</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">ENABLE_POSTGREY</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;0&#39;</span>
<span class="w"> </span><span class="nt">ENABLE_FAIL2BAN</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">AMAVIS_LOGLEVEL</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;-1&#39;</span>
<span class="w"> </span><span class="nt">SPOOF_PROTECTION</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">MOVE_SPAM_TO_JUNK</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">ENABLE_UPDATE_CHECK</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">ENABLE_SPAMASSASSIN</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="nt">SUPERVISOR_LOGLEVEL</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">warn</span>
<span class="w"> </span><span class="nt">SPAMASSASSIN_SPAM_TO_INBOX</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;1&#39;</span>
<span class="w"> </span><span class="c1"># here, we provide an example for the SSL configuration</span>
<span class="w"> </span><span class="nt">SSL_TYPE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">manual</span>
<span class="w"> </span><span class="nt">SSL_CERT_PATH</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/secrets/ssl/rsa/tls.crt</span>
<span class="w"> </span><span class="nt">SSL_KEY_PATH</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/secrets/ssl/rsa/tls.key</span>
</code></pre></div>
</div>
<p>You can also make use of user-provided configuration files (<em>e.g. <code>user-patches.sh</code>, <code>postfix-accounts.cf</code>, etc</em>), to customize DMS to your needs.</p>
<details class="example">
<summary>Providing config files</summary>
<p>Here is a minimal example that supplies a <code>postfix-accounts.cf</code> file inline with two users:</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ConfigMap</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver.files</span>
<span class="nt">data</span><span class="p">:</span>
<span class="w"> </span><span class="nt">postfix-accounts.cf</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
<span class="w"> </span><span class="no">test@example.com|{SHA512-CRYPT}$6$someHashValueHere</span>
<span class="w"> </span><span class="no">other@example.com|{SHA512-CRYPT}$6$someOtherHashValueHere</span>
</code></pre></div>
<div class="admonition warning">
<p class="admonition-title">Static Configuration</p>
<p>The inline <code>postfix-accounts.cf</code> config example above provides file content that is static. It is mounted as read-only at runtime, thus cannot support modifications.</p>
<p>For production deployments, use persistent volumes instead (via <code>PersistentVolumeClaim</code>). That will enable files like <code>postfix-account.cf</code> to add and remove accounts, while also persisting those changes externally from the container.</p>
</div>
</details>
<div class="admonition tip">
<p class="admonition-title">Modularize your <code>ConfigMap</code></p>
<p><a href="https://kustomize.io/">Kustomize</a> can be a useful tool as it supports creating a <code>ConfigMap</code> from multiple files.</p>
</div>
</div>
<div class="tabbed-block">
<p>To persist data externally from the DMS container, configure a <code>PersistentVolumeClaim</code> (PVC).</p>
<p>Make sure you have a storage system (like Longhorn, Rook, etc.) and that you choose the correct <code>storageClassName</code> (according to your storage system).</p>
<div class="admonition example">
<p class="admonition-title">Example</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">PersistentVolumeClaim</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">storageClassName</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">local-path</span>
<span class="w"> </span><span class="nt">accessModes</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ReadWriteOnce</span>
<span class="w"> </span><span class="nt">resources</span><span class="p">:</span>
<span class="w"> </span><span class="nt">requests</span><span class="p">:</span>
<span class="w"> </span><span class="nt">storage</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25Gi</span>
</code></pre></div>
</div>
</div>
<div class="tabbed-block">
<p>A <a href="https://kubernetes.io/docs/concepts/services-networking/service"><code>Service</code></a> is required for getting the traffic to the pod itself. It configures a load balancer with the ports you'll need.</p>
<p>The configuration for a <code>Service</code> affects if the original IP from a connecting client is preserved (<em>this is important</em>). <a href="#exposing-your-mail-server-to-the-outside-world">More about this further down below</a>.</p>
<div class="admonition example">
<p class="admonition-title">Example</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Service</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LoadBalancer</span>
<span class="w"> </span><span class="nt">selector</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># smtp</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="c1"># submissions (ESMTP with implicit TLS)</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submission</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">465</span>
<span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submissions</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="c1"># submission (ESMTP with explicit TLS)</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submission</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">587</span>
<span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submission</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="c1"># imaps (implicit TLS)</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">993</span>
<span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
</code></pre></div>
</div>
</div>
<div class="tabbed-block">
<div class="admonition example">
<p class="admonition-title">Using <a href="https://cert-manager.io/docs/"><code>cert-manager</code></a> to supply TLS certificates</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cert-manager.io/v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Certificate</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail-tls-certificate-rsa</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">secretName</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail-tls-certificate-rsa</span>
<span class="w"> </span><span class="nt">isCA</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="nt">privateKey</span><span class="p">:</span>
<span class="w"> </span><span class="nt">algorithm</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">RSA</span>
<span class="w"> </span><span class="nt">encoding</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">PKCS1</span>
<span class="w"> </span><span class="nt">size</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2048</span>
<span class="w"> </span><span class="nt">dnsNames</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">mail.example.com</span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">issuerRef</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail-issuer</span>
<span class="w"> </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Issuer</span>
</code></pre></div>
<p>The <a href="../../security/ssl/">TLS docs page</a> provides guidance when it comes to certificates and transport layer security.</p>
</div>
<div class="admonition tip">
<p class="admonition-title">ECDSA + RSA (fallback)</p>
<p>You could supply RSA certificates as fallback certificates instead, with ECDSA as the primary. DMS supports dual certificates via the ENV <code>SSL_ALT_CERT_PATH</code> and <code>SSL_ALT_KEY_PATH</code>.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Always provide sensitive information via a <code>Secret</code></p>
<p>For storing OpenDKIM keys, TLS certificates, or any sort of sensitive data - you should be using <code>Secret</code>s.</p>
<p>A <code>Secret</code> is similar to <code>ConfigMap</code>, it can be used and mounted as a volume as demonstrated in the <a href="#deployment"><code>Deployment</code> manifest</a> tab.</p>
</div>
</div>
<div class="tabbed-block">
<p>The <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment"><code>Deployment</code></a> config is the most complex component.</p>
<ul>
<li>It instructs Kubernetes how to run the DMS container and how to apply your <code>ConfigMap</code>s, persisted storage, etc.</li>
<li>Additional options can be set to enforce runtime security.</li>
</ul>
<details class="example" open="open">
<summary>Example</summary>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apps/v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deployment</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">annotations</span><span class="p">:</span>
<span class="w"> </span><span class="nt">ignore-check.kube-linter.io/run-as-non-root</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
<span class="w"> </span><span class="no">&#39;mailserver&#39; needs to run as root</span>
<span class="w"> </span><span class="nt">ignore-check.kube-linter.io/privileged-ports</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
<span class="w"> </span><span class="no">&#39;mailserver&#39; needs privileged ports</span>
<span class="w"> </span><span class="nt">ignore-check.kube-linter.io/no-read-only-root-fs</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
<span class="w"> </span><span class="no">There are too many files written to make the root FS read-only</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span>
<span class="w"> </span><span class="nt">selector</span><span class="p">:</span>
<span class="w"> </span><span class="nt">matchLabels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">template</span><span class="p">:</span>
<span class="w"> </span><span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">annotations</span><span class="p">:</span>
<span class="w"> </span><span class="nt">container.apparmor.security.beta.kubernetes.io/mailserver</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">runtime/default</span>
<span class="w"> </span><span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">hostname</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail</span>
<span class="w"> </span><span class="nt">containers</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ghcr.io/docker-mailserver/docker-mailserver:latest</span>
<span class="w"> </span><span class="nt">imagePullPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IfNotPresent</span>
<span class="w"> </span><span class="nt">securityContext</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># `allowPrivilegeEscalation: true` is required to support SGID via the `postdrop`</span>
<span class="w"> </span><span class="c1"># executable in `/var/mail-state` for Postfix (maildrop + public dirs):</span>
<span class="w"> </span><span class="c1"># https://github.com/docker-mailserver/docker-mailserver/pull/3625</span>
<span class="w"> </span><span class="nt">allowPrivilegeEscalation</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="nt">readOnlyRootFilesystem</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="nt">runAsUser</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0</span>
<span class="w"> </span><span class="nt">runAsGroup</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0</span>
<span class="w"> </span><span class="nt">runAsNonRoot</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="nt">privileged</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="nt">capabilities</span><span class="p">:</span>
<span class="w"> </span><span class="nt">add</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># file permission capabilities</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">CHOWN</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">FOWNER</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">MKNOD</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SETGID</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SETUID</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DAC_OVERRIDE</span>
<span class="w"> </span><span class="c1"># network capabilities</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">NET_ADMIN</span><span class="w"> </span><span class="c1"># needed for F2B</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">NET_RAW</span><span class="w"> </span><span class="c1"># needed for F2B</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">NET_BIND_SERVICE</span>
<span class="w"> </span><span class="c1"># miscellaneous capabilities</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SYS_CHROOT</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">KILL</span>
<span class="w"> </span><span class="nt">drop</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">ALL</span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">seccompProfile</span><span class="p">:</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">RuntimeDefault</span>
<span class="w"> </span><span class="c1"># Tune this to your needs.</span>
<span class="w"> </span><span class="c1"># If you disable ClamAV, you can use less RAM and CPU.</span>
<span class="w"> </span><span class="c1"># This becomes important in case you&#39;re low on resources</span>
<span class="w"> </span><span class="c1"># and Kubernetes refuses to schedule new pods.</span>
<span class="w"> </span><span class="nt">resources</span><span class="p">:</span>
<span class="w"> </span><span class="nt">limits</span><span class="p">:</span>
<span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4Gi</span>
<span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1500m</span>
<span class="w"> </span><span class="nt">requests</span><span class="p">:</span>
<span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2Gi</span>
<span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">600m</span>
<span class="w"> </span><span class="nt">volumeMounts</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">files</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">postfix-accounts.cf</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/tmp/docker-mailserver/postfix-accounts.cf</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="c1"># PVCs</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/var/mail</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/var/mail-state</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">state</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/var/log/mail</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">log</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w"> </span><span class="c1"># certificates</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">certificates-rsa</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/secrets/ssl/rsa/</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submissions</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">465</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submission</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">587</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">993</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="nt">envFrom</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">configMapRef</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver.environment</span>
<span class="w"> </span><span class="nt">restartPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Always</span>
<span class="w"> </span><span class="nt">volumes</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># configuration files</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">files</span>
<span class="w"> </span><span class="nt">configMap</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver.files</span>
<span class="w"> </span><span class="c1"># PVCs</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="nt">persistentVolumeClaim</span><span class="p">:</span>
<span class="w"> </span><span class="nt">claimName</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">data</span>
<span class="w"> </span><span class="c1"># certificates</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">certificates-rsa</span>
<span class="w"> </span><span class="nt">secret</span><span class="p">:</span>
<span class="w"> </span><span class="nt">secretName</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail-tls-certificate-rsa</span>
<span class="w"> </span><span class="nt">items</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">tls.key</span>
<span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">tls.key</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">tls.crt</span>
<span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">tls.crt</span>
</code></pre></div>
</details>
</div>
</div>
</div>
</div>
<h2 id="exposing-your-mail-server-to-the-outside-world"><a class="toclink" href="#exposing-your-mail-server-to-the-outside-world">Exposing your Mail Server to the Outside World</a></h2>
<p>The more difficult part with Kubernetes is to expose a deployed DMS instance to the outside world.</p>
<p>The major problem with exposing DMS to the outside world in Kubernetes is to <a href="https://kubernetes.io/docs/tutorials/services/source-ip">preserve the real client IP</a>. The real client IP is required by DMS for performing IP-based DNS and spam checks.</p>
<p>Kubernetes provides multiple ways to address this; each has its upsides and downsides.</p>
<!-- This empty quote block is purely for a visual border -->
<div class="admonition quote">
<div class="tabbed-set tabbed-alternate" data-tabs="2:3"><input checked="checked" id="configure-ip-manually" name="__tabbed_2" type="radio" /><input id="host-network" name="__tabbed_2" type="radio" /><input id="using-the-proxy-protocol" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="configure-ip-manually">Configure IP Manually</label><label for="host-network">Host network</label><label for="using-the-proxy-protocol">Using the PROXY Protocol</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<details class="abstract" open="open">
<summary>Advantages / Disadvantages</summary>
<ul class="task-list">
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled checked/><span class="task-list-indicator"></span></label> Simple</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Requires the node to have a dedicated, publicly routable IP address</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Limited to a single node (<em>associated to the dedicated IP address</em>)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Your deployment requires an explicit IP in your configuration (<em>or an entire Load Balancer</em>).</li>
</ul>
</details>
<div class="admonition info">
<p class="admonition-title">Requirements</p>
<ol>
<li>You can dedicate a <strong>publicly routable IP</strong> address for the DMS configured <code>Service</code>.</li>
<li>A dedicated IP is required to allow your mail server to have matching <code>A</code> and <code>PTR</code> records (<em>which other mail servers will use to verify trust when they receive mail sent from your DMS instance</em>).</li>
</ol>
</div>
<div class="admonition example">
<p class="admonition-title">Example</p>
<p>Assign the DMS <code>Service</code> an external IP directly, or delegate an LB to assign the IP on your behalf.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:2"><input checked="checked" id="external-ip-service" name="__tabbed_3" type="radio" /><input id="load-balancer" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="external-ip-service">External-IP Service</label><label for="load-balancer">Load-Balancer</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<p>The DMS <code>Service</code> is configured with an "<a href="https://kubernetes.io/docs/concepts/services-networking/service/#external-ips">external IP</a>" manually. Append your externally reachable IP address to <code>spec.externalIPs</code>.</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Service</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">selector</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="nt">externalIPs</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10.20.30.40</span>
</code></pre></div>
</div>
<div class="tabbed-block">
<p>The config differs depending on your choice of load balancer. This example uses <a href="https://metallb.universe.tf/">MetalLB</a>.</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Service</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">annotations</span><span class="p">:</span>
<span class="w"> </span><span class="nt">metallb.universe.tf/address-pool</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="c1"># ...</span>
<span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">metallb.io/v1beta1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IPAddressPool</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail</span>
<span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">metallb-system</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">addresses</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="w"> </span><span class="nv">&lt;YOUR PUBLIC DEDICATED IP IN CIDR NOTATION&gt;</span><span class="w"> </span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">autoAssign</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">metallb.io/v1beta1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">L2Advertisement</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail</span>
<span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">metallb-system</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">ipAddressPools</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="w"> </span><span class="nv">mailserver</span><span class="w"> </span><span class="p p-Indicator">]</span>
</code></pre></div>
</div>
</div>
</div>
</div>
</div>
<div class="tabbed-block">
<details class="abstract" open="open">
<summary>Advantages / Disadvantages</summary>
<ul class="task-list">
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled checked/><span class="task-list-indicator"></span></label> Simple</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Requires the node to have a dedicated, publicly routable IP address</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Limited to a single node (<em>associated to the dedicated IP address</em>)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> It is not possible to access DMS via other cluster nodes, only via the node that DMS was deployed on</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Every port within the container is exposed on the host side</li>
</ul>
</details>
<div class="admonition example">
<p class="admonition-title">Example</p>
<p>Using <code>hostPort</code> and <code>hostNetwork: true</code> is a similar approach to <a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#network_mode"><code>network_mode: host</code> with Docker Compose</a>.</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apps/v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deployment</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="c1"># ...</span>
<span class="w"> </span><span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">hostNetwork</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="nt">containers</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="nt">hostPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submissions</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">465</span>
<span class="w"> </span><span class="nt">hostPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">465</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">submission</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">587</span>
<span class="w"> </span><span class="nt">hostPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">587</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">993</span>
<span class="w"> </span><span class="nt">hostPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">993</span>
</code></pre></div>
</div>
</div>
<div class="tabbed-block">
<details class="abstract" open="open">
<summary>Advantages / Disadvantages</summary>
<ul class="task-list">
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled checked/><span class="task-list-indicator"></span></label> Preserves the origin IP address of clients (<em>which is crucial for DNS related checks</em>)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled checked/><span class="task-list-indicator"></span></label> Aligns with a best practice for Kubernetes by using a dedicated ingress, routing external traffic to the k8s cluster (<em>with the benefits of flexible routing rules</em>)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled checked/><span class="task-list-indicator"></span></label> Avoids the restraint of a single <a href="https://kubernetes.io/docs/concepts/architecture/nodes">node</a> (<em>as a workaround to preserve the original client IP</em>)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Introduces complexity by requiring:<ul>
<li>A reverse-proxy / ingress controller (<em>potentially extra setup</em>)</li>
<li>Kubernetes manifest changes for the DMS configured <code>Service</code></li>
<li>DMS configuration changes for Postfix and Dovecot</li>
</ul>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> To keep support for direct connections to DMS services internally within cluster, service ports must be "duplicated" to offer an alternative port for connections using PROXY protocol</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Custom Fail2Ban required: Because the traffic to DMS is now coming from the proxy, banning the origin IP address will have no effect; you'll need to implement a <a href="https://github.com/docker-mailserver/docker-mailserver/issues/1761#issuecomment-2016879319">custom solution for your setup</a>.</li>
</ul>
</details>
<details class="question">
<summary>What is the PROXY protocol?</summary>
<p>PROXY protocol is a network protocol for preserving a clients IP address when the clients TCP connection passes through a proxy.</p>
<p>It is a common feature supported among reverse-proxy services (<em>NGINX, HAProxy, Traefik</em>), which you may already have handling ingress traffic for your cluster.</p>
<pre class="mermaid"><code>flowchart LR
A(External Mail Server) --&gt;|Incoming connection| B
subgraph cluster
B("Ingress Acting as a Proxy") --&gt;|PROXY protocol connection| C(DMS)
end</code></pre>
<p>For more information on the PROXY protocol, refer to <a href="../../../examples/tutorials/mailserver-behind-proxy/">our dedicated docs page</a> on the topic.</p>
</details>
<details class="example" open="open">
<summary>Configure the Ingress Controller</summary>
<div class="tabbed-set tabbed-alternate" data-tabs="4:2"><input checked="checked" id="traefik" name="__tabbed_4" type="radio" /><input id="nginx" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="traefik">Traefik</label><label for="nginx">NGINX</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<p>On Traefik's side, the configuration is very simple.</p>
<ul>
<li>Create an entrypoint for each port that you want to expose (<em>probably 25, 465, 587 and 993</em>).</li>
<li>Each entrypoint should configure an <a href="https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroutetcp"><code>IngressRouteTCP</code></a> that routes to the equivalent internal DMS <code>Service</code> port which supports PROXY protocol connections.</li>
</ul>
<p>The below snippet demonstrates an example for two entrypoints, <code>submissions</code> (port 465) and <code>imaps</code> (port 993).</p>
<div class="highlight"><pre><span></span><code><span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Service</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># This an optimization to get rid of additional routing steps.</span>
<span class="w"> </span><span class="c1"># Previously &quot;type: LoadBalancer&quot;</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ClusterIP</span>
<span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.io/v1alpha1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IngressRouteTCP</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">entryPoints</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="w"> </span><span class="nv">submissions</span><span class="w"> </span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">routes</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">match</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">HostSNI(`*`)</span>
<span class="w"> </span><span class="nt">services</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">subs-proxy</span><span class="w"> </span><span class="c1"># note the 15 character limit here</span>
<span class="w"> </span><span class="nt">proxyProtocol</span><span class="p">:</span>
<span class="w"> </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span>
<span class="nn">---</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.io/v1alpha1</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IngressRouteTCP</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">entryPoints</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="w"> </span><span class="nv">imaps</span><span class="w"> </span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">routes</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">match</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">HostSNI(`*`)</span>
<span class="w"> </span><span class="nt">services</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mail</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps-proxy</span>
<span class="w"> </span><span class="nt">proxyProtocol</span><span class="p">:</span>
<span class="w"> </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span>
</code></pre></div>
<div class="admonition info">
<p class="admonition-title"><code>*-proxy</code> port name suffix</p>
<p>The <code>IngressRouteTCP</code> example configs above reference ports with a <code>*-proxy</code> suffix.</p>
<ul>
<li>These port variants will be defined in the <a href="#deployment"><code>Deployment</code> manifest</a>, and are scoped to the <code>mailserver</code> service (via <code>spec.routes.services.name</code>).</li>
<li>The suffix is used to distinguish that these ports are only compatible with connections using the PROXY protocol, which is what your ingress controller should be managing for you by adding the correct PROXY protocol headers to TCP connections it routes to DMS.</li>
</ul>
</div>
</div>
<div class="tabbed-block">
<p>With an <a href="https://kubernetes.github.io/ingress-nginx">NGINX ingress controller</a>, add the following to the TCP services config map (<em>as described <a href="https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services">here</a></em>):</p>
<div class="highlight"><pre><span></span><code><span class="nt">25</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;mailserver/mailserver:25::PROXY&quot;</span>
<span class="nt">465</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;mailserver/mailserver:465::PROXY&quot;</span>
<span class="nt">587</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;mailserver/mailserver:587::PROXY&quot;</span>
<span class="nt">993</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;mailserver/mailserver:993::PROXY&quot;</span>
</code></pre></div>
</div>
</div>
</div>
</details>
<details class="example" open="open">
<summary>Adjust DMS config for Dovecot + Postfix</summary>
<details class="warning">
<summary>Only ingress should connect to DMS with PROXY protocol</summary>
<p>While Dovecot will restrict connections via PROXY protocol to only clients trusted configured via <code>haproxy_trusted_networks</code>, Postfix does not have an equivalent setting. Public clients should always route through ingress to establish a PROXY protocol connection.</p>
<p>You are responsible for properly managing traffic inside your cluster and to <strong>ensure that only trustworthy entities</strong> can connect to the designated PROXY protocol ports.</p>
<p>With Kubernetes, this is usually the task of the CNI (<em>container network interface</em>).</p>
</details>
<div class="admonition tip">
<p class="admonition-title">Advised approach</p>
<p>The <em>"Separate PROXY protocol ports"</em> tab below introduces a little more complexity, but provides better compatibility for internal connections to DMS.</p>
</div>
<div class="tabbed-set tabbed-alternate" data-tabs="5:2"><input checked="checked" id="only-accept-connections-with-proxy-protocol" name="__tabbed_5" type="radio" /><input id="separate-proxy-protocol-ports-for-ingress" name="__tabbed_5" type="radio" /><div class="tabbed-labels"><label for="only-accept-connections-with-proxy-protocol">Only accept connections with PROXY protocol</label><label for="separate-proxy-protocol-ports-for-ingress">Separate PROXY protocol ports for ingress</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="admonition warning">
<p class="admonition-title">Connections to DMS within the internal cluster will be rejected</p>
<p>The services for these ports can only enable PROXY protocol support by mandating the protocol on all connections for these ports.</p>
<p>This can be problematic when you also need to support internal cluster traffic directly to DMS (<em>instead of routing indirectly through the ingress controller</em>).</p>
</div>
<p>Here is an example configuration for <a href="../override-defaults/postfix/">Postfix</a>, <a href="../override-defaults/dovecot/">Dovecot</a>, and the required adjustments for the <a href="#deployment"><code>Deployment</code> manifest</a>. The port names are adjusted here only to convey the additional context described earlier.</p>
<div class="highlight"><pre><span></span><code><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ConfigMap</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver-extra-config</span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="nt">data</span><span class="p">:</span>
<span class="w"> </span><span class="nt">postfix-main.cf</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
<span class="w"> </span><span class="no">postscreen_upstream_proxy_protocol = haproxy</span>
<span class="w"> </span><span class="nt">postfix-master.cf</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
<span class="w"> </span><span class="no">smtp/inet/postscreen_upstream_proxy_protocol=haproxy</span>
<span class="w"> </span><span class="no">submission/inet/smtpd_upstream_proxy_protocol=haproxy</span>
<span class="w"> </span><span class="no">submissions/inet/smtpd_upstream_proxy_protocol=haproxy</span>
<span class="w"> </span><span class="nt">dovecot.cf</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
<span class="w"> </span><span class="no">haproxy_trusted_networks = &lt;YOUR POD CIDR&gt;</span>
<span class="w"> </span><span class="no">service imap-login {</span>
<span class="w"> </span><span class="no">inet_listener imap {</span>
<span class="w"> </span><span class="no">haproxy = yes</span>
<span class="w"> </span><span class="no">}</span>
<span class="w"> </span><span class="no">inet_listener imaps {</span>
<span class="w"> </span><span class="no">haproxy = yes</span>
<span class="w"> </span><span class="no">}</span>
<span class="w"> </span><span class="no">}</span>
<span class="c1"># ...</span>
<span class="nn">---</span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deployment</span>
<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apps/v1</span>
<span class="nt">metadata</span><span class="p">:</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mailserver</span>
<span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">template</span><span class="p">:</span>
<span class="w"> </span><span class="nt">spec</span><span class="p">:</span>
<span class="w"> </span><span class="nt">containers</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">docker-mailserver</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">25</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imap-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">143</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">subs-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">465</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">sub-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">587</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">993</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="nt">volumeMounts</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">config</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">postfix-main.cf</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/tmp/docker-mailserver/postfix-main.cf</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">config</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">postfix-master.cf</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/tmp/docker-mailserver/postfix-master.cf</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">config</span>
<span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">dovecot.cf</span>
<span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/tmp/docker-mailserver/dovecot.cf</span>
<span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
</code></pre></div>
</div>
<div class="tabbed-block">
<div class="admonition info">
<p class="admonition-title">Info</p>
<p>Supporting internal cluster connections to DMS without using PROXY protocol requires both Postfix and Dovecot to be configured with alternative ports for each service port (<em>which only differ by enforcing PROXY protocol connections</em>).</p>
<ul>
<li>The ingress controller will route public connections to the internal alternative ports for DMS (<code>*-proxy</code> variants).</li>
<li>Internal cluster connections will instead use the original ports configured for the DMS container directly (<em>which are private to the cluster network</em>).</li>
</ul>
</div>
<p>In this example we'll create a copy of the original service ports with PROXY protocol enabled, and increment the port number assigned by <code>10000</code>.</p>
<p>Create a <code>user-patches.sh</code> file to apply these config changes during container startup:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="c1"># Duplicate the config for the submission(s) service ports (587 / 465) with adjustments for the PROXY ports (10587 / 10465) and `syslog_name` setting:</span>
postconf<span class="w"> </span>-Mf<span class="w"> </span>submission/inet<span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span>s/^submission/10587/<span class="w"> </span>-e<span class="w"> </span><span class="s1">&#39;s/submission/submission-proxyprotocol/&#39;</span><span class="w"> </span>&gt;&gt;<span class="w"> </span>/etc/postfix/master.cf
postconf<span class="w"> </span>-Mf<span class="w"> </span>submissions/inet<span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span>s/^submissions/10465/<span class="w"> </span>-e<span class="w"> </span><span class="s1">&#39;s/submissions/submissions-proxyprotocol/&#39;</span><span class="w"> </span>&gt;&gt;<span class="w"> </span>/etc/postfix/master.cf
<span class="c1"># Enable PROXY Protocol support for these new service variants:</span>
postconf<span class="w"> </span>-P<span class="w"> </span><span class="m">10587</span>/inet/smtpd_upstream_proxy_protocol<span class="o">=</span>haproxy
postconf<span class="w"> </span>-P<span class="w"> </span><span class="m">10465</span>/inet/smtpd_upstream_proxy_protocol<span class="o">=</span>haproxy
<span class="c1"># Create a variant for port 25 too (NOTE: Port 10025 is already assigned in DMS to Amavis):</span>
postconf<span class="w"> </span>-Mf<span class="w"> </span>smtp/inet<span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span>s/^smtp/12525/<span class="w"> </span>&gt;&gt;<span class="w"> </span>/etc/postfix/master.cf
<span class="c1"># Enable PROXY Protocol support (different setting as port 25 is handled via postscreen), optionally configure a `syslog_name` to distinguish in logs:</span>
postconf<span class="w"> </span>-P<span class="w"> </span><span class="m">12525</span>/inet/postscreen_upstream_proxy_protocol<span class="o">=</span>haproxy<span class="w"> </span><span class="m">12525</span>/inet/syslog_name<span class="o">=</span>smtp-proxyprotocol
</code></pre></div>
<p>For Dovecot, you can configure <a href="../override-defaults/dovecot/"><code>dovecot.cf</code></a> to look like this:</p>
<div class="highlight"><pre><span></span><code><span class="na">haproxy_trusted_networks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&lt;YOUR POD CIDR&gt;</span>
<span class="na">service imap-login {</span>
<span class="w"> </span><span class="na">inet_listener imap-proxied {</span>
<span class="w"> </span><span class="na">haproxy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">yes</span>
<span class="w"> </span><span class="na">port</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10143</span>
<span class="w"> </span><span class="na">}</span>
<span class="w"> </span><span class="na">inet_listener imaps-proxied {</span>
<span class="w"> </span><span class="na">haproxy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">yes</span>
<span class="w"> </span><span class="na">port</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10993</span>
<span class="w"> </span><span class="na">ssl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">yes</span>
<span class="w"> </span><span class="na">}</span>
<span class="na">}</span>
</code></pre></div>
<p>Update the <a href="#deployment"><code>Deployment</code> manifest</a> <code>ports</code> section by appending these new ports:</p>
<div class="highlight"><pre><span></span><code><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">smtp-proxy</span>
<span class="w"> </span><span class="c1"># not 10025 in this example due to a possible clash with Amavis</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12525</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imap-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10143</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">subs-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10465</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">sub-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10587</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">imaps-proxy</span>
<span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10993</span>
<span class="w"> </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">TCP</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If you use other Dovecot ports (110, 995, 4190), you may want to configure those similar to above. The <code>dovecot.cf</code> config for these ports is <a href="../../../examples/tutorials/mailserver-behind-proxy/">documented here</a> (<em>in the equivalent section of that page</em>).</p>
</div>
</div>
</div>
</div>
</details>
</div>
</div>
</div>
</div>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12Z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
<p>&copy <a href="https://github.com/docker-mailserver"><em>Docker Mailserver Organization</em></a><br/><span>This project is licensed under the MIT license.</span></p>
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__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>
<script src="../../../assets/javascripts/bundle.3220b9d7.min.js"></script>
</body>
</html>