Ugh. Not a good start for a service I just decided to switch fully to.
The tl;dr is basically because of e2ee, ProtonMail Bridge needs to be installed to act as both an SMTP server for sending mail back to Proton, and an IMAP server for your third-party client to connect to. It doesn’t work like traditional email services that have less in the way of encryption.
This, given Proton’s e2ee, is understandable. What I don’t understand is why they refuse to implement a toggle for users like me (and many others that I have seen while digging for a solution). Folks with robust home setups and VPN connections, to have bridge running on the LAN as an SMTP/IMAP server accessible by multiple devices. Proton’s answer is frustratingly: lol recompile it.
You see, bridge is intended to be run on the same end-device that your email client is running on, with no way around that functionality outside of compiling from source. There are a couple issues with this, assuming I do not wish to compile from source (I do not and I will not):
- If I want to run on multiple devices, I have to set up the bridge on all said devices.
- (the main issue) there is no bridge for Android, meaning I am locked into their first-party app.
So I ended up doing some digging and cobbling together a few guides to get a working setup. (It also disappoints me how sparse their first-party documentation is. They really want you to use their first-party apps.)
The gist:
- Spin up a dedicated VM on the LAN, accessible via VPN tunnel, to handle this. (This served as my test drive of Debian 13.)
- Install and configure ProtonMail Bridge under a dedicated locked user.
- Set up
socat
to handle forwarding the localhost ports that Proton exposes to the standard STMP and IMAP ports. - Enable the above - Bridge and
socat
- assystemd
services.
I’m glad I decided to try this out before really committing to ProtonMail as my main provider. It makes me more hesitant. I realize now that I likely don’t want to host my own at this point, but if simply getting into my damn email is this difficult - and not just because of the security aspect, but because the company itself just doesn’t feel like implementing a simple toggle for certain users - then I’m not sure this is the best choice long-term.
Then again, it’s the only option I’ve got where the provider can’t just peruse my emails whenever they wish.
I followed these guides:
Spin up a dedicated VM
Basically follow the instructions here, omitting a couple things such as changing the SSH port (no need when it’s a local server) and configuring ufw
(if you do this you will need to allow different ports).
Install necessary packages
apt install dnsutils net-tools socat pass libxcb-cursor0 libsecret-1-0 libpulse-mainloop-glib0 fonts-dejavu
All the guides I was using were out of date in one way or another so this list of packages is probably not fully correct. YMMV. I had to scan the output of a failed command (either when I tried to install the given ones, or when starting ProtonMail Bridge) to glean what packages I should install. I also had to run apt --fix-broken install
.
Install ProtonMail Bridge
I need to refresh how to check package signatures, I was lazy this time. Do that.
wget https://github.com/ProtonMail/proton-bridge/releases/download/{tag}/{filename}
dpkg -i protonmail-bridge*.deb
Create proton user
useradd -m proton
usermod -L proton
Would also recommend changing shell and grabbing configs from the primary user - won’t be using this user much, but enough to warrant some QoL.
Setup pass
Copied from here
su proton
cd
script /dev/null # https://bugzilla.redhat.com/show_bug.cgi?id=659512
gpg --full-generate-key
>>>> Choose 1 (1) RSA and RSA (default)
>>>> Choose 2048 (default)
>>>> Choose 0 0 = key does not expire
>>>> Type your name e.g. Proty McProtonFace
>>>> Type your email e.g. a@a.com
>>>> Leave empty comment
>>>> Leave empty passphrase
gpg --list-keys
pass init user@email.com
Set up ProtonMail Bridge CLI
Copied from here
protonmail-bridge --cli
>>>> add (add your protonmail account to bridge)
>>>> (enter your protonmail account email address)
>>>> (enter your protonmail account password)
>>>> list (list configured accounts)
>>>> info (list SMTP credentials for configuring any local SMTP compatible service)
>>>> help (get familiarized with the bridge options)
>>>> exit (exit the bridge console which stops the local SMTP server created)
Set up systemd units
Here’s where I break from the original guide I found and use the second guide, which handles the socat
. The Bridge systemd
service is mentioned in the Github gist, but I had to figure it out.
Bridge
This will start the ProtonMail Bridge client on startup, under the proton
user.
# /etc/systemd/system/protonmail-bridge.service
[Unit]
Description=ProtonMail Bridge
After=network.target
[Service]
User=proton
Group=proton
ExecStart=protonmail-bridge --noninteractive > /home/proton/bridge.log 2>&1
Restart=always
[Install]
WantedBy=multi-user.target
systemctl start protonmail
systemctl status protonmail
systemctl enable protonmail
socat
SMTP port mapping
# /etc/systemd/system/proton-socat-smtp.service
[Unit]
Description=Socat service for Proton Bridge SMTP port forwarding
After=protonmail-bridge.target
[Service]
ExecStart=/usr/bin/socat TCP4-LISTEN:587,fork TCP4:127.0.0.1:1025
Restart=always
[Install]
WantedBy=multi-user.target
systemctl start proton-socat-smtp
systemctl status proton-socat-smtp
systemctl enable proton-socat-smtp
socat
IMAP
# /etc/systemd/system/proton-socat-imap.service
[Unit]
Description=Socat service for Proton Bridge IMAP port forwarding
After=protonmail-bridge.target
[Service]
ExecStart=/usr/bin/socat TCP4-LISTEN:143,fork TCP4:127.0.0.1:1143
Restart=always
[Install]
WantedBy=multi-user.target
systemctl start proton-socat-imap
systemctl status proton-socat-imap
systemctl enable proton-socat-imap
Connect!
Follow-up - a day after
So this works, the only thing I dislike in this configuration (outside of what I have already stated about Proton’s unwillingness to put more development time into Bridge) is the fact that it uses a self-signed certificate.
I understand that my risk is low, given that I am running this on a home server through a VPN tunnel, and MitM attacks are unlikely. I did go ahead and set a local DNS record so that when I’m disconnected from my VPN I simply get a DNS timeout instead of trying to connect to an IP address - even though it’s highly unlikely I’ll ever run into that IP address in the wild.
I don’t fully understand how this works, but I tried to run an Nginx proxy to forward the ports instead of the given socat
solution, and it simply wouldn’t connect. My idea with this was to generate a certificate using a DNS challenge, like I have set up for my main server running all my services in Docker - eliminating the self-signed issue. I didn’t dig into it too deeply, as I figured it was more likely that I was going about it entirely the wrong way than it was that I had a simple misconfiguration. My theory - knowing little about Nginx - is one of two things. 1) The proxy is HTTP-only (made evident by the “invalid URL prefix” when I put anything other than http://
or https://
after the proxy_pass
directive) or 2) Bridge using its own certificate causes issues somewhere along the line. Or, it could be something else entirely.
I did find several tutorials mentioning stream proxying (if that’s the term) and a mail {}
directive in Nginx, but I believe those require different Nginx modules and I wasn’t about to fuck with it.
I’m 90% satisfied with this configuration - so far. Much better than being locked into the first-party app, and it shouldn’t require much if any maintenance.
EOF