[[Uebersicht|← Zurück zur Homepage]]
# PaperSafe – Proton Mail Bridge (Installation & Anbindung)
> **Rolle dieser Note:** Die **vollständige, tatsächlich umgesetzte** Einrichtung der Proton-Anbindung – von der Bridge im eigenen LXC über die knifflige Zertifikats-/Erreichbarkeitslösung bis zu den Paperless-Regeln. Ausgegliedert aus [[11-E-Mail-Postfaecher]] (dort steht das allgemeine IMAP-Konzept + Outlook); diese Note ist für Proton **maßgeblich**.
>
> **Stand 24.07.2026:** Bridge läuft produktiv, Anbindung an Paperless steht, Erstimport abgeschlossen (alle Ordner geleert). Der laufende Abruf erfolgt automatisch alle 10 Min (siehe „Betrieb").
## Überblick / Datenfluss
```
Proton-Server ──(HTTPS, Login+2FA)──► Proton Bridge [CT 100, eigener LXC]
│ lokaler IMAP 127.0.0.1:1143 (STARTTLS, self-signed CN=127.0.0.1)
│ systemd-socket-proxyd: 0.0.0.0:143 → 127.0.0.1:1143
▼ LAN: 192.168.2.49:143
socat-Sidecar (im Netz-Namespace des Paperless-webservers)
127.0.0.1:143 → 192.168.2.49:143
▼
Paperless (CT 110) ── Mail-Konto 127.0.0.1:143 ──► 15 Regeln (je Ordner ein Tag)
```
**Warum dieser Umweg?** Das Bridge-Zertifikat ist fest auf **`CN=127.0.0.1` / SAN IP 127.0.0.1** ausgestellt und liegt **verschlüsselt** in der Bridge (`vault.enc`) – es ist **nicht** gegen ein Zertifikat mit der LAN-IP austauschbar. Paperless prüft aber den Hostnamen (kein Abschalter). Lösung: Paperless spricht die Bridge als **`127.0.0.1`** an (dann passt der Zertifikatsname), und ein winziger **socat-Weiterleiter im Netz-Namespace des webserver-Containers** reicht `127.0.0.1:143` an die Bridge-IP weiter. Das selbstsignierte Zertifikat wird über `PAPERLESS_EMAIL_CERTIFICATE_LOCATION` als vertrauenswürdig hinterlegt.
## Komponenten (Ist-Stand)
| Komponente | Ort / Wert |
|---|---|
| Bridge-LXC | **CT 100** „protonmail-bridge", **192.168.2.49**, Debian 13 (Community-Script) |
| Bridge-Dienst | `protonmail-bridge.service` (headless, `--noninteractive`), enabled |
| LAN-Proxy | `protonmail-bridge-imap.socket` → `…-imap-proxy.service` (systemd-socket-proxyd), `0.0.0.0:143 → 127.0.0.1:1143` |
| socat-Sidecar | Compose-Dienst `proton-imap-proxy`, Image `docker.io/alpine/socat:1.8.0.3` (gepinnt), `network_mode: service:webserver`, Kommando `TCP4-LISTEN:143,fork,reuseaddr,bind=127.0.0.1 TCP4:192.168.2.49:143` |
| Zertifikat | `/opt/paperless/certs/proton-bridge.pem` (Host) → gemountet nach `/usr/src/paperless/certs/proton-bridge.pem` (ro) |
| Env | `PAPERLESS_EMAIL_CERTIFICATE_LOCATION=/usr/src/paperless/certs/proton-bridge.pem` (in `docker-compose.env`) |
| Paperless-Konto | „Proton", Server **127.0.0.1**, Port **143**, **STARTTLS**, User = Proton-Adresse, Passwort = Bridge-IMAP-Passwort |
## Installation – so wurde es gemacht
### 1. Bridge-LXC anlegen (Community-Script)
Proxmox-VE-Helper-Script **„Proton Mail Bridge"** ([community-scripts.org/scripts/protonmail-bridge](https://community-scripts.org/scripts/protonmail-bridge)) in der Proxmox-Shell ausführen (interaktives whiptail-Menü, Defaults gewählt). Ergebnis: CT 100, Debian 13, Bridge + `pass`/GPG + die beiden Socket-Proxy-Units (IMAP 143, SMTP 587) – jeweils zunächst **disabled**, mit Bedingung `ConditionPathExists=/home/protonbridge/.protonmailbridge-initialized`.
### 2. Proton-Login (interaktiv, Nutzer)
Im Container `protonmailbridge-configure` ausführen → CLI-Login mit **Proton-Adresse + 2FA**. Die Bridge erzeugt dabei das **IMAP-Passwort** (Benutzername = Proton-Adresse).
> **Abschluss nicht vergessen:** Im Bridge-Prompt `>>>` am Ende **`exit`** eingeben. Erst dann setzt das `configure`-Script den Marker `.protonmailbridge-initialized`, aktiviert den **headless-Dienst** und **beide Sockets** (`systemctl enable --now`). Ohne `exit` bleibt der LAN-Port `:143` zu.
### 3. Erreichbarkeit prüfen
```bash
# im CT 100
systemctl is-active protonmail-bridge.service protonmail-bridge-imap.socket # beide active
ss -tlnp | grep :143 # *:143 (systemd)
# vom Host
openssl s_client -connect 192.168.2.49:143 -starttls imap # Zertifikat CN=127.0.0.1
```
### 4. Zertifikat für Paperless hinterlegen
```bash
# im CT 110
mkdir -p /opt/paperless/certs
echo | openssl s_client -connect 192.168.2.49:143 -starttls imap 2>/dev/null \
| openssl x509 -outform PEM > /opt/paperless/certs/proton-bridge.pem
```
Dann in `docker-compose.yml` beim `webserver` mounten:
`- ./certs/proton-bridge.pem:/usr/src/paperless/certs/proton-bridge.pem:ro`
und in `docker-compose.env`:
`PAPERLESS_EMAIL_CERTIFICATE_LOCATION=/usr/src/paperless/certs/proton-bridge.pem`
(Setting-Name ist `…_LOCATION`, **nicht** `…_FILE`.)
### 5. socat-Sidecar in den Compose-Stack
Neuer Dienst in `docker-compose.yml` (teilt den Netz-Namespace des webservers, damit `127.0.0.1:143` das Loopback ist, das Paperless sieht):
```yaml
proton-imap-proxy:
image: docker.io/alpine/socat:1.8.0.3
restart: unless-stopped
network_mode: "service:webserver"
depends_on:
- webserver
command: TCP4-LISTEN:143,fork,reuseaddr,bind=127.0.0.1 TCP4:192.168.2.49:143
```
`docker compose up -d` → webserver wird neu erstellt (Mount + Env), Sidecar startet.
### 6. Verbindungstest (exakt wie Paperless)
```python
import imaplib, ssl
ctx = ssl.create_default_context()
ctx.load_verify_locations(cafile="/usr/src/paperless/certs/proton-bridge.pem")
M = imaplib.IMAP4("127.0.0.1", 143); M.starttls(ssl_context=ctx)
M.login("<proton-adresse>", "<bridge-imap-passwort>") # muss OK liefern
```
Vertrauen (Zertifikatsdatei) **+** Hostname (`127.0.0.1` = SAN) **+** Login müssen zusammen durchlaufen.
### 7. Mail-Konto + Regeln in Paperless
Konto „Proton" (Server 127.0.0.1, Port 143, STARTTLS, User/Passwort). Je Proton-Ablageordner **eine Regel** (`folder` = genau ein Ordner, keine Rekursion), `assign_tags` = Ordnername, `assign_title_from` = Betreff, `consumption_scope` = **Stufe 3** (Mail als `.eml` + Anhänge getrennt), `attachment_type` = nur echte Anhänge.
> **Sonderfall Gesendet (`Sent`, seit 25.07.2026):** Zusätzlich zu den Ablageordnern wird auch der System-Ordner **`Sent`** gesichert (Regel „Proton: Gesendet", Tag **`Gesendet`**, Aktion Delete wie die übrigen). **Kein Korrespondent** – bei gesendeten Mails ist der Absender immer der eigene Account; Paperless kann den **Empfänger nicht** als Korrespondent setzen (`assign_correspondent_from` kennt nur Absender/fest/keiner). Der Empfänger bleibt über den Volltext (Header „An:") auffindbar.
## Betriebs-Fallstricke (am System gelernt)
> **⚠ Mailverarbeitung als User `paperless` anstoßen, nie als root.**
> Wird `process_mail_accounts()` über die Django-Shell **als root** ausgelöst, gehören die temporären `.eml` in `data/scratch` root (Modus 0600). Der Consumer läuft als `paperless` und kann sie **nicht** lesen → `[Errno 13] Permission denied`. Immer `docker compose exec --user paperless …` verwenden. Der reguläre Zeitplan (Celery-Beat) läuft ohnehin als `paperless`.
> **⚠ Getrennte Datenbestände O365 ↔ Proton.** Das Paperless-Archiv stammt aus dem **alten O365-Postfach** (PST-Import); Proton ist das **neue** Postfach (Umstellung ~Mitte 2025). Überlappung minimal. Die **.eml-Texte** werden neu importiert (PST- und IMAP-Serialisierung unterscheiden sich → Byte-MD5 greift nicht als Duplikatschutz). **Anhänge** (PDF/Bild) sind dagegen byte-identisch – vorhandene werden von Paperless als Duplikat **übersprungen** (Task-Status „FAILURE: … is a duplicate of …"). Das ist **kein Fehler**, sondern gewollt: keine doppelten Belege.
> **Delete-Semantik bei Proton:** Die Regel-Aktion „Delete" entfernt die Mail nach erfolgreichem Import **aus dem Ordner** – Proton **entlabelt** sie, die Mail bleibt in **„All Mail"** (nicht im Papierkorb, nicht endgültig weg). Gelöscht wird **nur nach erfolgreichem** eml-Import (chord-abgesichert); scheitert der Import, bleibt die Mail liegen.
> **⚠ webserver-Neustart reißt den Sidecar mit.** Der socat-Sidecar `proton-imap-proxy` teilt den **Netz-Namespace des webservers** (`network_mode: service:webserver`). Wird der `webserver`-Container neu gestartet (z. B. als Consumer-Notgriff oder durch den Post-Boot-Fix, siehe [[04-Betrieb-Backup]] Abschnitt 4a), entsteht ein neuer Namespace und der Sidecar hängt am alten → `127.0.0.1:143` liefert `Connection refused`, **der Proton-Abruf fällt still aus**. Fix: `docker compose restart proton-imap-proxy` **nach jedem** webserver-Neustart. Am 25.07.2026 real aufgetreten und behoben.
## Betrieb – wann und wie der Import läuft
Der Abruf läuft **vollautomatisch alle 10 Minuten**, rund um die Uhr.
| Punkt | Wert (am System verifiziert 24.07.2026) |
|---|---|
| Auslöser | Celery-Beat-Task **„Check all e-mail accounts"** → `paperless_mail.tasks.process_mail_accounts` |
| Zeitplan | **`*/10 * * * *`** (alle 10 Min). `PAPERLESS_EMAIL_TASK_CRON` ist **nicht** gesetzt → Paperless-Standard |
| Ausführungs-User | `paperless` (Worker) – nie root (siehe Fallstrick oben) |
| Voraussetzung | CT 110 **und** CT 100 (Bridge) laufen. Ist die Bridge aus, scheitert der Lauf still und wird beim nächsten Zyklus erneut versucht |
**Ablauf je Lauf:** verbinden (`127.0.0.1:143` → socat → Bridge) → alle **15 Regeln** abarbeiten (je Regel ein Ordner) → neue Mails einlesen (Stufe 3: `.eml` + Anhänge, Tag = Ordnername, Korrespondent aus Absender – Ausnahme `Sent`: keiner) → **Delete** = Ordner-Label entfernen (Mail → „All Mail"). Bereits verarbeitete Mails erkennt Paperless an der UID (kein Doppel-Import).
**Im Alltag:** Eine Mail in Proton in einen der 15 Ordner verschieben → innerhalb von **10 Min** in Paperless (mit Tag) und aus dem Ordner verschwunden. Kein manueller Schritt nötig.
**Sofort statt warten:** In der Weboberfläche *Einstellungen → E-Mail* beim Konto „Ausführen", oder am Host `docker compose exec --user paperless webserver python manage.py mail_fetch`.
## Wiederherstellung / Neuaufbau
- **Bridge (CT 100):** Der LXC ist ein eigener Gast → vom Proxmox-Backup (vzdump) wiederherstellbar. Nach Restore ggf. `protonmailbridge-configure` erneut (Login+2FA), dann `exit` → Dienst/Sockets aktiv.
- **Paperless-Seite:** `certs/proton-bridge.pem`, der Sidecar-Dienst und die Env-Zeile stecken in `docker-compose.yml`/`.env` (im vzdump von CT 110 enthalten). Ändert sich das Bridge-Zertifikat (Neuaufbau der Bridge), muss `proton-bridge.pem` neu exportiert werden (Schritt 4).
## Sicherheit
Proton-Login und das Bridge-IMAP-Passwort **kommen nicht ins Vault** (Projektregel 6) – **generiert, separat übermittelt**. In Paperless liegt das Bridge-Passwort verschlüsselt in der DB (nötig für den Abruf); das ist kein Vault-Inhalt.
## Quellen
- Proxmox VE Helper-Scripts – *Proton Mail Bridge*, `community-scripts.org/scripts/protonmail-bridge`: LXC-Default Debian 13 (2 Kerne/1024 MB/8 GB), headless-Bridge, `systemd-socket-proxyd` (IMAP 143 → 127.0.0.1:1143), Erstsetup `protonmailbridge-configure` – Zugriff 22.07.2026
- Proton – *Bridge for Linux*, `proton.me/support/bridge-for-linux`: Bridge nur mit kostenpflichtigem Plan, Secret-Store (`pass`/GPG) – Zugriff 21.07.2026
- Eigene Prüfung am laufenden System (24.07.2026): Bridge-Zertifikat `CN=127.0.0.1, SAN IP 127.0.0.1`, Zertifikat verschlüsselt in `bridge-v3/vault.enc` (keine austauschbare `cert.pem`); Paperless `paperless_mail/mail.py` `get_mailbox()` nutzt `create_default_context()` + optional `EMAIL_CERTIFICATE_FILE`, Setting-Name `PAPERLESS_EMAIL_CERTIFICATE_LOCATION`; Duplikatprüfung `documents/consumer.py` per `hashlib.md5` gegen `checksum`/`archive_checksum`; **Abrufzeitplan** `settings.CELERY_BEAT_SCHEDULE` „Check all e-mail accounts" = `paperless_mail.tasks.process_mail_accounts`, Crontab `*/10 * * * *`, `PAPERLESS_EMAIL_TASK_CRON` nicht gesetzt (Standard)
---
**Status:** Bridge produktiv, Paperless-Anbindung steht (Konto + 15 Regeln), Erstimport abgeschlossen, laufender Abruf alle 10 Min
**Version:** 1.3
**Letzte Aktualisierung:** 25.07.2026, 12:08 Uhr
### Änderungshistorie
| Version | Datum | Uhrzeit | Änderung |
|---|---|---|---|
| 1.3 | 25.07.2026 | 12:08 | **Kritischer Fallstrick ergänzt:** Ein `webserver`-Neustart reißt den socat-Sidecar `proton-imap-proxy` mit (gemeinsamer Netz-Namespace) → Proton-IMAP `127.0.0.1:143` tot, bis der Sidecar ebenfalls neu gestartet wird. Am 25.07. real aufgetreten (webserver-Neustart als Consumer-Fix legte Proton lahm), per `docker compose restart proton-imap-proxy` behoben |
| 1.2 | 25.07.2026 | 08:02 | **Gesendet-Ordner ergänzt.** 15. Regel „Proton: Gesendet" (Ordner `Sent`, Tag `Gesendet`, Stufe 3, Aktion Delete, **kein Korrespondent** – Empfänger als Korrespondent von Paperless nicht unterstützt). Datenfluss/Betrieb/Status auf 15 Regeln aktualisiert. 576 Sent-Mails werden per regulärem 10-Min-Abruf importiert |
| 1.1 | 24.07.2026 | 21:24 | Abschnitt **„Betrieb – wann und wie der Import läuft"** ergänzt: automatischer Abruf alle 10 Min (Celery-Beat `*/10 * * * *`, `PAPERLESS_EMAIL_TASK_CRON` nicht gesetzt = Standard; am System verifiziert), Voraussetzung Bridge läuft, Ablauf je Lauf, manuelles Sofort-Auslösen. Stand/Status auf „Erstimport abgeschlossen" gesetzt |
| 1.0 | 24.07.2026 | 14:15 | Erstfassung. Bridge-Installation und Paperless-Anbindung aus [[11-E-Mail-Postfaecher]] ausgegliedert und auf den **tatsächlich umgesetzten** Stand gebracht: CT 100 (Community-Script), Login+2FA, headless-Dienst, LAN-Socket-Proxy, **socat-Sidecar + `PAPERLESS_EMAIL_CERTIFICATE_LOCATION`** als Lösung für das 127.0.0.1-Zertifikat, Konto + Regeln. Fallstricke dokumentiert (paperless-User, O365↔Proton getrennt, Anhang-Dedup, Delete=Entlabeln) |
---
[[Impressum|Impressum]] | [[Datenschutzerklärung|Datenschutz]]