This is a self-hosted docker-compose configuration for SimpleLogin.
-
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.comfor the email andapp.mydomain.comfor 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 allmydomain.comandapp.mydomain.comoccurrences 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:
sudo apt update \
&& sudo apt install -y net-tools dnsutilsPlease 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.
Create an A record that points app.mydomain.com. to your server IP.
To verify, the following command:
dig @1.1.1.1 app.mydomain.com ashould return your server IP.
Create a MX record that points mydomain.com. to app.mydomain.com. with priority 10.
To verify if the DNS works, the following command:
dig @1.1.1.1 mydomain.com mxshould return:
mydomain.com. 3600 IN MX 10 app.mydomain.com.
From Wikipedia https://en.wikipedia.org/wiki/Reverse_DNS_lookup
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:
dig @1.1.1.1 -x $( ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)should return your domain name.
From Wikipedia https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail
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:
openssl genrsa -traditional -out dkim.key 1024
openssl rsa -in dkim.key -pubout -out dkim.pub.keyYou 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:
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
-----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:
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 1To verify, the following command:
dig @1.1.1.1 dkim._domainkey.mydomain.com txtshould return the above value.
From Wikipedia https://en.wikipedia.org/wiki/Sender_Policy_Framework
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:
v=spf1 mx -all
What it means is only your server can send email with @mydomain.com domain.
To verify, the following command
dig @1.1.1.1 mydomain.com txtshould return the above value.
From Wikipedia https://en.wikipedia.org/wiki/DMARC
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
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
dig @1.1.1.1 _dmarc.mydomain.com txtshould return the set value.
For more information on DMARC, please consult https://tools.ietf.org/html/rfc7489
From Wikipedia https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
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
From Wikipedia https://en.wikipedia.org/wiki/DNS_Certification_Authority_Authorization
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 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 to create a CAA record with the following configuration:
flags:0tag:issuevalue:"letsencrypt.org"
To verify if the DNS works, the following command:
dig @1.1.1.1 mydomain.com caashould return:
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.
From Wikipedia https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security
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 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:
dig @1.1.1.1 mta-sts.mydomain.com ashould return your server IP.
Create a TXT record for _mta-sts.mydomain.com. with the following value:
v=STSv1; id=UNIX_TIMESTAMP
With UNIX_TIMESTAMP being the current date/time.
Use the following command to generate the record:
echo "v=STSv1; id=$(date +%s)"To verify if the DNS works, the following command:
dig @1.1.1.1 _mta-sts.mydomain.com txtshould return a result similar to this one:
_mta-sts.mydomain.com. 3600 IN TXT "v=STSv1; id=1689416399"
SMTP TLS Reporting 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:
v=TSLRPTv1; rua=mailto:YOUR_EMAILThe 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
dig @1.1.1.1 _smtp._tls.mydomain.com txtshould return a result similar to this one:
_smtp._tls.mydomain.com. 3600 IN TXT "v=TSLRPTv1; rua=mailto:tls-reports@mydomain.com"
If you don't already have Docker installed on your server, please follow the steps on Docker CE for Ubuntu to install Docker.
You can also install Docker using the docker-install script which is
curl -fsSL https://get.docker.com | shEnable IPv6 for the default bridge network
{
"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 containers
- postfix
Run SimpleLogin from Docker containers:
-
Clone this repository in
/opt/simplelogin -
Copy
.env.exampleto.envand set appropriate values.- set the
DOMAINvariable to your domain. - set the
SUBDOMAINvariable to your domain. The default value isapp. - set the
POSTGRES_USERvariable to match the postgres credentials (when starting from scratch, usesimplelogin). - set the
POSTGRES_PASSWORDto match the postgres credentials (when starting from scratch, set to a random key). - set the
FLASK_SECRETto an arbitrary secret key.
- set the
Run the application using the following commands:
docker compose up --detach --remove-orphans --build && docker compose logs -fYou may want to setup Certificate Authority Authorization (CAA) at this point.
If all the above steps are successful, open https://app.mydomain.com/ 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":
docker compose exec -it postgres psql -U myuser simplelogin
> UPDATE users SET lifetime = TRUE;
> \qOnce you've created all your desired login accounts, add these lines to .env to disable further registrations:
DISABLE_REGISTRATION=1
DISABLE_ONBOARDING=trueThen, to restart the web app, apply: docker compose restart app
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:
dig @1.1.1.1 *.mydomain.com mxShould return:
*.mydomain.com. 3600 IN MX 10 app.mydomain.com
SSL-Certificates are requested from Let`s Encrypt. 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: https://go-acme.github.io/lego/dns/
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
and postfix/templates/virtual-regexp.tpl template files.
The default configuration is as follows:
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.
unknown@mydomain.com contact@mydomain.com
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.
/^([^@]+)@([^.]+)\.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.
- Change the image version in
.env
SL_VERSION=4.6.5-beta- Check and apply migration commands
For instance, to upgrade from 3.4.0 to 4.6.x-beta, the following change must be done in simple-login-compose.yaml:
migration:
image: simplelogin/app:$SL_VERSION
- command: [ "flask", "db", "upgrade" ]
+ command: [ "alembic", "upgrade", "head" ]
container_name: sl-migration
env_file: .envFinally, the following command must be run in the database:
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
docker compose stop && docker compose up --detachAfter 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:
SL_VERSION=v4.70.0
SL_IMAGE=app-ciCaution: some underpowered VPS 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:
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-stoppedAnd 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.
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 the database using the following command:
mkdir /tmp/sl-backup/
docker compose \
-f /opt/simplelogin/docker-compose.yaml exec postgres \
pg_dump -U <postgres-user-name> simplelogin -F c -b >/tmp/sl-backup/simplelogin.sql-
Backup your DKIM public and private keys.
-
Backup your PGP keys, avatar picture and undelivered emails from the
upload/andpgp/folders. -
Backup your existing
.envfile.
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:
docker rmi private/postfix:latestIn-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.
- Stop the stack using
. ./down.sh. - Upgrade to the latest version of the files.
- Create and update the
.envfile 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 , a Let’sEncrypt client library written in Go. Please, review the LEGO documentation for supported providers and their parameters.
- Start the stack using
. ./up.sh.
You can now cleanup the folders that are no longer useful:
rm -rf acme.sh/
rm -rf nginx/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.
- Clone this repository to get the latest version of the files.
- Create and update the
.envfile 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 , a Let’sEncrypt client library written in Go. Please, review the LEGO documentation for supported providers and their parameters.
- Restore the
pgp/andupload/folders. - Restore the
dkim.pub.keyanddkim.keyfiles. - Restore the postfix
virtualandvirtual-regexpfiles. - 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:
sudo cp /tmp/sl-backup/simplelogin.sql db/
docker compose exec -it pg_restore -U <postgres-user-name> \
--dbname=simplelogin \
--clean \
--verbose \
/var/lib/postgresql/data/simplelogin.sql