Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
22 KB
Referenced Files
None
Subscribers
None
diff --git a/docs/docs/administration/postfix.md b/docs/docs/administration/postfix.md
index 7fbb7af..5ccfecf 100644
--- a/docs/docs/administration/postfix.md
+++ b/docs/docs/administration/postfix.md
@@ -1,49 +1,72 @@
# Postfix
Postfix has the following relevant queues:
* Active: Email that is going to be delivered
* Deferred: Email that failed to be delivered, but is being retried until delivery succeeds.
* Hold: Email that was place on hold is not automatically retried.
## Inspecting mail queues
The following will generate an overview of mails in the queues, grouped by sender:
```
kolabctl postfix mailq-count-senders
```
This can take a significant time (15min with > 50k messages).
To get a quick count:
```
kolabctl postfix find /var/spool/postfix/deferred/ -type f -print | wc -l
```
## Putting mails on hold by sender address
The following will move mails from a specific sender, that are currently in the active or deferred queue, to the hold queue.
```
kolabctl postfix mailq-put-on-hold $sender
```
To delete emails that are currently in the hold queue, by sender:
```
kolabctl postfix mailq-purge-hold-queue --from $sender --now
```
## Print queued emails
+Print all queued emails, from all queues.
+
```
kolabctl postfix postqueue -p
```
+## Delete emails from all queues by sender
+
+To delete emails that are currently in any queue, by sender:
+
+```
+kolabctl postfix bash -c "postqueue -p | grep $sender | grep -oE '^[0-9A-F]{12}' | xargs -i postsuper -d {}"
+```
+
+
## Release emails from the hold queue
To release all emails in the hold queue:
```
kolabctl postfix postsuper -H ALL
```
+
+## Print a message by id
+
+```
+kolabctl postfix postcat -q $messageid
+```
+
+## Process the mailqueue immediately
+
+```
+kolabctl postfix postqueue -f
+```
diff --git a/docs/docs/deploy/networking.md b/docs/docs/deploy/networking.md
index 7ebd956..9c7300b 100644
--- a/docs/docs/deploy/networking.md
+++ b/docs/docs/deploy/networking.md
@@ -1,256 +1,264 @@
# Networking
## IPs
Kolab requires at least one public IP to function.
On a single node deployment one IP is enough. For a cluster-setup at least 3 internal ip's are required, that are claimed by services via metallb:
* Postfix requires a dedicated IP for port 25 email receiving
* Coturn requires a dedicated IP
* Managesieve requires a dedicated IP because it is not proxied via the nginx proxy.
* The nginx proxy claims one IP for all other services, forwarding the client ip as necessary.
The dedicated IP requirement stems from how services are exposed via metallb, and the requirement to see client-ips.
It would in principle be possible to consolidate all services on a single IP by routing everything over a proxy, but this requires making all components compatible with the proxy protocol to forward the client ip (postfix via postscreen).
Metallb currently requires dedicated ip's because the service *must* be on the same node as the destination pod for the client-ip to be accurate.
### Client-IP
Various components require that the client-ip is available for them to function properly:
* Postfix requires the client IP on port 25, for various checks
* Coturn requires the client IP for RDP traffic routing.
* The NGINX proxy requires the client IP for imap/submission for rate-limiting and access control checks.
For http based traffic the client ip may also be required (e.g. for dav/activesync 2fa), but over http the X-Forwarded-For header may be used (set by ingress by default).
## Exposed endpoints
-* 80/443 (via ingress):
- * /: Kolab 4 UI
- * /api: Kolab 4 API
- * /oauth: Laravel passport oauth
- * admin.$domain/horizon: Laravel Horizon Dashboard
- * /Microsoft-Server-ActiveSync: Activesync via NGINX Proxy to roundcube container
- * /dav: Dav via NGINX Proxy to imap container
- * /webmail: Roundcube via NGINX Proxy to roundcube container
- * /chwala: Chwala file api via NGINX Proxy to roundcube container
- * /browser, /hosting, /cool: Collabora http endpoints via NGINX Proxy to collabora container
- * /meetmedia: Kolab Meet http endpoint
- * /.well-known: Various .well-known endpoints for autoconfig
- * /mail/config-v1.1.xml: Mail autoconfig
- * /prometheus: Prometheus
- * /loki: Loki API
- * /alertmanager: Alertmanager UI
-* 143:993 (via metallb, proxy ip):
+* Port 80/443 (via ingress):
+ * `/`: Kolab 4 UI
+ * `/api`: Kolab 4 API
+ * `/oauth`: Laravel passport oauth
+ * `admin.$domain/horizon`: Laravel Horizon Dashboard
+ * `/Microsoft-Server-ActiveSync`: Activesync via NGINX Proxy to roundcube container
+ * `/dav`: Dav via NGINX Proxy to imap container
+ * `/webmail`: Roundcube via NGINX Proxy to roundcube container
+ * `/chwala`: Chwala file api via NGINX Proxy to roundcube container
+ * `/browser, /hosting, /cool`: Collabora http endpoints via NGINX Proxy to collabora container
+ * `/meetmedia`: Kolab Meet http endpoint
+ * `/.well-known`: Various .well-known endpoints for autoconfig
+ * `/mail/config-v1.1.xml`: Mail autoconfig
+ * `/prometheus`: Prometheus
+ * `/select`: Victorialogs API
+ * `/alertmanager`: Alertmanager UI
+* Port 143:993 (via metallb, proxy ip):
* IMAP via NGINX Proxy
-* 465/587(via metallb, proxy ip):
+* Port 465/587(via metallb, proxy ip):
* Submission for clients
-* 25 (via metallb, smtp ip):
+* Port 25 (via metallb, smtp ip):
* SMTP for mail delivery
-* 3478 (via metallb, turn ip)
+* Port 3478 (via metallb, turn ip)
* Coturn for Webrtc
## DNS
To successfully send and receive mail, various dns related aspects must be configured properly.
### PTR records
A PTR record must be available for all ip's that appear as source addresses when sending emails, so that a dns reverse lookup resolves to a domain that also points to the same IP via A record.
(postfix reject_unknown_client_hostname).
### MTA-STS
MTA-STS applies to inbound email from other parties. It requests from a compliant mailexchanger to only deliver email over tls,
and only to the ip's listed in the mta-sts policy
* Before submitting mail the MTA-STS policy on https://mta_sts.$domain/.well-known/mta-sts.txt will be looked up, which looks like this:
```
version: STSv1
mode: enforce
mx: mx01.kolabnow.com
max_age: 604800
```
* It will also lookup _mta-sts.$domain with a policy id that should change when the policy changes.
* Email will only be delivered to the servers listed in the policy file.
Relevant DNS records:
* `mta-sts.$domain CNAME kolab.klab.cc.`
* `_mta-sts.$domain TXT "v=STSv1; id=2024031901;"`
The mta-sts. CNAME record is only required if we don't provide the policy directly from that subdomain.
### DKIM
DKIM is applied to individual emails, and ensures the header information of each mail has not been tampered with.
Each mail is signed with a private key, the recipient verifies the signature after looking up the public key on the senders domain (d= in signature).
Amavis implements dkim signing and verification.
The published dkim key must match the selector used in the signature (s=dkim1), which is used to select the correct dkim public key in dns (on the domain in the d= in the signature).
By using different selectors, multiple dkim signatures are possible, e.g. for key rotation.
Relevant DNS records:
```
dkim1._domainkey.kolab TXT (
"v=DKIM1; p="
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7JdTEn/T2MhB6KLbATJj"
"4SGernbem4d7dAW7/kVRbiMB2EtPpQCR98eeXOOHcufXVc3w4BocXEnD47JPpkFY"
"JBXWF32m4Y2SapBYbsXndN9fyXRrHO9wPJlW5QK5i9D/bRUznfaBJm54y+BuX0Ln"
"/ippqFe6z3LPjmro9Y9WpRzevYG/TT69Iug5v4U/PA1/rEv+zZGQvNxInZYF7O2M"
"FDbD2pYi7l4hWADP+iwOEc+Li5vPlEvOaUlSQCb06sc0/QBHDDyU2WaEJiYy/Mk2"
"xCmSI44f3mQghmiNsu7vlPiztAYKjNyiVk8iWDttL9OV9qQyxHL18Q74UzJR6Ayl"
"rwIDAQAB"
)
```
* To delegate the dkim key:
```
dkim1._domainkey.kolab-secondary CNAME dkim1._domainkey.kolab.klab.cc
```
### SPF
SPF defines from which ip's email may come.
The spf policy will be retrieved on the domain in the SMTP HELO/FROM (return path).
The policy must match the sending ip.
Relevant DNS records:
-* kolab TXT "v=spf1 mx a:kolab.klab.cc mx:kolab.klab.cc -all"
+```
+kolab TXT "v=spf1 mx a:kolab.klab.cc mx:kolab.klab.cc -all"
+```
### DMARC
The dmarc policy tells the recipient what to do after checking spf and dkim.
Relevant DNS records:
```
_dmarc.kolab TXT "v=DMARC1; p=quarantine; adkim=s; aspf=s; rua=mailto:admin@kolab.klab.cc; ruf=mailto:admin@kolab.klab.cc"
```
The above policy sets a strict adkim/aspf policy, and instructs to quarantine mail if the check fails.
### Autodiscovery
For Outlook:
-* autodiscover.kolab CNAME kolab.klab.cc.
+```
+autodiscover.kolab CNAME kolab.klab.cc.
+```
For service discovery:
-* _autodiscover._tcp.kolab SRV 0 0 443 kolab.klab.cc.
-* _caldav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
-* _caldavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
-* _carddav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
-* _carddavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
-* _imap._tcp.kolab SRV 0 0 143 kolab.klab.cc.
-* _imaps._tcp.kolab SRV 0 1 993 kolab.klab.cc.
-* _sieve._tcp.kolab SRV 0 0 4190 kolab.klab.cc.
-* _submission._tcp.kolab SRV 0 1 587 kolab.klab.cc.
-* _webdav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
-* _webdavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
+```
+_autodiscover._tcp.kolab SRV 0 0 443 kolab.klab.cc.
+_caldav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
+_caldavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
+_carddav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
+_carddavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
+_imap._tcp.kolab SRV 0 0 143 kolab.klab.cc.
+_imaps._tcp.kolab SRV 0 1 993 kolab.klab.cc.
+_sieve._tcp.kolab SRV 0 0 4190 kolab.klab.cc.
+_submission._tcp.kolab SRV 0 1 587 kolab.klab.cc.
+_webdav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
+_webdavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
+```
Enable tls reporting via tlsrpt for failed delivery attempts:
-* _smtp._tls.kolab TXT "v=TLSRPTv1; rua=mailto:admin@kolab.klab.cc"
+```
+_smtp._tls.kolab TXT "v=TLSRPTv1; rua=mailto:admin@kolab.klab.cc"
+```
### Example: kolab.klab.cc subdomain configuration
```
kolab A 185.254.79.10
kolab MX 10 kolab.klab.cc.
kolab TXT "v=spf1 mx a:kolab.klab.cc mx:kolab.klab.cc -all"
autodiscover.kolab CNAME kolab.klab.cc.
_autodiscover._tcp.kolab SRV 0 0 443 kolab.klab.cc.
_caldav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
_caldavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
_carddav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
_carddavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
_imap._tcp.kolab SRV 0 0 143 kolab.klab.cc.
_imaps._tcp.kolab SRV 0 1 993 kolab.klab.cc.
_sieve._tcp.kolab SRV 0 0 4190 kolab.klab.cc.
_submission._tcp.kolab SRV 0 1 587 kolab.klab.cc.
_webdav._tcp.kolab SRV 0 0 80 kolab.klab.cc.
_webdavs._tcp.kolab SRV 0 1 443 kolab.klab.cc.
_smtp._tls.kolab TXT "v=TLSRPTv1; rua=mailto:admin@kolab.klab.cc"
_dmarc.kolab TXT "v=DMARC1; p=quarantine; adkim=s; aspf=s; rua=mailto:admin@kolab.klab.cc; ruf=mailto:admin@kolab.klab.cc"
mta-sts.kolab CNAME kolab.klab.cc.
_mta-sts.kolab TXT "v=STSv1; id=2024031901;"
dkim1._domainkey.kolab TXT (
"v=DKIM1; p="
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7JdTEn/T2MhB6KLbATJj"
"4SGernbem4d7dAW7/kVRbiMB2EtPpQCR98eeXOOHcufXVc3w4BocXEnD47JPpkFY"
"JBXWF32m4Y2SapBYbsXndN9fyXRrHO9wPJlW5QK5i9D/bRUznfaBJm54y+BuX0Ln"
"/ippqFe6z3LPjmro9Y9WpRzevYG/TT69Iug5v4U/PA1/rEv+zZGQvNxInZYF7O2M"
"FDbD2pYi7l4hWADP+iwOEc+Li5vPlEvOaUlSQCb06sc0/QBHDDyU2WaEJiYy/Mk2"
"xCmSI44f3mQghmiNsu7vlPiztAYKjNyiVk8iWDttL9OV9qQyxHL18Q74UzJR6Ayl"
"rwIDAQAB"
)
```
### Example: Additional configuration of a secondary domain
```
kolab-secondary MX 10 kolab.klab.cc.
kolab-secondary TXT "v=spf1 mx include:kolab.klab.cc -all"
_dmarc.kolab-secondary TXT "v=DMARC1; p=quarantine; adkim=s; aspf=s; rua=mailto:admin@kolab.klab.cc; ruf=mailto:admin@kolab.klab.cc"
dkim1._domainkey.kolab-secondary CNAME dkim1._domainkey.kolab.klab.cc
_autodiscover._tcp.kolab-secondary SRV 0 0 443 kolab.klab.cc.
_caldav._tcp.kolab-secondary SRV 0 0 80 kolab.klab.cc.
_caldavs._tcp.kolab-secondary SRV 0 1 443 kolab.klab.cc.
_carddav._tcp.kolab-secondary SRV 0 0 80 kolab.klab.cc.
_carddavs._tcp.kolab-secondary SRV 0 1 443 kolab.klab.cc.
_imap._tcp.kolab-secondary SRV 0 0 143 kolab.klab.cc.
_imaps._tcp.kolab-secondary SRV 0 1 993 kolab.klab.cc.
_sieve._tcp.kolab-secondary SRV 0 0 4190 kolab.klab.cc.
_submission._tcp.kolab-secondary SRV 0 1 587 kolab.klab.cc.
_webdav._tcp.kolab-secondary SRV 0 0 80 kolab.klab.cc.
_webdavs._tcp.kolab-secondary SRV 0 1 443 kolab.klab.cc.
_smtp._tls.kolab-secondary TXT "v=TLSRPTv1; rua=mailto:admin@kolab.klab.cc"
```
## NAT
### Inbound
```
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 80 -j DNAT --to-destination "10.11.2.254"
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 443 -j DNAT --to-destination "10.11.2.254"
# Postfix has a dedicated ip for port 25
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 25 -j DNAT --to-destination "10.11.2.131"
# The nginx proxy has a dedicated ip
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 143 -j DNAT --to-destination "10.11.2.132"
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 465 -j DNAT --to-destination "10.11.2.132"
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 587 -j DNAT --to-destination "10.11.2.132"
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 993 -j DNAT --to-destination "10.11.2.132"
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 4190 -j DNAT --to-destination "10.11.2.132"
# meet webrtc ports
$iptables -t nat -A PREROUTING -p tcp -m tcp -d "185.254.79.10" --dport 44444:44446 -j DNAT --to-destination "10.11.2.133"
$iptables -t nat -A PREROUTING -p udp -m udp -d "185.254.79.10" --dport 44444:44446 -j DNAT --to-destination "10.11.2.133"
```
### Outbound
```
allow_http "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_https "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_imap "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_imaps "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_smtp "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_smtps "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_submission "${vlan1102}" "0.0.0.0/0" "FORWARD"
allow_sieve "0/0" "10.11.2.128/28" "FORWARD"
allow_standard_protocol "44444:44446" "tcp" "0/0" "0.0.0.0/0" "FORWARD"
allow_standard_protocol "44444:44446" "udp" "0/0" "0.0.0.0/0" "FORWARD"
$iptables -t nat -A POSTROUTING \
-o ${external_interface} -s ${vlan1102} -j SNAT --to-source "185.254.79.10"
```
diff --git a/docs/docs/overview/index.md b/docs/docs/overview/index.md
index 42e9c3f..4f25132 100644
--- a/docs/docs/overview/index.md
+++ b/docs/docs/overview/index.md
@@ -1,9 +1,44 @@
# Kolab Overview
-Kolab consists of the Kolab PHP application as well as a variety of components that are integrated:
+Kolab consists of:
+* The Kolab PHP Application as management interface and central integration point
* Cyrus IMAP as IMAP/CalDAV/CardDAV Server
* Postfix as Mail Transfer Agent
* Amavis and Spamassassin as Spam/Virus checker
+* Roundcube for webmail
+* Syncroton for ActiveSync
+* Chwala
* Kolab Meet for WebRTC video-conferencing
* Collabora for collaborative editing
+
+The following provides a high-level overview how the various components interact with each other.
+
+``` mermaid
+graph TD
+ Proxy[Proxy]
+ IMAP[IMAP/CalDAV/CardDAV]
+ Postfix --> |Delivery|IMAP
+ Proxy --> IMAP
+ Proxy --> Kolab
+ Proxy --> Postfix
+ Proxy --> Roundcube
+ Postfix --> Mariadb
+ Kolab --> IMAP
+ Kolab --> Mariadb
+ Kolab --> Redis
+ Kolab --> |S3| Minio
+ Roundcube --> IMAP
+ Roundcube --> Postfix
+ Roundcube --> Kolab
+ Roundcube --> Mariadb
+ Roundcube --> Redis
+ Postfix --> |Filtering|Kolab
+ Postfix --> |Auth|Kolab
+ IMAP --> |Auth|Kolab
+ Postfix --> Disk
+ IMAP --> Disk
+ Mariadb --> Disk
+ Redis --> Disk
+ Minio --> Disk
+```
diff --git a/docs/docs/overview/kolab.md b/docs/docs/overview/kolab.md
new file mode 100644
index 0000000..af87817
--- /dev/null
+++ b/docs/docs/overview/kolab.md
@@ -0,0 +1,5 @@
+# Kolab PHP Application
+
+Kolab is a Laravel based application that is served via swoole.
+
+Kolab provides the management interface (the cockpit), and an API that all components work against.
diff --git a/docs/docs/overview/roundcube.md b/docs/docs/overview/roundcube.md
new file mode 100644
index 0000000..6b2756c
--- /dev/null
+++ b/docs/docs/overview/roundcube.md
@@ -0,0 +1,32 @@
+# Roundcube
+
+Roundcube is the webmail application that Kolab uses and actively develops.
+In addition to webmail it provides comprehensive groupware functionality, through a variety of plugins.
+
+``` mermaid
+graph TD
+ HTTPD --> Roundcube
+ Roundcube --> |Mail over IMAP|IMAP[Cyrus IMAP]
+ Roundcube --> |Contacts over CardDAV|IMAP[Cyrus IMAP]
+ Roundcube --> |Calendars over CalDAV|IMAP[Cyrus IMAP]
+ Roundcube --> |Send emails|Postfix
+ Roundcube --> |Syncronization state|Mariadb
+ Roundcube --> |Caching|Redis
+```
+
+## Syncroton
+
+Syncroton is an implementation of the ActiveSync protocol, based on the Roundcube framework. It allows devices to synchronize Email, Tasks, Calendars and Contacts stored in Cyrus-IMAP via
+
+``` mermaid
+graph TD
+ HTTPD --> Syncroton
+ Syncroton --> |Mail over IMAP|IMAP[Cyrus IMAP]
+ Syncroton --> |Contacts over CardDAV|IMAP[Cyrus IMAP]
+ Syncroton --> |Calendars over CalDAV|IMAP[Cyrus IMAP]
+ Syncroton --> |Send emails|Postfix
+ Syncroton --> |Syncronization state|Mariadb
+ Syncroton --> |Caching|Redis
+```
+
+## Chwala
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index d91f6b7..f42c0fc 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -1,72 +1,77 @@
---
site_name: Kolab Documentation 4.0.16
site_url: https://docs.kolab.org/
repo_name: kolab-infrastructure
repo_url: https://git.kolab.org/source/kolab-infrastructure
theme:
name: material
palette:
primary: grey
accent: custom
font:
text: Nunito
logo: assets/mail-blue.png
favicon: assets/mail-blue.png
features:
- navigation.sections
- navigation.instant
- navigation.tabs
- navigation.top
- navigation.tracking
- navigation.indexes
- search.highlight
- search.share
- search.suggest
- toc.follow
+ - content.code.copy
+ - content.code.annotate
# FIXME doesn't work with mermaid atm.
# It attempts to obtain mermaid over the url inside the container "http://0.0.0.0:8000" instead of what we use in the browser (http://localhost:9000).
# This is not just about the port, but the entire URL
# plugins:
# - privacy
extra_css:
- stylesheets/extra.css
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
nav:
- Home:
- index.md
- home/what-is-kolab.md
- home/kolab3.md
- home/contribute.md
- Overview:
- overview/index.md
- overview/distribution.md
- overview/kolabctl.md
- overview/logging.md
- - overview/mta.md
+ - Components:
+ - overview/mta.md
+ - overview/roundcube.md
+ - overview/kolab.md
- Deploy:
- deploy/index.md
- deploy/quickstart.md
- deploy/supported-platforms.md
- deploy/about-kolab-on-kubernetes.md
- Reference Architectures:
- deploy/reference-architectures/index.md
- Single Node K3s: deploy/reference-architectures/single-node-k3s.md
- Replicated K3s: deploy/reference-architectures/replicated-k3s.md
- Kubernetes Cluster: deploy/reference-architectures/kubernetes-cluster.md
- Networking: deploy/networking.md
- Administration:
- administration/index.md
- Notes: administration/notes.md
- Migration: administration/migration.md
- User management: administration/usermanagement.md
- Changing TLS Certificates: administration/changing-tls-certificates.md
- Cyrus IMAP: administration/cyrus-imap.md
- Postfix: administration/postfix.md
- Spamassassin: administration/spamassassin.md

File Metadata

Mime Type
text/x-diff
Expires
Sat, Apr 4, 4:38 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822599
Default Alt Text
(22 KB)

Event Timeline