https://github.com/springcomp/self-hosted-simplelogin
Docker-based self-hosted SimpleLogin.io configuration
https://github.com/springcomp/self-hosted-simplelogin
Last synced: 5 months ago
JSON representation
Docker-based self-hosted SimpleLogin.io configuration
- Host: GitHub
- URL: https://github.com/springcomp/self-hosted-simplelogin
- Owner: springcomp
- Created: 2023-07-22T09:17:59.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2026-01-04T10:29:16.000Z (6 months ago)
- Last Synced: 2026-01-26T22:11:45.461Z (5 months ago)
- Language: Smarty
- Size: 202 KB
- Stars: 81
- Watchers: 5
- Forks: 18
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# SimpleLogin
This is a self-hosted docker-compose configuration for [SimpleLogin](https://simplelogin.io).
## Prerequisites
- a Linux server (either a VM or dedicated server). This doc shows the setup for Ubuntu 18.04 LTS but the steps could be adapted for other popular Linux distributions. As most of components run as Docker container and Docker can be a bit heavy, having at least 2 GB of RAM is recommended. The server needs to have the port 25 (email), 80, 443 (for the webapp), 22 (so you can ssh into it) open.
- a domain for which you can config the DNS. It could be a sub-domain. In the rest of the doc, let's say it's `mydomain.com` for the email and `app.mydomain.com` for SimpleLogin webapp. Please make sure to replace these values by your domain name and subdomain name whenever they appear in the doc. A trick we use is to download this README file on your computer and replace all `mydomain.com` and `app.mydomain.com` occurrences by your domain.
Except for the DNS setup that is usually done on your domain registrar interface, all the below steps are to be done on your server. The commands are to run with `bash` (or any bash-compatible shell like `zsh`) being the shell. If you use other shells like `fish`, please make sure to adapt the commands.
- Some utility packages used to verify the setup. Install them by:
```bash
sudo apt update \
&& sudo apt install -y net-tools dnsutils
```
## DNS Configuration
> **Please note** that DNS changes could take up to 24 hours to propagate. In practice, it's a lot faster though (~1 minute or so in our test). In DNS setup, we usually use domain with a trailing dot (`.`) at the end to to force using absolute domain.
### A record
Create an **A record** that points `app.mydomain.com.` to your server IP.
To verify, the following command:
```bash
dig @1.1.1.1 app.mydomain.com a
```
should return your server IP.
### MX record
Create a **MX record** that points `mydomain.com.` to `app.mydomain.com.` with priority 10.
To verify if the DNS works, the following command:
```bash
dig @1.1.1.1 mydomain.com mx
```
should return:
```dns
mydomain.com. 3600 IN MX 10 app.mydomain.com.
```
### PTR record
From Wikipedia
> A reverse DNS lookup or reverse DNS resolution (rDNS) is the querying technique of the Domain Name System (DNS) to determine the domain name associated with an IP address – the reverse of the usual "forward" DNS lookup of an IP address from a domain name.
Create a **PTR record** that point your IP address to your domain name.
**Important** Some providers require PTR configuration to be done from their dashboard and ignore DNS records. Please, make sure to properly configure reverse DNS lookup for your domain.
To verify, the following command:
```bash
dig @1.1.1.1 -x $( ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)
```
should return your domain name.
### DKIM
From Wikipedia
> DomainKeys Identified Mail (DKIM) is an email authentication method designed to detect forged sender addresses in emails (email spoofing), a technique often used in phishing and email spam.
Setting up DKIM is highly recommended to reduce the chance for your emails ending up in the recipient's Spam folder.
First you need to generate a private and public key for DKIM:
```bash
openssl genrsa -traditional -out dkim.key 1024
openssl rsa -in dkim.key -pubout -out dkim.pub.key
```
You will need the files `dkim.key` and `dkim.pub.key` for the next steps.
For email gurus, we have chosen 1024 key length instead of 2048 for DNS simplicity as some registrars don't play well with long TXT record.
Set up DKIM by adding a **TXT record** for `dkim._domainkey.mydomain.com.` with the following value:
```plaintext
v=DKIM1; k=rsa; p=PUBLIC_KEY
```
with `PUBLIC_KEY` being your `dkim.pub.key` but
- remove the `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----`
- join all the lines on a single line.
For example, if your `dkim.pub.key` is
```plaintext
-----BEGIN PUBLIC KEY-----
ab
cd
ef
gh
-----END PUBLIC KEY-----
```
then the `PUBLIC_KEY` would be `abcdefgh`.
You can get the `PUBLIC_KEY` by running this command:
```bash
sed "s/-----BEGIN PUBLIC KEY-----/v=DKIM1; k=rsa; p=/g" $(pwd)/dkim.pub.key | \
sed 's/-----END PUBLIC KEY-----//g' | \
tr -d '\n' | awk 1
```
To verify, the following command:
```bash
dig @1.1.1.1 dkim._domainkey.mydomain.com txt
```
should return the above value.
### SPF
From Wikipedia
> Sender Policy Framework (SPF) is an email authentication method designed to detect forging sender addresses during the delivery of the email
Similar to DKIM, setting up SPF is highly recommended.
Create a **TXT record** for `mydomain.com.` with the value:
```plaintext
v=spf1 mx -all
```
What it means is only your server can send email with `@mydomain.com` domain.
To verify, the following command
```bash
dig @1.1.1.1 mydomain.com txt
```
should return the above value.
### DMARC
From Wikipedia
> It (DMARC) is designed to give email domain owners the ability to protect their domain from unauthorized use, commonly known as email spoofing
Setting up DMARC is also recommended.
Create a **TXT record** for `_dmarc.mydomain.com.` with the following value
```plaintext
v=DMARC1; p=quarantine; adkim=r; aspf=r
```
This is a `relaxed` DMARC policy. You can also use a more strict policy with `v=DMARC1; p=reject; adkim=s; aspf=s` value.
To verify, the following command
```bash
dig @1.1.1.1 _dmarc.mydomain.com txt
```
should return the set value.
For more information on DMARC, please consult
### HSTS
From Wikipedia
> HTTP Strict Transport Security (HSTS) is a policy mechanism that helps to protect websites against man-in-the-middle attacks such as protocol downgrade attacks and cookie hijacking.
HTTP Strict Transport Security is an extra step you can take to protect your web app from certain man-in-the-middle attacks. It does this by specifying an amount of time (usually a really long one) for which you should only accept HTTPS connections, not HTTP ones.
This repository already enables HSTS, thanks to the traefik configuration for the simplelogin container
### CAA
From Wikipedia
> DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism that allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name.
[Certificate Authority Authorization](https://letsencrypt.org/docs/caa/) is a step you can take to restrict the list of certificate authorities that are allowed to issue certificates for your domains.
Use [SSLMate’s CAA Record Generator](https://sslmate.com/caa/) to create a **CAA record** with the following configuration:
- `flags`: `0`
- `tag`: `issue`
- `value`: `"letsencrypt.org"`
To verify if the DNS works, the following command:
```bash
dig @1.1.1.1 mydomain.com caa
```
should return:
```dns
mydomain.com. 3600 IN CAA 0 issue "letsencrypt.org"
```
**Warning**: setting up a CAA record will restrict which certificate authority can successfully issue SSL certificates for your domain.
This will prevent certificate issuance from Let’s Encrypt staging servers. You may want to differ this DNS record until after SSL certificates are successfully issued for your domain.
### MTA-STS
From Wikipedia
> SMTP MTA Strict Transport Security defines a protocol for mail servers to declare their ability to use secure channels in specific files on the server and specific DNS TXT records.
[SMTP MTA Strict Transport Security](https://datatracker.ietf.org/doc/html/rfc8461) is an extra step you can take to broadcast the ability of your instance to receive and, optionally enforce, TSL-secure SMTP connections to protect email traffic.
Create an **A record** that points `mta-sts.mydomain.com.` to your server IP.
To verify, the following command:
```bash
dig @1.1.1.1 mta-sts.mydomain.com a
```
should return your server IP.
Create a **TXT record** for `_mta-sts.mydomain.com.` with the following value:
```plaintext
v=STSv1; id=UNIX_TIMESTAMP
```
With `UNIX_TIMESTAMP` being the current date/time.
Use the following command to generate the record:
```bash
echo "v=STSv1; id=$(date +%s)"
```
To verify if the DNS works, the following command:
```bash
dig @1.1.1.1 _mta-sts.mydomain.com txt
```
should return a result similar to this one:
```dns
_mta-sts.mydomain.com. 3600 IN TXT "v=STSv1; id=1689416399"
```
### TLSRPT
[SMTP TLS Reporting](https://datatracker.ietf.org/doc/html/rfc8460) is used by SMTP systems to report failures in establishing TLS-secure sessions as broadcast by the MTA-STS configuration.
Configuring MTA-STS in `mode: testing` as shown in the previous section gives you time to review failures from some SMTP senders.
Create a **TXT record** for `_smtp._tls.mydomain.com.` with the following value:
```txt
v=TSLRPTv1; rua=mailto:YOUR_EMAIL
```
The TLSRPT configuration at the DNS level allows SMTP senders that fail to initiate TLS-secure sessions to send reports to a particular email address. We suggest creating a `tls-reports` alias in SimpleLogin for this purpose.
To verify if the DNS works, the following command
```bash
dig @1.1.1.1 _smtp._tls.mydomain.com txt
```
should return a result similar to this one:
```dns
_smtp._tls.mydomain.com. 3600 IN TXT "v=TSLRPTv1; rua=mailto:tls-reports@mydomain.com"
```
## Docker
If you don't already have Docker installed on your server, please follow the steps on [Docker CE for Ubuntu](https://docs.docker.com/v17.12/install/linux/docker-ce/ubuntu/) to install Docker.
You can also install Docker using the [docker-install](https://github.com/docker/docker-install) script which is
```bash
curl -fsSL https://get.docker.com | sh
```
Enable IPv6 for [the default bridge network](https://docs.docker.com/config/daemon/ipv6/#use-ipv6-for-the-default-bridge-network)
```json
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64",
"experimental": true,
"ip6tables": true
}
```
This procedure will guide you through running the entire stack using Docker containers.
This includes:
- traefik
- The [SimpleLogin app](https://github.com/simple-login/app) containers
- postfix
Run SimpleLogin from Docker containers:
1. Clone this repository in `/opt/simplelogin`
1. Copy `.env.example` to `.env` and set appropriate values.
- set the `DOMAIN` variable to your domain.
- set the `SUBDOMAIN` variable to your domain. The default value is `app`.
- set the `POSTGRES_USER` variable to match the postgres credentials (when starting from scratch, use `simplelogin`).
- set the `POSTGRES_PASSWORD` to match the postgres credentials (when starting from scratch, set to a random key).
- set the `FLASK_SECRET` to an arbitrary secret key.
#### Running the application
Run the application using the following commands:
```sh
docker compose up --detach --remove-orphans --build && docker compose logs -f
```
You may want to setup [Certificate Authority Authorization (CAA)](#caa) at this point.
## Next steps
If all the above steps are successful, open and create your first account!
By default, new accounts are not premium so don't have unlimited aliases. To make your account premium,
please go to the database, table "users" and set "lifetime" column to "1" or "TRUE":
```bash
docker compose exec -it postgres psql -U myuser simplelogin
> UPDATE users SET lifetime = TRUE;
> \q
```
Once you've created all your desired login accounts, add these lines to `.env` to disable further registrations:
```env
DISABLE_REGISTRATION=1
DISABLE_ONBOARDING=true
```
Then, to restart the web app, apply: `docker compose restart app`
## Miscellaneous
### Wildcard subdomains
**Note** the following section documents wildcard certificates and subdomains. You may want to use builtin facility within SimpleLogin to achieve the same results.
If your DNS supports it, you can add a **MX record** to point `*.mydomain.com` to `app.mydomain.com` so that you can receive mails from any number of subdomains.
To verify, the following command:
```sh
dig @1.1.1.1 *.mydomain.com mx
```
Should return:
```dns
*.mydomain.com. 3600 IN MX 10 app.mydomain.com
```
SSL-Certificates are requested from [Let`s Encrypt](https://letsencrypt.org/).
Traefik is (by default) configured to use TLS-ALPN Challenge, because this works out-of-the-box without further
configuration, as long as DNS resolves to your server.
Disadvantage of this configuration is, that letsencrypt does not allow requesting wildcard certificates via TLS Challenge.
To request a wildcard certificate, edit `.env` file to set `LE_CHALLENGE=dns`, identify your DNS provider
by setting `LE_DNS_PROVIDER`, and provide further details (i.e. credentials/API-Key, depending on your DNS provider) as ENV.
You can find all supported DNS providers and corresponding instructions here:
### Postfix configuration - Spamhaus
The Spamhaus Project maintains a reliable list of IP addresses known to be the source of SPAM.
You can check whether a given IP address is in that list by submitting queries to the DNS infrastructure.
Since Spamhaus blocks queries coming from public (open) DNS-Resolvers (see: https://check.spamhaus.org/returnc/pub) and your postfix container may use
a public resolver by default, it is recommended to sign up for the free
[Spamhaus Data Query Service](https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account/)
and obtain a Spamhaus DQS key.
Paste this key as `SPAMHAUS_DQS_KEY` in your `.env`
If no DQS-key is provided, your postfix container will check if the Spamhaus public mirrors are accepting its queries and use them instead.
If Spamhaus rejects queries from your postfix container to the public mirrors, it will be disabled entirely.
### Postfix configuration - Virtual aliases
The postfix configuration supports virtual aliases using the `postfix/conf.d/virtual` and `postfix/conf.d/virtual-regexp` files.
Those files are automatically created on startup based upon the corresponding [`postfix/templates/virtual.tpl`](./postfix/templates/virtual.tpl)
and [`postfix/templates/virtual-regexp.tpl`](./postfix/templates/virtual-regexp.tpl) template files.
The default configuration is as follows:
#### virtual.tpl
The `virtual` file supports postfix `virtual_alias_maps` settings.
It includes a rule that maps `unknown@mydomain.com` to `contact@mydomain.com` to demonstrate receiving
and email from a specific address that does not correspond to an existing alias, to another one that does.
```postfix-conf
unknown@mydomain.com contact@mydomain.com
```
#### virtual-regexp.tpl
The `virtual-regexp` file supports postfix `virtual_alias_maps` settings.
It includes a rule that rewrite emails addressed to an arbitrary subdomain, which does not correspond
to an existing alias, to a new alias that belongs to a directory whose name is taken from the subdomain.
That alias may be created on the fly if it does not exist.
```postfix-conf
/^([^@]+)@([^.]+)\.mydomain.com/ $2/$1@mydomain.com
```
For instance, emails sent to `someone@directory.mydomain.com` will be routed to `directory/someone@mydomain.com` by postfix.
## How-to Upgrade from 3.4.0
- Change the image version in `.env`
```env
SL_VERSION=4.6.5-beta
```
- Check and apply [migration commands](https://github.com/simple-login/app/blob/master/docs/upgrade.md)
For instance, to upgrade from `3.4.0` to `4.6.x-beta`, the following change must be done in `simple-login-compose.yaml`:
```patch
migration:
image: simplelogin/app:$SL_VERSION
- command: [ "flask", "db", "upgrade" ]
+ command: [ "alembic", "upgrade", "head" ]
container_name: sl-migration
env_file: .env
```
Finally, the following command must be run in the database:
```bash
docker compose exec -it postgres psql -U myuser simplelogin
> UPDATE email_log SET alias_id=(SELECT alias_id FROM contact WHERE contact.id = email_log.contact_id);
> \q
```
- Restart containers
```sh
docker compose stop && docker compose up --detach
```
After successfully upgrading to `v4.6.x-beta` you might want to upgrade
to the latest stable version. Change the `SL_IMAGE` and `SL_VERSION`
variables from the `.env` file:
```env
SL_VERSION=v4.70.0
SL_IMAGE=app-ci
```
**Caution**: some [underpowered VPS](https://github.com/springcomp/self-hosted-simplelogin/issues/12#issuecomment-3160394621) might exhibit some WORKER_TIMEOUT errors
when running the `sl-app` image. To mitigate this issue, you may want to
increase the starting timeout value in [`simple-login-compose.yaml`](https://github.com/springcomp/self-hosted-simplelogin/blob/main/simple-login-compose.yaml#L49):
```patch
app:
image: simplelogin/$SL_IMAGE:$SL_VERSION
container_name: sl-app
env_file: .env
volumes:
- ./pgp:/sl/pgp
- ./upload:/code/static/upload
- ./dkim.key:/dkim.key
- ./dkim.pub.key:/dkim.pub.key
+ command: ["gunicorn","wsgi:app","-b","0.0.0.0:7777","-w","2","--timeout","30"]
restart: unless-stopped
```
And restart the containers.
This will pull up the latest versions of the docker images,
potentially running the updated `sl-migration` steps, and
startup the application.
## How-to Upgrade from previous NGinx-based setup
This section outlines the migration steps from a previous installation of `self-hosted-simplelogin` using the NGinx-based setup, to the current Traefik-based setup.
### Backup your server
1. Backup the database using the following command:
```powershell
mkdir /tmp/sl-backup/
docker compose \
-f /opt/simplelogin/docker-compose.yaml exec postgres \
pg_dump -U simplelogin -F c -b >/tmp/sl-backup/simplelogin.sql
```
1. Backup your DKIM public and private keys.
1. Backup your PGP keys, avatar picture and undelivered emails from the `upload/` and `pgp/` folders.
1. Backup your existing `.env` file.
### Postfix
The `postfix` container is running a private image that has changed from the previous NGinx-based setup to the current Traefik-based setup.
That image needs to be regenerated. You can remove the previous version using the command:
```sh
docker rmi private/postfix:latest
```
### In-place upgrade
In-place upgrade refers to the fact that you will upgrade the stack from the previous setup to the current setup in the same directoy.
This is the easiest upgrade path as you only need to change the docker-compose and setup files. If you cloned this repository, you most likely need to use `git pull` to upgrade to the latest version.
**Prerequisites**: make sure you are running a recent version of SimpleLogin. This section assumes you are running `app-ci:v4.70.0`.
1. Stop the stack using `. ./down.sh`.
1. Upgrade to the latest version of the files.
1. Create and update the `.env` file from `.env.example`.
The new `.env` file supports specifying parameters for certificate renewal using either the `DNS-01` or `TLS–ALPN-01` ACME challenge from Let’sEncrypt using [LEGO](https://go-acme.github.io/lego/dns/) , a Let’sEncrypt client library written in Go. Please, review the LEGO documentation for supported providers and their parameters.
4. Start the stack using `. ./up.sh`.
You can now cleanup the folders that are no longer useful:
```sh
rm -rf acme.sh/
rm -rf nginx/
```
### Backup / restore upgrade
If you want to keep the existing setup in a known working directory, you can use the backup - restore path to test the new setup from a separate folder.
1. Clone this repository to get the latest version of the files.
1. Create and update the `.env` file from `.env.example`.
The new `.env` file supports specifying parameters for certificate renewal using either the `DNS-01` or `TLS–ALPN-01` ACME challenge from Let’sEncrypt using [LEGO](https://go-acme.github.io/lego/dns/) , a Let’sEncrypt client library written in Go. Please, review the LEGO documentation for supported providers and their parameters.
3. Restore the `pgp/` and `upload/` folders.
3. Restore the `dkim.pub.key` and `dkim.key` files.
3. Restore the postfix `virtual` and `virtual-regexp` files.
4. Start the stack using `. ./up.sh`.
This will create the `private/postfix:latest` image and request new certificates from Let’s Encrypt.
Once the application is running successfully, you need to restore the database. The easiest way it to copy the backup file in the `db/` folder:
```sh
sudo cp /tmp/sl-backup/simplelogin.sql db/
docker compose exec -it pg_restore -U \
--dbname=simplelogin \
--clean \
--verbose \
/var/lib/postgresql/data/simplelogin.sql
```