Documentation Restructure
This commit is contained in:
273
services/email/iredmail/deploy-iredmail.md
Normal file
273
services/email/iredmail/deploy-iredmail.md
Normal file
@@ -0,0 +1,273 @@
|
||||
**Purpose**:
|
||||
Self-Hosted Open-Source email server that can be setup in minutes, and is enterprise-grade if upgraded with an iRedAdmin-Pro license.
|
||||
|
||||
!!! note "Assumptions"
|
||||
It is assumed you are running at least Rocky Linux 9.3. While you can use CentOS Stream, Alma, Debian, Ubuntu, FreeBSD, and OpenBSD, the more enterprise-level sections of my homelab are built on Rocky Linux.
|
||||
|
||||
!!! warning "iRedMail / iRedAdmin-Pro Version Mismatching"
|
||||
This document assumes you are deploying iRedMail 1.6.8, which at the time of writing, coincided with iRedAdmin-Pro 5.5. If you are not careful, you may end up with mismatched versions down the road as iRedMail keeps getting updates. Due to how you have to pay for a license in order to get access to the original iRedAdmin-Pro-SQL repository data, if a newer version of iRedAdmin-Pro comes out after February 2025, this document may not account for that, leaving you on an older version of the software. This is unavoidable if you want to avoid paying $500/year for licensing this software.
|
||||
|
||||
## Overview
|
||||
The instructions below are specific to my homelab environment, but can be easily ported depending on your needs. This guide also assumes you want to operate a PostgreSQL-based iRedMail installation. You can follow along with the official documentation on [Installation](https://docs.iredmail.org/install.iredmail.on.rhel.html) as well as [DNS Record Configuration](https://docs.iredmail.org/setup.dns.html) if you want more detailed explanations throughout the installation process.
|
||||
|
||||
## Configure FQDN
|
||||
Ensure the FQDN of the server is correctly set in `/etc/hostname`. The `/etc/hosts` file will be automatically injected using the FQDN from `/etc/hostname` in a script further down, don't worry about editing it.
|
||||
|
||||
## Disable SELinux
|
||||
iRedMail doesn't work with SELinux, so please disable it by setting below value in its config file /etc/selinux/config. After server reboot, SELinux will be completely disabled.
|
||||
``` sh
|
||||
# Elevate to Root User
|
||||
sudo su
|
||||
|
||||
# Disable SELinux
|
||||
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config # (1)
|
||||
setenforce 0
|
||||
```
|
||||
|
||||
1. If you prefer to let SELinux prints warnings instead of enforcing, you can set this value instead: `SELINUX=permissive`
|
||||
|
||||
## iRedMail Installation
|
||||
|
||||
### Set Domain and iRedMail Version
|
||||
Start by connecting to the server / VM via SSH, then set silent deployment variables below.
|
||||
``` sh
|
||||
# Define some deployment variables.
|
||||
VERSION="1.6.8" # (1)
|
||||
MAIL_DOMAIN="bunny-lab.io" # (2)
|
||||
```
|
||||
|
||||
1. This is the version of iRedMail you are deploying. You can find the newest version on the [iRedMail Download Page](https://www.iredmail.org/download.html).
|
||||
2. This is the domain suffix that appears after mailbox names. e.g. `first.last@bunny-lab.io` would use a domain value of `bunny-lab.io`.
|
||||
|
||||
You will then proceed to bootstrap a silent unattended installation of iRedMail. (I've automated as much as I can to make this as turn-key as possible). Just copy/paste this whole thing into your terminal and hit ENTER.
|
||||
|
||||
!!! danger "Storage Space Requirements"
|
||||
You absolutely need to ensure that `/var/vmail` has a lot of space. At least 16GB. This is where all of your emails / mailboxes / a lot of settings will be. If possible, create a second physical/virtual disk specifically for the `/var` partition, or specifically for `/var/vmail` at minimum, so you can expand it over time if necessary. LVM-based provisioning is recommended but not required.
|
||||
|
||||
### Install iRedMail
|
||||
``` sh
|
||||
# Automatically configure the /etc/hosts file to point to the server listed in "/etc/hostname".
|
||||
sudo sed -i "1i 127.0.0.1 $(cat /etc/hostname) $(cut -d '.' -f 1 /etc/hostname) localhost localhost.localdomain localhost4 localhost4.localdomain4" /etc/hosts
|
||||
|
||||
# Check for Updates in the Package Manager
|
||||
yum update -y
|
||||
|
||||
# Install Extra Packages for Enterprise Linux
|
||||
dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
|
||||
|
||||
# Download the iRedMail binaries and extract them
|
||||
cd /root
|
||||
curl https://codeload.github.com/iredmail/iRedMail/tar.gz/refs/tags/$VERSION -o iRedMail-$VERSION.tar.gz
|
||||
tar zxf iRedMail-$VERSION.tar.gz
|
||||
|
||||
# Create the unattend config file for silent deployment. This will automatically generate random 32-character passwords for all of the databases.
|
||||
(echo "export STORAGE_BASE_DIR='/var/vmail'"; echo "export WEB_SERVER='NGINX'"; echo "export BACKEND_ORIG='PGSQL'"; echo "export BACKEND='PGSQL'"; for var in VMAIL_DB_BIND_PASSWD VMAIL_DB_ADMIN_PASSWD MLMMJADMIN_API_AUTH_TOKEN NETDATA_DB_PASSWD AMAVISD_DB_PASSWD IREDADMIN_DB_PASSWD RCM_DB_PASSWD SOGO_DB_PASSWD SOGO_SIEVE_MASTER_PASSWD IREDAPD_DB_PASSWD FAIL2BAN_DB_PASSWD PGSQL_ROOT_PASSWD DOMAIN_ADMIN_PASSWD_PLAIN; do echo "export $var='$(openssl rand -base64 48 | tr -d '+/=' | head -c 32)'"; done; echo "export FIRST_DOMAIN='$MAIL_DOMAIN'"; echo "export USE_IREDADMIN='YES'"; echo "export USE_SOGO='YES'"; echo "export USE_NETDATA='YES'"; echo "export USE_FAIL2BAN='YES'"; echo "#EOF") > /root/iRedMail-$VERSION/config
|
||||
|
||||
# Make Config Read-Only
|
||||
chmod 400 /root/iRedMail-$VERSION/config
|
||||
|
||||
# Set Environment Variables for Silent Deployment
|
||||
cd /root/iRedMail-$VERSION
|
||||
|
||||
# Deploy iRedMail via the Install Script
|
||||
AUTO_USE_EXISTING_CONFIG_FILE=y \
|
||||
AUTO_INSTALL_WITHOUT_CONFIRM=y \
|
||||
AUTO_CLEANUP_REMOVE_SENDMAIL=y \
|
||||
AUTO_CLEANUP_REPLACE_FIREWALL_RULES=y \
|
||||
AUTO_CLEANUP_RESTART_FIREWALL=n \
|
||||
AUTO_CLEANUP_REPLACE_MYSQL_CONFIG=y \
|
||||
bash iRedMail.sh
|
||||
```
|
||||
|
||||
When the installation is completed, take note of any output it gives you for future reference. Then reboot the server to finalize the server installation.
|
||||
```
|
||||
reboot
|
||||
```
|
||||
|
||||
!!! warning "Automatically-Generated Postmaster Password"
|
||||
When you deploy iRedMail, it will give you a username and password for the postmaster account. If you accidentally forget to document this, you can log back into the server via SSH and see the credentials at `/root/iRedMail-$VERSION/iRedMail.tips`. This file is critical and contains passwords and DNS information such as DKIM record information as well.
|
||||
|
||||
## Networking Configuration
|
||||
|
||||
### Nested Reverse Proxy Configuration
|
||||
In my homelab environment, I run Traefik reverse proxy in front of everything, which includes the NGINX reverse proxy that iRedMail creates. In my scenario, I have to make some custom adjustments to the reverse proxy dynamic configuration data to ensure it will step aside and let the NGINX reverse proxy inside of iRedMail handle everything, including handling its own SSL termination with Let's Encrypt.
|
||||
|
||||
``` sh
|
||||
tcp:
|
||||
routers:
|
||||
mail-tcp-router:
|
||||
rule: "HostSNI(`mail.bunny-lab.io`)"
|
||||
entryPoints: ["websecure"]
|
||||
service: mail-nginx-service
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
services:
|
||||
mail-nginx-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.13:443"
|
||||
```
|
||||
|
||||
### Let's Encrypt ACME Certbot
|
||||
At this point, we want to set up automatic Let's Encrypt SSL termination inside of iRedMail so we don't have to manually touch this in the future.
|
||||
|
||||
#### Generate SSL Certificate
|
||||
=== "Debian/Ubuntu"
|
||||
|
||||
``` sh
|
||||
# Download the Certbot
|
||||
sudo apt update
|
||||
sudo apt install -y certbot
|
||||
sudo certbot certonly --webroot -w /var/www/html -d mail.bunny-lab.io
|
||||
|
||||
# Set up Symbolic Links (Where iRedMail Expects Them)
|
||||
sudo mv /etc/ssl/certs/iRedMail.crt{,.bak}
|
||||
sudo mv /etc/ssl/private/iRedMail.key{,.bak}
|
||||
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/fullchain.pem /etc/ssl/certs/iRedMail.crt
|
||||
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/privkey.pem /etc/ssl/private/iRedMail.key
|
||||
|
||||
# Restart iRedMail Services
|
||||
sudo systemctl restart postfix dovecot nginx
|
||||
```
|
||||
|
||||
=== "CentOS/Rocky/AlmaLinux"
|
||||
|
||||
``` sh
|
||||
# Download the Certbot
|
||||
sudo yum install -y epel-release
|
||||
sudo yum install -y certbot
|
||||
sudo certbot certonly --webroot -w /var/www/html -d mail.bunny-lab.io
|
||||
|
||||
# Set up Symbolic Links (Where iRedMail Expects Them)
|
||||
sudo mv /etc/pki/tls/certs/iRedMail.crt{,.bak}
|
||||
sudo mv /etc/pki/tls/private/iRedMail.key{,.bak}
|
||||
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/fullchain.pem /etc/pki/tls/certs/iRedMail.crt
|
||||
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/privkey.pem /etc/pki/tls/private/iRedMail.key
|
||||
|
||||
# Restart iRedMail Services
|
||||
sudo systemctl restart postfix dovecot nginx
|
||||
```
|
||||
|
||||
#### Configure Automatic Renewal
|
||||
To automate the renewal process, set up a cron job that runs the certbot renew command regularly. This command will renew certificates that are due to expire within 30 days.
|
||||
|
||||
Open the crontab editor with the following command:
|
||||
```
|
||||
sudo crontab -e
|
||||
```
|
||||
|
||||
Add the following line to run the renewal process daily at 3:01 AM:
|
||||
```
|
||||
1 3 * * * certbot renew --post-hook 'systemctl restart postfix dovecot nginx'
|
||||
```
|
||||
|
||||
### DNS Records
|
||||
Now you need to set up DNS records in Cloudflare (or the DNS Registrar you have configured) so that the mail server can be found and validated.
|
||||
|
||||
| **Type** | **Name** | **Content** | **Proxy Status** | **TTL** |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| MX | bunny-lab.io | mail.bunny-lab.io | DNS Only | Auto |
|
||||
| TXT | bunny-lab.io | "v=spf1 a:mail.bunny-lab.io ~all" | DNS Only | Auto |
|
||||
| TXT | dkim._domainkey | v=DKIM1; p=`IREDMAIL-DKIM-VALUE` | DNS Only | 1 Hour |
|
||||
| TXT | _dmarc | "v=DMARC1; p=reject; pct=100; rua=mailto:postmaster@bunny-lab.io; ruf=mailto:postmaster@bunny-lab.io" | DNS Only | Auto |
|
||||
|
||||
### Port Forwarding
|
||||
Lastly, we need to set up port forwarding to open the ports necessary for the server to send and receive email.
|
||||
|
||||
| **Protocol** | **Port** | **Destination Server** | **Description** |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| TCP | 995 | 192.168.3.13 | POP3 service: port 110 over STARTTLS |
|
||||
| TCP | 993 | 192.168.3.13 | IMAP service: port 143 over STARTTLS |
|
||||
| TCP | 587 | 192.168.3.13 | SMTP service: port 587 over STARTTLS |
|
||||
| TCP | 25 | 192.168.3.13 | SMTP (Email Server-to-Server Communication) |
|
||||
|
||||
## Install iRedAdmin-Pro
|
||||
When it comes to adding extra features, start by copying the data from this [Bunny Lab repository](https://git.bunny-lab.io/bunny-lab/iRedAdmin-Pro-SQL) to the following folder by running these commands first:
|
||||
|
||||
``` sh
|
||||
# Stop the iRedMail Services
|
||||
sudo systemctl stop postfix dovecot nginx
|
||||
|
||||
# Grant Temporary Access to the iRedAdmin Files and Folders
|
||||
sudo chown nicole:nicole -R /opt/www/iRedAdmin-2.5
|
||||
|
||||
# Copy the data from the repository mentioned above into this folder, merging identical folders and files. Feel free to use your preferred file transfer tool tool / method (e.g. MobaXTerm / WinSCP).
|
||||
|
||||
# Change permissions back to normal
|
||||
sudo chown iredadmin:iredadmin -R /opt/www/iRedAdmin-2.5
|
||||
|
||||
# Reboot the Server
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### Activate iRedAdmin-Pro
|
||||
At this point, if you want to use iRedAdmin-Pro, you either have a valid license key, or you adjust the python function responsible for checking license keys to bypass the check, effectively forcing iRedAdmin to be activated. In this instance, we will be forcing activation by adjusting this function, seen below.
|
||||
|
||||
There is someone else who outlined all of these changes, and additional (aesthetic) ones, like removing the renew license button from the license page, but the core functionality is seen below. If you want to see the original repository this was inspired from, it can be found [Here](https://github.com/marcus-alicia/iRedAdmin-Pro-SQL)
|
||||
|
||||
``` sh
|
||||
# Take permission of the python script
|
||||
sudo chown nicole:nicole /opt/www/iRedAdmin-2.5/libs/sysinfo.py
|
||||
```
|
||||
|
||||
=== "Original Activation Function"
|
||||
|
||||
```jsx title="/opt/www/iRedAdmin-2.5/libs/sysinfo.py"
|
||||
def get_license_info():
|
||||
if len(__id__) != 32:
|
||||
web.conn_iredadmin.delete("updatelog")
|
||||
session.kill()
|
||||
raise web.seeother("/login?msg=INVALID_PRODUCT_ID")
|
||||
|
||||
params = {
|
||||
"v": __version__,
|
||||
"f": __id__,
|
||||
"lang": settings.default_language,
|
||||
"host": get_hostname(),
|
||||
"backend": settings.backend,
|
||||
"webmaster": settings.webmaster,
|
||||
"mac": ",".join(get_all_mac_addresses()),
|
||||
}
|
||||
|
||||
url = "https://lic.iredmail.org/check_version/licenseinfo/" + __id__ + ".json"
|
||||
url += "?" + urllib.parse.urlencode(params)
|
||||
|
||||
try:
|
||||
urlopen = __get_proxied_urlopen()
|
||||
_json = urlopen(url).read()
|
||||
lic_info = json.loads(_json)
|
||||
lic_info["id"] = __id__
|
||||
return True, lic_info
|
||||
except Exception as e:
|
||||
return False, web.urlquote(e)
|
||||
```
|
||||
|
||||
=== "Bypassed Activation Function"
|
||||
|
||||
```jsx title="/opt/www/iRedAdmin-2.5/libs/sysinfo.py"
|
||||
def get_license_info():
|
||||
return True, {
|
||||
"status": "active",
|
||||
"product": "iRedAdmin-Pro-SQL",
|
||||
"licensekey": "forcefully-open-source",
|
||||
"upgradetutorials": "https://docs.iredmail.org/iredadmin-pro.releases.html",
|
||||
"purchased": "Never",
|
||||
"contacts": "nicole.rappe@bunny-lab.io",
|
||||
"latestversion": "5.5",
|
||||
"expired": "Never",
|
||||
"releasenotes": "https://docs.iredmail.org/iredadmin-pro.releases.html",
|
||||
"id": __id__
|
||||
}
|
||||
```
|
||||
|
||||
``` sh
|
||||
# Revert permission of the python script
|
||||
sudo chown iredadmin:iredadmin /opt/www/iRedAdmin-2.5/libs/sysinfo.py
|
||||
|
||||
# Reboot the Server (To be safe)
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
!!! success "Successful Activation"
|
||||
At this point, if you navigate to the [iRedAdmin-Pro License Page](https://mail.bunny-lab.io/iredadmin/system/license) you should see the server is activated successfully.
|
||||
35
services/email/iredmail/query-smtp-outgoing-queue.md
Normal file
35
services/email/iredmail/query-smtp-outgoing-queue.md
Normal file
@@ -0,0 +1,35 @@
|
||||
## Purpose
|
||||
You may need to troubleshoot the outgoing SMTP email queue / active sessions in iRedMail for one reason or another. This can provide useful insight into the reason why emails are not being delivered, etc.
|
||||
|
||||
### Overall Queue Backlog
|
||||
You can run the following command to get the complete backlog of all email senders in the queue. This can be useful for tracking the queue's "drainage" over-time.
|
||||
|
||||
```sh
|
||||
# List the total number of queued messages
|
||||
postqueue -p | egrep -c '^[A-F0-9]'
|
||||
|
||||
# Itemize and count the queued messages based on sender.
|
||||
postqueue -p | awk '/^[A-F0-9]/ {id=$1} /from=<[^>]+>/ && $0 !~ /from=<>/ {print id; exit}'
|
||||
```
|
||||
|
||||
!!! example "Example Output"
|
||||
- 10392 problematic@bunny-lab.io
|
||||
- 301 prettybad@bunny-lab.io
|
||||
- 39 infrastructure@bunny-lab.io
|
||||
- 20 nicole.rappe@bunny-lab.io
|
||||
|
||||
### Investigating Individual Emails
|
||||
You can run the following command to list all queued messages: `postqueue -p`. You can then run `postcat -vq <message-ID>` to read detailed information on any specific queued SMTP message:
|
||||
|
||||
```sh
|
||||
postqueue -p
|
||||
postcat -vq 4dgHry5LZnzH6x08 # (1)
|
||||
```
|
||||
|
||||
1. Example message ID gathered from the previous `postqueue -p` command.
|
||||
|
||||
### Attempt to Gracefully Reload Postfix
|
||||
You may want to try to unstick things by gracefully "reloading" the postfix service via `postfix reload`. This will ensure that we don't drop / disconnect / lose all of the active outgoing SMTP sessions in the queue. It may not help resolve issues, but it's worth noting down:
|
||||
|
||||
### Reattempt Delivery
|
||||
You can attempt redelivery via running `postqueue -f` to try to free up the queue. Postfix will immediately re-attempt delivery of all queued messages instead of waiting for their scheduled retry time. It does not override remote rejections or fix underlying delivery errors; it only accelerates the next delivery attempt.
|
||||
3
services/email/iredmail/quick-server-settings.md
Normal file
3
services/email/iredmail/quick-server-settings.md
Normal file
@@ -0,0 +1,3 @@
|
||||
| Server | Port(s) | Security | Auth Method | Username |
|
||||
|:------------------|:----------------------------------------------|:----------|:----------------|:-------------------|
|
||||
| `mail.bunny-lab.io` | **IMAP:** 143 `Internal`, 993 `External`<br>**SMTP:** 587, 25 `Fallback` | STARTTLS | Normal Password | user@bunny-lab.io |
|
||||
231
services/email/mailcow.md
Normal file
231
services/email/mailcow.md
Normal file
@@ -0,0 +1,231 @@
|
||||
!!! warning "Under Construction"
|
||||
The deployment of Mailcow is mostly correct here, but with the exception that we dont point DNS records to the reverse proxy (internally) because it's currently not functioning as expected. So for the time being, you would open all of the ports up to the Mailcow server's internal IP address via port forwarding on your firewall.
|
||||
|
||||
## Purpose
|
||||
The purpose of this document is to illustrate how to deploy Mailcow in a dockerized format.
|
||||
|
||||
!!! note "Assumptions"
|
||||
It is assumed that you are deploying Mailcow into an existing Ubuntu Server environment. If you are using a different operating system, refer to the [official documentation](https://docs.mailcow.email/getstarted/install/).
|
||||
|
||||
### Setting Up Docker
|
||||
Go ahead and set up docker and docker-compose with the following commands:
|
||||
```bash
|
||||
sudo su # (1)
|
||||
curl -sSL https://get.docker.com/ | CHANNEL=stable sh # (2)
|
||||
apt install docker-compose-plugin # (3)
|
||||
systemctl enable --now docker # (4)
|
||||
```
|
||||
|
||||
1. Make yourself root.
|
||||
2. Install `Docker`
|
||||
3. Install `Docker-Compose`
|
||||
4. Make docker run automatically when the server is booted.
|
||||
|
||||
### Download and Deploy Mailcow
|
||||
Run the following commands to pull down the mailcow deployment files and install them with docker. Go get a cup of coffee as the `docker compose pull` command may take a while to run.
|
||||
|
||||
!!! note "Potential `Docker Compose` Issues"
|
||||
If you run the `docker-compose pull` command and it fails for some reason, change the command to `docker compose pull` instead. This is just the difference between the plugin version of compose versus the standalone version. Both will have the same result.
|
||||
|
||||
```bash
|
||||
cd /opt
|
||||
git clone https://github.com/mailcow/mailcow-dockerized
|
||||
cd mailcow-dockerized
|
||||
./generate_config.sh # (1)
|
||||
docker-compose pull # (2)
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
1. Generate a configuration file. Use a FQDN (`host.domain.tld`) as hostname when asked.
|
||||
2. If you get an error about the ports of the `nginx-mailcow` service in the `docker-compose.yml` stack, change the ports for that service as follows:
|
||||
```yaml
|
||||
ports:
|
||||
- "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}"
|
||||
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
|
||||
```
|
||||
|
||||
### Reverse-Proxy Configuration
|
||||
For the purposes of this document, it will be assumed that you are deploying Mailcow behind Traefik. You can use the following dynamic configuration file to achieve this:
|
||||
```yaml title="/srv/containers/traefik/config/dynamic/mail.bunny-lab.io.yml"
|
||||
# ========================
|
||||
# Mailcow / Traefik Config
|
||||
# ========================
|
||||
|
||||
# ----------------------------------------------------
|
||||
# HTTP Section - Handles Mailcow web UI via Traefik
|
||||
# ----------------------------------------------------
|
||||
http:
|
||||
routers:
|
||||
mailcow-server:
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: mailcow-http
|
||||
rule: Host(`mail.bunny-lab.io`)
|
||||
services:
|
||||
mailcow-http:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://192.168.3.61:80
|
||||
passHostHeader: true
|
||||
|
||||
# ----------------------------------------------------
|
||||
# TCP Section - Handles all mail protocols
|
||||
# ----------------------------------------------------
|
||||
tcp:
|
||||
routers:
|
||||
# -----------
|
||||
# SMTP Router (Port 25, non-TLS, all mail deliveries)
|
||||
# -----------
|
||||
mailcow-smtp:
|
||||
entryPoints:
|
||||
- smtp
|
||||
rule: "" # Empty rule = accept ALL connections on port 25 (plain SMTP)
|
||||
service: mailcow-smtp
|
||||
|
||||
# -----------
|
||||
# SMTPS Router (Port 465, implicit TLS)
|
||||
# -----------
|
||||
mailcow-smtps:
|
||||
entryPoints:
|
||||
- smtps
|
||||
rule: "HostSNI(`*`)" # Match any SNI (required for TLS)
|
||||
service: mailcow-smtps
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
# -----------
|
||||
# Submission Router (Port 587, implicit TLS or STARTTLS)
|
||||
# -----------
|
||||
mailcow-submission:
|
||||
entryPoints:
|
||||
- submission
|
||||
rule: "HostSNI(`*`)" # Match any SNI (required for TLS)
|
||||
service: mailcow-submission
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
# -----------
|
||||
# IMAPS Router (Port 993, implicit TLS)
|
||||
# -----------
|
||||
mailcow-imaps:
|
||||
entryPoints:
|
||||
- imaps
|
||||
rule: "HostSNI(`*`)" # Match any SNI (required for TLS)
|
||||
service: mailcow-imaps
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
# -----------
|
||||
# IMAP Router (Port 143, can be STARTTLS)
|
||||
# -----------
|
||||
mailcow-imap:
|
||||
entryPoints:
|
||||
- imap
|
||||
rule: "HostSNI(`*`)" # Match any SNI (for TLS connections)
|
||||
service: mailcow-imap
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
# -----------
|
||||
# POP3S Router (Port 995, implicit TLS)
|
||||
# -----------
|
||||
mailcow-pop3s:
|
||||
entryPoints:
|
||||
- pop3s
|
||||
rule: "HostSNI(`*`)" # Match any SNI (required for TLS)
|
||||
service: mailcow-pop3s
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
# -----------
|
||||
# Dovecot Managesieve (Port 4190, implicit TLS)
|
||||
# -----------
|
||||
mailcow-dovecot-managesieve:
|
||||
entryPoints:
|
||||
- pop3s
|
||||
rule: "HostSNI(`*`)" # Match any SNI (required for TLS)
|
||||
service: dovecot-managesieve
|
||||
tls:
|
||||
passthrough: true
|
||||
|
||||
services:
|
||||
# SMTP (Port 25, plain)
|
||||
mailcow-smtp:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:25"
|
||||
|
||||
# SMTPS (Port 465, implicit TLS)
|
||||
mailcow-smtps:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:465"
|
||||
|
||||
# Submission (Port 587, implicit TLS or STARTTLS)
|
||||
mailcow-submission:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:587"
|
||||
|
||||
# IMAPS (Port 993, implicit TLS)
|
||||
mailcow-imaps:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:993"
|
||||
|
||||
# IMAP (Port 143, plain/STARTTLS)
|
||||
mailcow-imap:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:143"
|
||||
|
||||
# POP3S (Port 995, implicit TLS)
|
||||
mailcow-pop3s:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:995"
|
||||
|
||||
# Dovecot Managesieve (Port 4190, implicit TLS)
|
||||
dovecot-managesieve:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "192.168.3.61:4190"
|
||||
```
|
||||
|
||||
### Traefik-Specific Configuration
|
||||
You will need to add some extra entrypoints and ports to Traefik itself so it can listen for this new traffic.
|
||||
```yaml
|
||||
#Entrypoints
|
||||
- "--entrypoints.smtp.address=:25"
|
||||
- "--entrypoints.smtps.address=:465"
|
||||
- "--entrypoints.submission.address=:587"
|
||||
- "--entrypoints.imap.address=:143"
|
||||
- "--entrypoints.imaps.address=:993"
|
||||
- "--entrypoints.pop3.address=:110"
|
||||
- "--entrypoints.pop3s.address=:995"
|
||||
- "--entrypoints.dovecot-managesieve.address=:4190"
|
||||
|
||||
#Ports
|
||||
- "25:25"
|
||||
- "110:110"
|
||||
- "143:143"
|
||||
- "465:465"
|
||||
- "587:587"
|
||||
- "993:993"
|
||||
- "995:995"
|
||||
- "4190:4190"
|
||||
```
|
||||
|
||||
### Login to Mailcow
|
||||
At this point, the Mailcow server has been deployed so you can log into it.
|
||||
|
||||
- **Administrators**: `https://${MAILCOW_HOSTNAME}/admin` (Username: `admin` | Password: `moohoo`)
|
||||
- **Regular Mailbox Users**: `https://${MAILCOW_HOSTNAME}` (*FQDN only*)
|
||||
|
||||
### Mail-Client Considerations
|
||||
You need to ensure that you generate an app password if you have MFA enabled within Mailcow. (MFA is non-functional in Roundcube/SoGo, you set it up via Mailcow itself). You can access it via the Mailcow configuration page: https://mail.bunny-lab.io/user, then look for the "**App Passwords**" tab.
|
||||
|
||||
### Running Updates
|
||||
If you want to run updates, just SSH into the server, and navigate to `/opt/mailcow-dockerized` and run `./update.sh`. I recommend avoiding the IPv6 implementation section. Be patient, and the upgrade will be fully-automated.
|
||||
@@ -0,0 +1,71 @@
|
||||
**Purpose**: If you want to set up automatic Let's Encrypt SSL certificates on a Microsoft Exchange server, you have to go through a few steps to install the WinACME bot, and configure it to automatically renew certificates.
|
||||
|
||||
!!! note "ACME Bot Provisioning Considerations"
|
||||
This document assumes you want a fully-automated one-liner command for configuring the ACME Bot, it is also completely valid to go step-by-step through the bot to configure the SSL certificate, the IIS server, etc, and it will automatically create a Scheduled Task to renew on its own. The whole process is very straight-forward with most answers being the default option.
|
||||
|
||||
### Download the Win-ACME Bot:
|
||||
|
||||
* Log into the on-premise Exchange Server via Datto RMM
|
||||
* Navigate to: [https://www.win-acme.com/](https://www.win-acme.com/)
|
||||
* On the top-right of the website, you will see a "**Download**" button with the most recent version of the Win-ACME bot
|
||||
* Extract the contents of the ZIP file to "**C:\\Program Files (x86)\\Lets Encrypt**"
|
||||
* Make the "**Lets Encrypt**" folder if it does not already exist
|
||||
|
||||
### Configure `settings_default.json`:
|
||||
|
||||
* The next step involves us making a modification to the configuration of the Win-ACME bot that allows us to export the necessary private key data for Exchange
|
||||
* Using a text editor, open the "**settings\_default.json**" file
|
||||
* Look for the setting called "**PrivateKeyExportable**" and change the value from "**false**" to "**true**"
|
||||
* Save and close the file
|
||||
|
||||
### Download and Install the SSL Certificate:
|
||||
|
||||
* Open an administrative Command Line (DO NOT USE POWERSHELL)
|
||||
* Navigate to the Let's Encrypt bot directory: `CD "C:\Program Files (x86)\Lets Encrypt"`
|
||||
* Invoke the bot to automatically download and install the certificate into the IIS Server that Exchange uses to host the Exchange Server
|
||||
* Be sure to change the placeholder subdomains to match the domain of the actual Exchange Server
|
||||
* (e.g. "**mail.example.org**" | "**autodiscover.example.org**")
|
||||
```
|
||||
wacs.exe --target manual --host mail.example.org,autodiscover.example.org --certificatestore My --acl-fullcontrol "network service,administrators" --installation iis,script --installationsiteid 1 --script "./Scripts/ImportExchange.ps1" --scriptparameters "'{CertThumbprint}' 'IIS,SMTP,IMAP' 1 '{CacheFile}' '{CachePassword}' '{CertFriendlyName}'" --verbose
|
||||
```
|
||||
|
||||
* When the command is running, it will ask for an email address for alerts and abuse notifications, just put "**infrastructure@bunny-lab.io**"
|
||||
* If you run into any unexpected errors that result in anything other than exiting with a status "0", consult with Nicole Rappe to proceed
|
||||
* Check that the domain of the Exchange Server is reachable on port 80 as Let's Encrypt uses this to build the cert.
|
||||
* Searching the external IP of the server on [Shodan](https://www.shodan.io/) will reveal all open ports.
|
||||
|
||||
### Troubleshooting:
|
||||
If you find that any of the services such as [https://mail.example.org/ecp](https://mail.example.org/ecp), [https://autodiscover.example.org](https://autodiscover.example.org), or [https://mail.example.org/owa](https://mail.example.org/owa) do not let you log in, proceed with the steps below to correct the "Certificate Binding" in IIS Manager:
|
||||
|
||||
* Open "**Server Manager**" > Tools > "**Internet Information Services (IIS) Manager**"
|
||||
* Expand the "**Connections**" server tree on the left-hand side of the IIS Manager
|
||||
* Expand the "**Sites**" folder
|
||||
* Click on "**Default Web Site**"
|
||||
* On the right-hand Actions menu, click on "**Bindings...**"
|
||||
* A table will appear with different endpoints on the Exchange server > What you are looking for is an entry that looks like the following:
|
||||
* **Type**: https
|
||||
* **Host Name**: autodiscover.example.org
|
||||
* **Port**: 443
|
||||
* Double-click on the row, or click one then click the "**Edit**" button to open the settings for that endpoint
|
||||
* Under "**SSL Certificate**" > Make sure the certificate name matches the following format: "**\[Manual\] autodiscover.example.org @ YYYY/MM/DD**"
|
||||
* If it does not match the above, use the dropdown menu to correct it and click the "**OK**" button
|
||||
* **Type**: https
|
||||
* **Host Name**: mail.example.org
|
||||
* **Port**: 443
|
||||
* Repeat the steps seen above, except this time for "**mail.example.org**"
|
||||
* Click on "**Exchange Back End**"
|
||||
* On the right-hand Actions menu, click on "**Bindings...**"
|
||||
* A table will appear with different endpoints on the Exchange server > What you are looking for is an entry that looks like the following:
|
||||
* **Type**: https
|
||||
* **Host Name**: <blank>
|
||||
* **Port**: 444
|
||||
* Repeat the steps seen above, ensuring that the "**\[Manual\] autodiscover.example.org @ YYYY/MM/DD**" certificate is selected and applied
|
||||
* Click the "**OK**" button
|
||||
* On the left-hand menu under "**Connections**" in IIS Manager, click on the server name itself
|
||||
* (e.g. "**EXAMPLE-EXCHANGE (DOMAIN\\dptadmin**")
|
||||
* On the right-hand "**Actions**" menu > Under "Manage Server" > Select "Restart"
|
||||
* Wait for the IIS server to restart itself, then try accessing the webpages for Exchange that were exhibiting issues logging in
|
||||
|
||||
### Additional Documentation:
|
||||
|
||||
* [https://www.alitajran.com/install-free-lets-encrypt-certificate-in-exchange-server/](https://www.alitajran.com/install-free-lets-encrypt-certificate-in-exchange-server/)
|
||||
@@ -0,0 +1,117 @@
|
||||
**Purpose**:
|
||||
This document is meant to be an abstract guide on what to do before installing Cumulative Updates on Microsoft Exchange Server. There are a few considerations that need to be made ahead of time. This list was put together through shere brute-force while troubleshooting an update issue for a server on 12/16/2024.
|
||||
|
||||
!!! abstract "Overview"
|
||||
We are looking to add an administrative user to several domain security groups, adjust local security policy to put them into the "Manage Auditing and Security Logs" security policy, and run the setup.exe included on the Cumulative Update ISO images within a `SeSecurityPrivilege` operational context.
|
||||
|
||||
## Domain Group Membership
|
||||
You have to be logged in with a domain user that possesses the following domain group memberships, if these group memberships are missing, the upgrade process will fail.
|
||||
|
||||
- `Enterprise Admins`
|
||||
- `Schema Admins`
|
||||
- `Organization Management`
|
||||
|
||||
## User Rights Management
|
||||
You have to be part of the "**Local Policies > User Rights Assignment > "Manage Auditing and Security Logs**" security policy. You can set this via group policy management or locally on the Exchange server via `secpol.msc`. This is required for the "Monitoring Tools" portion of the upgrade.
|
||||
|
||||
It's recommended to reboot the server after making this change to be triple-sure that everything was applied correctly.
|
||||
|
||||
!!! note "Security Policy Only Required on Exchange Server"
|
||||
While the `Enterprise Admins`, `Schema Admins`, and `Organization Management` security group memberships are required on a domain-wide level, the security policy membership for "Manage Auditing and Security Logs" mentioned above is only required on the Exchange Server itself. You can create a group policy that only targets the Exchange Server to add this, or you can make your user a domain-wide member of "Manage Auditing and Security Logs" (Optional). If no existing policies are in-place affecting the Exchange server, you can just use `secpol.msc` to manually add your user to this security policy for the duration of the upgrade/update (or leave it there for future updates).
|
||||
|
||||
## Running Updater within `SeSecurityPrivilege` Operational Context
|
||||
At this point, you would technically be ready to invoke `setup.exe` on the Cumulative Update ISO image to launch the upgrade process, but we are going to go the extra mile to manually "Enable" the `SeSecurityPrivilege` within a Powershell session, then use that same session to invoke the `setup.exe` so the updater runs within that context. This is not really necessary, but something I added as a "hail mary" to make the upgrade successful.
|
||||
|
||||
### Open Powershell ISE
|
||||
The first thing we are going to do, is open the Powershell ISE so we can copy/paste the following powershell script, this script will explicitely enable `SeSecurityPrivilege` for anyone who holds that privilege within the powershell session.
|
||||
|
||||
!!! warning "Run Powershell ISE as Administrator"
|
||||
In order for everything to work correctly, the ISE has to be launched by right-clicking "Run as Administrator", otherwise it is guarenteed that the updater application will fail at some point.
|
||||
|
||||
```powershell title="SeSecurityPrivilege Enablement Script"
|
||||
# Create a Privilege Adjustment
|
||||
$definition = @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class Privilege
|
||||
{
|
||||
const int SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
|
||||
const int TOKEN_QUERY = 0x0008;
|
||||
const string SE_SECURITY_NAME = "SeSecurityPrivilege";
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, out IntPtr TokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out long lpLuid);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct TOKEN_PRIVILEGES
|
||||
{
|
||||
public int PrivilegeCount;
|
||||
public long Luid;
|
||||
public int Attributes;
|
||||
}
|
||||
|
||||
public static bool EnablePrivilege()
|
||||
{
|
||||
IntPtr tokenHandle;
|
||||
TOKEN_PRIVILEGES tokenPrivileges;
|
||||
|
||||
if (!OpenProcessToken(System.Diagnostics.Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out tokenHandle))
|
||||
return false;
|
||||
|
||||
if (!LookupPrivilegeValue(null, SE_SECURITY_NAME, out tokenPrivileges.Luid))
|
||||
return false;
|
||||
|
||||
tokenPrivileges.PrivilegeCount = 1;
|
||||
tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
return AdjustTokenPrivileges(tokenHandle, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
Add-Type -TypeDefinition $definition
|
||||
[Privilege]::EnablePrivilege()
|
||||
```
|
||||
|
||||
### Validate Privilege
|
||||
At this point, we now have a powershell session operating with the `SeSecurityPrivilege` privilege enabled. We want to confirm this by running the following commands:
|
||||
|
||||
```powershell
|
||||
whoami # (1)
|
||||
whoami /priv # (2)
|
||||
```
|
||||
|
||||
1. Output will appear similar to "bunny-lab\nicole.rappe", prefixing the username of the person running the command with the domain they belong to.
|
||||
2. Reference the privilege table seen below to validate the output of this command matches what you see below.
|
||||
|
||||
| **Privilege Name** | **Description** | **State** |
|
||||
| :--- | :--- | :--- |
|
||||
| `SeSecurityPrivilege` | Manage auditing and security log | Enabled |
|
||||
|
||||
### Execute `setup.exe`
|
||||
Finally, at the last stage, we mount the ISO file for the Cumulative Update ISO (e.g. 6.6GB ISO image), and using this powershell session we made above, we navigate to the drive it is running on, and invoke setup.exe, causing it to run under the `SeSecurityPrivilege` operational state.
|
||||
|
||||
```powershell
|
||||
D: <ENTER> # (1)
|
||||
.\Setup.EXE /m:upgrade /IAcceptExchangeServersLicenseTerms_DiagnosticDataON # (2)
|
||||
```
|
||||
|
||||
1. Replace this drive letter with whatever letter was assigned when you mounted the ISO image for the Exchange Updater.
|
||||
2. This launches the Exchange updater application. Be patient and give it time to launch. At this point, you should be good to proceed with the update. You can optionally change the argument to `/IAcceptExchangeServersLicenseTerms_DiagnosticDataOFF` if you do not need diagnostic data.
|
||||
|
||||
!!! success "Ready to Proceed with Updating Exchange"
|
||||
At this point, after doing the three sections above, you should be safe to do the upgrade/update of Microsoft Exchange Server. The installer will run its own readiness checks for other aspects such as IIS Rewrite Modules and will give you a link to download / upgrade it separately, then giving you the option to "**Retry**" after installing the module for the installer to re-check and proceed.
|
||||
|
||||
## Post-Update Health Checks
|
||||
After the update(s) are installed, you will likely want to check to ensure things are healthy and operational, validating mail flow in both directions, running `Get-Queue` to check for backlogged emails, etc.
|
||||
|
||||
!!! note "Under Construction"
|
||||
This section is under construction and will be based on some feedback from others to help build the section out.
|
||||
@@ -0,0 +1,72 @@
|
||||
## Purpose
|
||||
If you operate an Exchange Database Availability Group (DAG) with 2 or more servers, you may need to do maintenance to one of the members, and during that maintenance, it's possible that one of the databases of the server that was rebooted etc will be out-of-date. In case this happens, it may suspend the database replication to one of the DAG's member servers.
|
||||
|
||||
## Checking DAG Database Replication Status
|
||||
You will want to first log into one of the DAG servers and open the *"Exchange Management Shell"*. From there, run the following command to get the status of database replication. An example of the kind of output you would see is below the command.
|
||||
|
||||
```powershell
|
||||
Get-MailboxDatabaseCopyStatus * | Format-Table Name, Status, CopyQueueLength, ReplayQueueLength, ContentIndexState
|
||||
```
|
||||
|
||||
| **Name** | **Status** | **CopyQueueLength** | **ReplayQueueLength** | **ContentIndexState** |
|
||||
| :--- | ---: | ---: | ---: | ---: |
|
||||
| DB01\MX-DAG-01 | Mounted | 0 | 0 | Healthy |
|
||||
| DB01\MX-DAG-02 | Healthy | 0 | 0 | Healthy |
|
||||
|
||||
!!! info "Example Output Breakdown"
|
||||
In the above example output, you can see that there are two member servers in the DAG, `MX-DAG-01` and `MX-DAG-02`. Then you will see that there is a status of `Mounted`, this means that `MX-DAG-01` is the active production server; this means that it is handling all mailflow and web requests / webmail.
|
||||
|
||||
**CopyQueueLength**: This is a number of database "*transaction logs*" that have taken place since a replica database stopped getting updates. This is the queue of all database transactions that are being copied from the production (mounted) database to replica databases. This data is not immediately written to the replica database(s).
|
||||
|
||||
**CopyReplayLength**: This represents the queue of all data that was successfully copied from the production database to the replica database on the given DAG member that still needs to process on the replica database. The "**CopyQueueLength**" will need to reach zero before the "**CopyReplayLength**" will start making meaningful progress to reaching zero.
|
||||
|
||||
When both the "**CopyQueueLength**" and "**CopyReplayLength**" queues have reached zero, the replica database(s) will have reached 100% parity with the production (active/mounted) database.
|
||||
|
||||
## Changing Active/Mounted DAG Member
|
||||
You may find that you need to perform work on one of the DAG members, and that requires you to failover the responsibility of hosting the Exchange environment to one of the other members of the DAG. You can generally do this with one command, seen below:
|
||||
```powershell
|
||||
Move-ActiveMailboxDatabase -Identity "DB01" -ActivateOnServer "MX-DAG-02" -MountDialOverride BestAvailability
|
||||
```
|
||||
|
||||
!!! info "Argument Breakdown"
|
||||
`-MountDialOverride`
|
||||
Specifies how tolerant Exchange should be to database copy health when mounting a database on the target server. This setting controls the level of availability Exchange requires before mounting the mailbox database after the move.
|
||||
|
||||
`-MountDialOverride`
|
||||
Instructs Exchange to mount the database as long as at least one healthy copy is available. This option maximizes uptime by allowing a database to mount even if some copies are unhealthy, prioritizing availability over strict health checks.
|
||||
|
||||
## Troubleshooting
|
||||
You may run into issues where either the `Status` or `ContentIndexState` are either Unhealthy, Suspended, or Failed. If this happens, you need to resume replication of the database from the production active/mounted server to the server that is having issues. In the worst-case, you would re-seed the replica database from-scratch.
|
||||
|
||||
### If `Status` is Unhealthy or Suspended
|
||||
If one of the DAG members has a status of "**Unhealthy**", you can run the following command to attempt to resume replication.
|
||||
```powershell
|
||||
Resume-MailboxDatabaseCopy -Identity "DB01\MX-DAG-02"
|
||||
```
|
||||
|
||||
If this fails to cause replication to resume, you can try telling the database to just focus on replication, which tells it to copy the queues and replay them on the replica database, while avoiding interacting with the "**ContentIndexState**" which can be individually fixed in the commands below:
|
||||
```powershell
|
||||
Resume-MailboxDatabaseCopy -Identity "DB01\MX-DAG-02" -ReplicationOnly
|
||||
```
|
||||
|
||||
### If `Status` is `ServiceDown`
|
||||
If you see this, it generally means that the Exchange Services for some reason or another are not running. You can remediate this with a powershell script. You will then have to double-check your work to ensure that all "Microsoft Exchange" services that have a startup mode of "Automatic" are running, if not, manually start them, then check on the status of the DAG again to see if the status changes from `ServiceDown` to `Healthy`. Depending on the speed of the Exchange server, it may take a few minutes, 5-10 minutes, for the services to fully initialize and be ready to handle requests. Go get a coffee and come back and check on the status of the DAG at that time.
|
||||
|
||||
[:material-powershell: Restart Exchange Services Script](../restart-exchange-services.md){ .md-button }
|
||||
|
||||
### If `ContentIndexState` is Unhealthy or Suspended
|
||||
If you see that the "ContentIndexState" is unhappy, you can run the following command to force it to re-seed / rebuild itself. (This is non-destructive this this is happening on a replica database).
|
||||
```powershell
|
||||
Update-MailboxDatabaseCopy "DB01\MX05" -CatalogOnly -BeginSeed
|
||||
```
|
||||
|
||||
### If Replica Database is FUBAR
|
||||
If the replica database just is not playing nice, you can take the *nuclear option* of completely rebuilding the replica database.
|
||||
|
||||
!!! warning
|
||||
This will destroy the replica database, so be careful to ensure you have a backup (if possible) before you do this. The following command will completely replace the replica database and replicate the data from the production active/mounted database to the newly-created replica database.
|
||||
```powershell
|
||||
Update-MailboxDatabaseCopy -Identity "DB01\MX-DAG-02" -SourceServer "MX-DAG-01"
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
### Purpose:
|
||||
Sometimes Microsoft Exchange Server will misbehave and the services will need to be *bumped* to fix them. This script iterates over all of the Exchange-related services and restarts them automatically for you.
|
||||
|
||||
``` powershell
|
||||
$servicelist = Get-Service | Where-Object {$_.DisplayName -like "Microsoft Exchange *"}
|
||||
$servicelist += Get-Service | Where-Object {$_.DisplayName -eq "IIS Admin Service"}
|
||||
$servicelist += Get-Service | Where-Object { $_.DisplayName –eq "Windows Management Instrumentation" }
|
||||
$servicelist += Get-Service | Where-Object { $_.DisplayName –eq "World Wide Web Publishing Service" }
|
||||
|
||||
foreach($service in $servicelist){
|
||||
Set-Service $service -StartupType Automatic
|
||||
Start-Service $service
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
**Purpose**: Sometimes you need to set an autoreply on a mailbox on behalf of someone else. In these cases, you can leverage the "Exchange Admin Shell" to configure an auto-reply to anyone who sends an email to the mailbox.
|
||||
|
||||
In the example below, replace `<username>` with the shortened username of the target user. (e.g. `nicole.rappe` not `nicole.rappe@bunny-lab.io`)
|
||||
|
||||
``` powershell
|
||||
Set-MailboxAutoReplyConfiguration -Identity <username> -AutoReplyState Scheduled -StartTime "1/1/2025 00:00:00" -EndTime "1/15/2025 00:00:00" -InternalMessage "Example,<br><br>Message here.<br><br>Thank you." -ExternalMessage "Example,<br><br>Message here.<br><br>Thank you."
|
||||
```
|
||||
|
||||
!!! note "Internal vs External"
|
||||
When you configure auto-replies, you can have different replies sent to people within the same organization versus external senders, keep this in mind based on the roles of the person.
|
||||
|
||||
!!! example "Example Email Reply"
|
||||
The email auto reply will look something like this based on the command above.
|
||||
```
|
||||
Example,
|
||||
|
||||
Message Here.
|
||||
|
||||
Thank you.
|
||||
```
|
||||
Reference in New Issue
Block a user