docker-mailserver/edge/examples/tutorials/mailserver-behind-proxy/index.html

2705 lines
83 KiB
HTML

<!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/examples/tutorials/mailserver-behind-proxy/">
<link rel="prev" href="../basic-installation/">
<link rel="next" href="../crowdsec/">
<link rel="icon" href="../../../assets/logo/favicon-32x32.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.18">
<title>Tutorials | Mail Server behind a Proxy - 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="#using-a-reverse-proxy" 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">
Tutorials | Mail Server behind a Proxy
</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">
<a href="../../../config/environment/" class="md-tabs__link">
Configuration
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../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--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<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="false">
<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="../../../config/environment/" class="md-nav__link">
<span class="md-ellipsis">
Environment Variables
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/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="../../../config/best-practices/autodiscover/" class="md-nav__link">
<span class="md-ellipsis">
Auto-discovery
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/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="../../../config/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="../../../config/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="../../../config/security/ssl/" class="md-nav__link">
<span class="md-ellipsis">
SSL/TLS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/security/fail2ban/" class="md-nav__link">
<span class="md-ellipsis">
Fail2Ban
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/security/mail_crypt/" class="md-nav__link">
<span class="md-ellipsis">
Mail Encryption
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/security/rspamd/" class="md-nav__link">
<span class="md-ellipsis">
Rspamd
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../../config/debugging/" class="md-nav__link">
<span class="md-ellipsis">
Debugging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/pop3/" class="md-nav__link">
<span class="md-ellipsis">
Mail Delivery with POP3
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/setup.sh/" class="md-nav__link">
<span class="md-ellipsis">
About setup.sh
</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" >
<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="false">
<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="../../../config/advanced/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="../../../config/advanced/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="../../../config/advanced/override-defaults/dovecot/" class="md-nav__link">
<span class="md-ellipsis">
Dovecot
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/override-defaults/postfix/" class="md-nav__link">
<span class="md-ellipsis">
Postfix
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/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="../../../config/advanced/auth-ldap/" class="md-nav__link">
<span class="md-ellipsis">
LDAP Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/auth-oauth2/" class="md-nav__link">
<span class="md-ellipsis">
OAuth2 Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/mail-sieve/" class="md-nav__link">
<span class="md-ellipsis">
Email Filtering with Sieve
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/mail-fetchmail/" class="md-nav__link">
<span class="md-ellipsis">
Email Gathering with Fetchmail
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/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="../../../config/advanced/mail-forwarding/relay-hosts/" class="md-nav__link">
<span class="md-ellipsis">
Relay Hosts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/mail-forwarding/aws-ses/" class="md-nav__link">
<span class="md-ellipsis">
AWS SES
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/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="../../../config/advanced/full-text-search/" class="md-nav__link">
<span class="md-ellipsis">
Full-Text Search
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/kubernetes/" class="md-nav__link">
<span class="md-ellipsis">
Kubernetes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/ipv6/" class="md-nav__link">
<span class="md-ellipsis">
IPv6
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/podman/" class="md-nav__link">
<span class="md-ellipsis">
Podman
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../config/advanced/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--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" checked>
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<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="true">
<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--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_1" checked>
<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="true">
<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="../basic-installation/" class="md-nav__link">
<span class="md-ellipsis">
Basic Installation
</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">
Mailserver behind Proxy
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Mailserver behind Proxy
</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="#using-a-reverse-proxy" class="md-nav__link">
<span class="md-ellipsis">
Using a Reverse Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#what-can-go-wrong" class="md-nav__link">
<span class="md-ellipsis">
What can go wrong?
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#configuration" class="md-nav__link">
<span class="md-ellipsis">
Configuration
</span>
</a>
<nav class="md-nav" aria-label="Configuration">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#reverse-proxy" class="md-nav__link">
<span class="md-ellipsis">
Reverse Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#dms-postfix-dovecot" class="md-nav__link">
<span class="md-ellipsis">
DMS (Postfix + Dovecot)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verification" class="md-nav__link">
<span class="md-ellipsis">
Verification
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-concerns" class="md-nav__link">
<span class="md-ellipsis">
Security concerns
</span>
</a>
<nav class="md-nav" aria-label="Security concerns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#forgery" class="md-nav__link">
<span class="md-ellipsis">
Forgery
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#monitoring" class="md-nav__link">
<span class="md-ellipsis">
Monitoring
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../crowdsec/" class="md-nav__link">
<span class="md-ellipsis">
Crowdsec
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../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="../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="../../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="../../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="../../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="../../use-cases/auth-lua/" class="md-nav__link">
<span class="md-ellipsis">
Lua Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../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="../../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="#using-a-reverse-proxy" class="md-nav__link">
<span class="md-ellipsis">
Using a Reverse Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#what-can-go-wrong" class="md-nav__link">
<span class="md-ellipsis">
What can go wrong?
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#configuration" class="md-nav__link">
<span class="md-ellipsis">
Configuration
</span>
</a>
<nav class="md-nav" aria-label="Configuration">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#reverse-proxy" class="md-nav__link">
<span class="md-ellipsis">
Reverse Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#dms-postfix-dovecot" class="md-nav__link">
<span class="md-ellipsis">
DMS (Postfix + Dovecot)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verification" class="md-nav__link">
<span class="md-ellipsis">
Verification
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-concerns" class="md-nav__link">
<span class="md-ellipsis">
Security concerns
</span>
</a>
<nav class="md-nav" aria-label="Security concerns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#forgery" class="md-nav__link">
<span class="md-ellipsis">
Forgery
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#monitoring" class="md-nav__link">
<span class="md-ellipsis">
Monitoring
</span>
</a>
</li>
</ul>
</nav>
</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/examples/tutorials/mailserver-behind-proxy.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/examples/tutorials/mailserver-behind-proxy.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>Mailserver behind Proxy</h1>
<h2 id="using-a-reverse-proxy"><a class="toclink" href="#using-a-reverse-proxy">Using a Reverse Proxy</a></h2>
<p>Guidance is provided via a Traefik config example, however if you're only familiar with configuring a reverse proxy for web services there are some differences to keep in mind.</p>
<ul>
<li>A security concern where preserving the client IP is important but needs to be handled at Layer 4 (TCP).</li>
<li>TLS will be handled differently due protocols like STARTTLS and the need to comply with standards for interoperability with other MTAs.</li>
<li>The ability to route the same port to different containers by FQDN can be limited.</li>
</ul>
<p>This reduces many of the benefits for why you might use a reverse proxy, but they can still be useful.</p>
<p>Some deployments may require a service to route traffic (kubernetes) when deploying, in which case the below advice is important to understand well.</p>
<p>The guide here has also been adapted for <a href="../../../config/advanced/kubernetes/#using-the-proxy-protocol">our Kubernetes docs</a>.</p>
<h2 id="what-can-go-wrong"><a class="toclink" href="#what-can-go-wrong">What can go wrong?</a></h2>
<p>Without a reverse proxy involved, a service is typically aware of the client IP for a connection.</p>
<p>However when a reverse proxy routes the connection this information can be lost, and the proxied service mistakenly treats the client IP as the reverse proxy handling the connection.</p>
<ul>
<li>That can be problematic when the client IP is meaningful information for the proxied service to act upon, especially when it <a href="#security-concerns">impacts security</a>.</li>
<li>The <a href="https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt">PROXY protocol</a> is a well established solution to preserve the client IP when both the proxy and service have enabled the support.</li>
</ul>
<details class="abstract">
<summary>Technical Details - HTTP vs TCP proxying</summary>
<p>A key difference for how the network is proxied relates to the <a href="https://www.cloudflare.com/learning/ddos/glossary/open-systems-interconnection-model-osi/">OSI Model</a>:</p>
<ul>
<li>Layer 7 (<em>Application layer protocols: SMTP / IMAP / HTTP / etc</em>)</li>
<li>Layer 4 (<em>Transport layer protocols: TCP / UDP</em>)</li>
</ul>
<p>When working with Layer 7 and a protocol like HTTP, it is possible to inspect a protocol header like <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded"><code>Forwarded</code></a> (<em>or it's predecessor: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For"><code>X-Forwarded-For</code></a></em>). At a lower level with Layer 4, that information is not available and we are routing traffic agnostic to the application protocol being proxied.</p>
<p>A proxy can prepend the <a href="https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt">PROXY protocol</a> header to the TCP/UDP connection as it is routed to the service, which must be configured to be compatible with PROXY protocol (<em>often this adds a restriction that connections must provide the header, otherwise they're rejected</em>).</p>
<p>Beyond your own proxy, traffic may be routed in the network by other means that would also rewrite this information such as Docker's own network management via <code>iptables</code> and <code>userland-proxy</code> (NAT). The PROXY header ensures the original source and destination IP addresses, along with their ports is preserved across transit.</p>
</details>
<h2 id="configuration"><a class="toclink" href="#configuration">Configuration</a></h2>
<h3 id="reverse-proxy"><a class="toclink" href="#reverse-proxy">Reverse Proxy</a></h3>
<p>The below guidance is focused on configuring <a href="https://traefik.io">Traefik</a>, but the advice should be roughly applicable elsewhere (<em>eg: <a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol">NGINX</a>, <a href="https://github.com/mholt/caddy-l4">Caddy</a></em>).</p>
<ul>
<li>Support requires the capability to proxy TCP (Layer 4) connections with PROXY protocol enabled for the upstream (DMS). The upstream must also support enabling PROXY protocol (<em>which for DMS services rejects any connection not using the protocol</em>).</li>
<li>TLS should not be terminated at the proxy, that should be delegated to DMS (<em>which should be configured with the TLS certs</em>). Reasoning is covered under the <a href="#ports">ports section</a>.</li>
</ul>
<details class="example" open="open">
<summary>Traefik service</summary>
<p>The Traefik service config is fairly standard, just define the necessary entrypoints:</p>
<div class="highlight"><span class="filename">compose.yaml</span><pre><span></span><code><span class="nt">services</span><span class="p">:</span>
<span class="w"> </span><span class="nt">reverse-proxy</span><span class="p">:</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">docker.io/traefik:latest</span><span class="w"> </span><span class="c1"># 2.10 / 3.0</span>
<span class="w"> </span><span class="c1"># CAUTION: In production you should configure the Docker API endpoint securely:</span>
<span class="w"> </span><span class="c1"># https://doc.traefik.io/traefik/providers/docker/#docker-api-access</span>
<span class="w"> </span><span class="nt">volumes</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">/var/run/docker.sock:/var/run/docker.sock</span>
<span class="w"> </span><span class="nt">command</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># Docker provider config:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--providers.docker=true</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--providers.docker.exposedbydefault=false</span>
<span class="w"> </span><span class="c1"># DMS ports you want to proxy:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-smtp.address=:25</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-submission.address=:587</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-submissions.address=:465</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-imap.address=:143</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-imaps.address=:993</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-pop3.address=:110</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-pop3s.address=:995</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">--entryPoints.mail-managesieve.address=:4190</span>
<span class="w"> </span><span class="c1"># Publish external access ports mapped to traefik entrypoint ports:</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="s">&quot;25:25&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;587:587&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;465:465&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;143:143&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;993:993&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;110:110&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;995:995&quot;</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">&quot;4190:4190&quot;</span>
<span class="w"> </span><span class="c1"># An IP is assigned here for other services (Dovecot) to trust for PROXY protocol:</span>
<span class="w"> </span><span class="nt">networks</span><span class="p">:</span>
<span class="w"> </span><span class="nt">default</span><span class="p">:</span>
<span class="w"> </span><span class="nt">ipv4_address</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">172.16.42.2</span>
<span class="c1"># Specifying a subnet to assign a fixed container IP to the reverse proxy:</span>
<span class="nt">networks</span><span class="p">:</span>
<span class="w"> </span><span class="nt">default</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">my-network</span>
<span class="w"> </span><span class="nt">ipam</span><span class="p">:</span>
<span class="w"> </span><span class="nt">config</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">subnet</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;172.16.42.0/24&quot;</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Extra considerations</p>
<ul>
<li><a href="https://doc.traefik.io/traefik/providers/docker/#network"><code>--providers.docker.network=my-network</code></a> is useful when there is more than one network to consider.</li>
<li>If your deployment has any other hops (an edge proxy, load balancer, etc) between the reverse proxy and the client, you'll need PROXY protocol support throughout that chain. For Traefik this additionally requires <a href="https://doc.traefik.io/traefik/routing/entrypoints/#proxyprotocol">enabling PROXY protocol on your entry points</a>.</li>
</ul>
</div>
</details>
<details class="example" open="open">
<summary>Traefik labels for DMS</summary>
<div class="highlight"><span class="filename">compose.yaml</span><pre><span></span><code><span class="nt">services</span><span class="p">:</span>
<span class="w"> </span><span class="nt">dms</span><span class="p">:</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">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">labels</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">traefik.enable=true</span>
<span class="w"> </span><span class="c1"># These are examples, configure the equivalent for any additional ports you proxy.</span>
<span class="w"> </span><span class="c1"># Explicit TLS (STARTTLS):</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-smtp.rule=HostSNI(`*`)</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-smtp.entrypoints=smtp</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-smtp.service=smtp</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.services.mail-smtp.loadbalancer.server.port=25</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.services.mail-smtp.loadbalancer.proxyProtocol.version=2</span>
<span class="w"> </span><span class="c1"># Implicit TLS is no different, except for optional HostSNI support:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-submissions.rule=HostSNI(`*`)</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-submissions.entrypoints=smtp-submissions</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.routers.mail-submissions.service=smtp-submissions</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.services.mail-submissions.loadbalancer.server.port=465</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">traefik.tcp.services.mail-submissions.loadbalancer.proxyProtocol.version=2</span>
<span class="w"> </span><span class="c1"># NOTE: Optionally match by SNI rule, this requires TLS passthrough (not compatible with STARTTLS):</span>
<span class="w"> </span><span class="c1">#- traefik.tcp.routers.mail-submissions.rule=HostSNI(`mail.example.com`)</span>
<span class="w"> </span><span class="c1">#- traefik.tcp.routers.mail-submissions.tls.passthrough=true</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">PROXY protocol compatibility</p>
<p>Only TCP routers support enabling PROXY Protocol (via <a href="https://doc.traefik.io/traefik/routing/services/#proxy-protocol"><code>proxyProtocol.version=2</code></a>)</p>
<p>Postfix and Dovecot are both compatible with PROXY protocol v1 and v2.</p>
</div>
</details>
<details class="abstract">
<summary>Technical Details - Ports (Traefik config)</summary>
<div class="admonition info">
<p class="admonition-title">Explicit TLS (STARTTLS)</p>
<p><strong>Service Ports:</strong> <code>mail-smtp</code> (25), <code>mail-submission</code> (587), <code>mail-imap</code> (143), <code>mail-pop3</code> (110), <code>mail-managesieve</code> (4190)</p>
<hr />
<ul>
<li><a href="https://doc.traefik.io/traefik/routing/routers/#entrypoints_1">Traefik expects the TCP router to not enable TLS</a> (<em>see "Server First protocols"</em>) for these connections. They begin in plaintext and potentially upgrade the connection to TLS, Traefik has no involvement in STARTTLS.</li>
<li>Without an initial TLS connection, the <a href="https://doc.traefik.io/traefik/routing/routers/#rule_1"><code>HostSNI</code> router rule is not usable</a> (<em>see "HostSNI &amp; TLS"</em>). This limits routing flexibility for these ports (<em>eg: routing these ports by the FQDN to different DMS containers</em>).</li>
</ul>
</div>
<div class="admonition info">
<p class="admonition-title">Implicit TLS</p>
<p><strong>Service Ports:</strong> <code>mail-submissions</code> (465), <code>mail-imaps</code> (993), <code>mail-pop3s</code> (995)</p>
<hr />
<p>The <code>HostSNI</code> router rule could specify the DMS FQDN instead of <code>*</code>:</p>
<ul>
<li>This requires the router to have TLS enabled, so that Traefik can inspect the server name sent by the client.</li>
<li>Traefik can only match the SNI to <code>*</code> when the client does not provide a server name. Some clients must explicitly opt-in, such as CLI clients <code>openssl</code> (<code>-servername</code>) and <code>swaks</code> (<code>--tls-sni</code>).</li>
<li>Add <a href="https://doc.traefik.io/traefik/routing/routers/#passthrough"><code>tls.passthrough=true</code> to the router</a> (<em>this implicitly enables TLS</em>).<ul>
<li>Traefik should not terminate TLS, decryption should occur within DMS instead when proxying to the same implicit TLS ports.</li>
<li>Passthrough ignores any certificates configured for Traefik; DMS must be configured with the certificates instead (<em><a href="../../../config/security/ssl/#traefik-v2">DMS can use <code>acme.json</code> from Traefik</a></em>).</li>
</ul>
</li>
</ul>
<p>Unlike proxying HTTPS (port 443) to a container via HTTP (port 80), the equivalent for DMS service ports is not supported:</p>
<ul>
<li>Port 25 must secure the connection via STARTTLS to be reached publicly.</li>
<li>STARTTLS ports requiring authentication for Postfix (587) and Dovecot (110, 143, 4190) are configured to only permit authentication over an encrypted connection.</li>
<li>Support would require routing the implicit TLS ports to their explicit TLS equivalent ports with auth restrictions removed. <code>tls.passthrough.true</code> would not be required, additionally port 25 would always be unencrypted (<em>if the proxy exclusively manages TLS/certs</em>), or unreachable by public MTAs attempting delivery if the proxy enables implicit TLS for this port.</li>
</ul>
</div>
</details>
<h3 id="dms-postfix-dovecot"><a class="toclink" href="#dms-postfix-dovecot">DMS (Postfix + Dovecot)</a></h3>
<details class="example" open="open">
<summary>Enable PROXY protocol on existing service ports</summary>
<p>This can be handled via our config override support.</p>
<hr />
<p>Postfix via <a href="../../../config/advanced/override-defaults/postfix/"><code>postfix-master.cf</code></a>:</p>
<div class="highlight"><span class="filename">docker-data/dms/config/postfix-master.cf</span><pre><span></span><code><span class="na">smtp/inet/postscreen_upstream_proxy_protocol</span><span class="o">=</span><span class="s">haproxy</span>
<span class="na">submission/inet/smtpd_upstream_proxy_protocol</span><span class="o">=</span><span class="s">haproxy</span>
<span class="na">submissions/inet/smtpd_upstream_proxy_protocol</span><span class="o">=</span><span class="s">haproxy</span>
</code></pre></div>
<p><a href="https://www.postfix.org/postconf.5.html#postscreen_upstream_proxy_protocol"><code>postscreen_upstream_proxy_protocol</code></a> and <a href="https://www.postfix.org/postconf.5.html#smtpd_upstream_proxy_protocol"><code>smtpd_upstream_proxy_protocol</code></a> both specify the protocol type used by a proxy. <code>haproxy</code> represents the PROXY protocol.</p>
<hr />
<p>Dovecot via <a href="../../../config/advanced/override-defaults/dovecot/"><code>dovecot.cf</code></a>:</p>
<div class="highlight"><span class="filename">docker-data/dms/config/dovecot.cf</span><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">172.16.42.2</span>
<span class="na">service imap-login {</span>
<span class="w"> </span><span class="na">inet_listener imap {</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">}</span>
<span class="w"> </span><span class="na">inet_listener imaps {</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">}</span>
<span class="na">}</span>
<span class="na">service pop3-login {</span>
<span class="w"> </span><span class="na">inet_listener pop3 {</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">}</span>
<span class="w"> </span><span class="na">inet_listener pop3s {</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">}</span>
<span class="na">}</span>
<span class="na">service managesieve-login {</span>
<span class="w"> </span><span class="na">inet_listener sieve {</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">}</span>
<span class="na">}</span>
</code></pre></div>
<ul>
<li><a href="https://doc.dovecot.org/settings/core/#core_setting-haproxy_trusted_networks"><code>haproxy_trusted_networks</code></a> must reference the reverse proxy IP, or a wider subnet using CIDR notation.</li>
<li><a href="https://doc.dovecot.org/configuration_manual/service_configuration/#haproxy-v2-2-19"><code>haproxy = yes</code></a> for the TCP listeners of each login service.</li>
</ul>
</details>
<div class="admonition warning">
<p class="admonition-title">Internal traffic (<em>within the network or DMS itself</em>)</p>
<ul>
<li>Direct connections to DMS from other containers within the internal network will be rejected when they don't provide the required PROXY header.</li>
<li>This can also affect services running within the DMS container itself if they attempt to make a connection and aren't PROXY protocol capable.</li>
</ul>
<hr />
<p>A solution is to configure alternative service ports that offer PROXY protocol support (as shown next).</p>
<p>Alternatively routing connections to DMS through the local reverse proxy via <a href="https://github.com/docker-mailserver/docker-mailserver/issues/3866#issuecomment-1928877236">DNS query rewriting</a> can work too.</p>
</div>
<details class="example">
<summary>Configuring services with separate ports for PROXY protocol</summary>
<p>In this example we'll take the original service ports and add <code>10000</code> for the new PROXY protocol service ports.</p>
<p>Traefik labels will need to update their service ports accordingly (eg: <code>.loadbalancer.server.port=10465</code>).</p>
<hr />
<p>Postfix config now requires <a href="../../../config/advanced/override-defaults/user-patches/">our <code>user-patches.sh</code> support</a> to add new services in <code>/etc/postfix/master.cf</code>:</p>
<div class="highlight"><span class="filename">docker-data/dms/config/user-patches.sh</span><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>
<hr />
<p>Dovecot is mostly the same as before:</p>
<ul>
<li>A new service name instead of targeting one to modify.</li>
<li>Add the new port assignment.</li>
<li>Set <a href="https://doc.dovecot.org/configuration_manual/service_configuration/#ssl"><code>ssl = yes</code></a> when implicit TLS is needed.</li>
</ul>
<div class="highlight"><span class="filename">docker-data/dms/config/dovecot.cf</span><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">172.16.42.2</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>
<span class="na">service pop3-login {</span>
<span class="w"> </span><span class="na">inet_listener pop3-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">10110</span>
<span class="w"> </span><span class="na">}</span>
<span class="w"> </span><span class="na">inet_listener pop3s-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">10995</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>
<span class="na">service managesieve-login {</span>
<span class="w"> </span><span class="na">inet_listener sieve-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">14190</span>
<span class="w"> </span><span class="na">}</span>
<span class="na">}</span>
</code></pre></div>
</details>
<h2 id="verification"><a class="toclink" href="#verification">Verification</a></h2>
<p>Send an email through the reverse proxy. If you do not use the DNS query rewriting approach, you'll need to do this from an external client.</p>
<details class="example">
<summary>Sending a generic test mail through <code>swaks</code> CLI</summary>
<p>Run a <code>swaks</code> command and then check your DMS logs for the expected client IP, it should no longer be using the reverse proxy IP.</p>
<div class="highlight"><pre><span></span><code><span class="c1"># NOTE: It is common to find port 25 is blocked from outbound connections, you may only be able to test the submission(s) ports.</span>
swaks<span class="w"> </span>--helo<span class="w"> </span>not-relevant.test<span class="w"> </span>--server<span class="w"> </span>mail.example.com<span class="w"> </span>--port<span class="w"> </span><span class="m">25</span><span class="w"> </span>-tls<span class="w"> </span>--from<span class="w"> </span>hello@not-relevant.test<span class="w"> </span>--to<span class="w"> </span>user@example.com
</code></pre></div>
<ul>
<li>You can specify the <code>--server</code> as the DMS FQDN or an IP address, where either should connect to the reverse proxy service.</li>
<li><code>not-relevant.test</code> technically may be subject to some tests, at least for port 25. With the submission(s) ports those should be exempt.</li>
<li><code>-tls</code> will use STARTTLS on port 25, you can exclude it to send unencrypted, but it would still go through the same port/route being tested.</li>
<li>To test the submission ports use <code>--port 587 -tls</code> or <code>--port 465 -tlsc</code> with your credentials <code>--auth-user user@example.com --auth-password secret</code></li>
<li>Add <code>--tls-sni mail.example.com</code> if you have configured <code>HostSNI</code> in Traefik router rules (<em>SNI routing is only valid for implicit TLS ports</em>).</li>
</ul>
</details>
<details class="warning">
<summary>Do not rely on local testing alone</summary>
<p>Testing from the Docker host technically works, however the IP is likely subject to more manipulation via <code>iptables</code> than an external client.</p>
<p>The IP will likely appear as from the gateway IP of the Docker network associated to the reverse proxy, where that gateway IP then becomes the client IP when writing the PROXY protocol header.</p>
</details>
<h2 id="security-concerns"><a class="toclink" href="#security-concerns">Security concerns</a></h2>
<h3 id="forgery"><a class="toclink" href="#forgery">Forgery</a></h3>
<p>Since the PROXY protocol sends a header with the client IP rewritten for software to use instead, this could be abused by bad actors.</p>
<p>Software on the receiving end of the connection often supports configuring an IP or CIDR range of clients to trust receiving the PROXY protocol header from.</p>
<details class="warning">
<summary>Risk exposure</summary>
<p>If you trust more than the reverse proxy IP, you must consider the risk exposure:</p>
<ul>
<li>Any container within the network that is compromised could impersonate another IP (<em>container or external client</em>) which may have been configured to have additional access/exceptions granted.</li>
<li>If the reverse proxy is on a separate network/host than DMS, exposure of the PROXY protocol enabled ports outside the network increases the importance of narrowing trust. For example with the <a href="../../../config/advanced/ipv6/#what-can-go-wrong">known IPv6 to subnet Gateway IP routing gotcha</a> in Docker, trusting the entire subnet DMS belongs to would wrongly trust external clients that have the subnet Gateway IP to impersonate any client IP.</li>
<li>There is a <a href="https://github.com/moby/moby/issues/45610">known risk with Layer 2 switching</a> (<em>applicable to VPC networks, impact varies by cloud vendor</em>):<ul>
<li>Neighbouring hosts can indirectly route to ports published on the interfaces of a separate host system that shouldn't be reachable (<em>eg: localhost <code>127.0.0.1</code>, or a private subnet <code>172.16.0.0/12</code></em>).</li>
<li>The scope of this in Docker is limited to published ports only when Docker uses <code>iptables</code> with the kernel tunable <code>sysctl net.ipv4.ip_forward=1</code> (enabled implicitly). Port access is via <code>HOST:CONTAINER</code> ports published to their respective interface(s), that includes the container IP + port.</li>
</ul>
</li>
</ul>
<p>While some concerns raised above are rather specific, these type of issues aren't exclusive to Docker and difficult to keep on top of as software is constantly changing. Limit the trusted networks where possible.</p>
</details>
<details class="warning">
<summary>Postfix has no concept of trusted proxies</summary>
<p>Postfix does not appear to have a way to configure trusted proxies like Dovecot does (<code>haproxy_trusted_networks</code>).</p>
<p><a href="https://www.postfix.org/postconf.5.html#postscreen_access_list"><code>postscreen_access_list</code></a> (<em>or <a href="https://www.postfix.org/postconf.5.html#smtpd_client_restrictions"><code>smtpd_client_restrictions</code></a> with <a href="https://www.postfix.org/postconf.5.html#check_client_access"><code>check_client_access</code></a> for ports 587/465</em>) can both restrict access by IP via a <a href="https://www.postfix.org/cidr_table.5.html">CIDR lookup table</a>, however the client IP is already rewritten at this point via PROXY protocol.</p>
<p>Thus those settings cannot be used for restricting access to only trusted proxies, only to the actual clients.</p>
<p>A similar setting <a href="https://www.postfix.org/postconf.5.html#mynetworks"><code>mynetworks</code></a> / <a href="../../../config/environment/#permit_docker"><code>PERMIT_DOCKER</code></a> manages elevated trust for bypassing security restrictions. While it is intended for trusted clients, it has no relevance to trusting proxies for the same reasons.</p>
</details>
<h3 id="monitoring"><a class="toclink" href="#monitoring">Monitoring</a></h3>
<p>While PROXY protocol works well with the reverse proxy, you may have some containers internally that interact with DMS on behalf of multiple clients.</p>
<details class="example">
<summary>Roundcube + Fail2Ban</summary>
<p>You may have other services with functionality like an API to send mail through DMS that likewise delegates credentials through DMS.</p>
<p>Roundcube is an example of this where authentication is delegated to DMS, which introduces the same concern with loss of client IP.</p>
<ul>
<li>While this service does implement some support for preserving the client IP, it is limited.</li>
<li>This may be problematic when monitoring services like Fail2Ban are enabled that scan logs for multiple failed authentication attempts which triggers a ban on the shared IP address.</li>
</ul>
<p>You should adjust configuration of these monitoring services to monitor for auth failures from those services directly instead, adding an exclusion for that service IP from any DMS logs monitored (<em>but be mindful of PROXY header forgery risks</em>).</p>
</details>
</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>