• Stars
    star
    663
  • Rank 67,991 (Top 2 %)
  • Language
    JavaScript
  • License
    Other
  • Created almost 5 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Privacy-focused encrypted email for everyone.

ForwardEmail

build status code style styled with prettier license

Forward Email is the 100% open-source and privacy-focused email service @ https://forwardemail.net.

Table of Contents

How do I get started

For Consumers

Visit https://forwardemail.net to get started!

For Developers

See Requirements below.

Requirements

macOS

  1. You should have brew and node installed. We recommend installing Node.js with n (e.g. n lts).

  2. Install brew dependencies:

    brew tap mongodb/brew
    brew install mongodb-community redis ansible ansible-lint libtool automake autoconf nasm
    brew services start mongodb-community
    brew services start redis
  3. Install ansible-galaxy requirements (assumes current working directory is the root of this repository):

    ansible-galaxy install -r ansible/requirements.yml
  4. Install pm2 which is used for deployment:

    npm i -g pm2
  5. Install pnpm v7 for faster dependency installation:

    npm i -g pnpm@7
  6. Install npm dependencies:

    pnpm install
  7. Install wkhtmltopdf.

Ubuntu

  1. Install n and latest Node LTS:

    curl -L https://raw.githubusercontent.com/mklement0/n-install/stable/bin/n-install | bash -s -- -y
  2. Install pm2:

    npm i -g pm2
  3. Install pnpm v7 for faster dependency installation:

    npm i -g pnpm@7
  4. Install fonts:

    echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | sudo debconf-set-selections
    sudo apt-get install xfonts-75dpi fontconfig libxrender1 xfonts-base ttf-mscorefonts-installer libfontconfig
  5. Install wkhtmltopdf:

    wget "https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.$(lsb_release -c -s)_$(dpkg --print-architecture).deb"
    sudo dpkg -i "wkhtmltox_0.12.6.1-2.$(lsb_release -c -s)_$(dpkg --print-architecture).deb"
  6. Install MongoDB by following the guide at https://www.digitalocean.com/community/tutorials/how-to-install-mongodb-on-ubuntu-20-04.

  7. Install Redis by following the guide at https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-20-04.

Server Infrastructure

Naming Convention

Our server alias naming convention consists of the following fields, joined together by a hyphen, and converted to lower case:

  1. App name (e.g. "web", "api", "bree", or "smtp")
  2. (Optional) App count (starting with 1) of the application (relative to the same provider and region). Only applicable for apps with potential count > 1.
  3. Provider name (abbreviated to 2 characters, e.g. "do" for "Digital Ocean", but you can optionally use more verbose for providers such as "Vultr" as "vultr")
  4. Region name (this is the region name given by the provider, e.g. "sfo3" for DO's SFO3 region)

For example, one of our web servers is named web-do-sfo3 and another is web-vultr-dallas.

Load Balancing

All server aliases with the same hostname (with a minimum count of at least 2) are set in Cloudflare under a geo-located load balancer.

Unless otherwise noted, all of the servers should have dedicated CPU's and not be running in a shared CPU environment.

Provisioning

See the ansible folder for our Ansible configuration and playbooks, which we use to provision servers with.

We recommend you to install yamllint and configure it in your editor while working with Ansible playbooks.

Also note that ansible-lint is a helpful linting tool you can use if you plan on making changes to playbooks. Note that our current playbooks have several existing lint errors.

First you must provision Ubuntu 18.04 LTS 64-bit server(s) using Digital Ocean, Linode, Vultr, or your host of choice. These newly provisioned server(s) should have your SSH key automatically added.

Follow the Deployment guide below for automatic provisioning and deployment instructions.

Deployment

  1. Set up host configuration by copying the hosts.yml file template:

    cp ansible/playbooks/templates/hosts.yml hosts.yml
  2. Edit this configuration and update the file with your newly created server aliases and IP addresses. You can add more than one host to each group if you are setting up load balancing. Refer to the Naming Convention documentation for our recommended approach to server alias naming. Note that this file is automatically ignored by git. If you have a private repository and would like to commit this, then remove hosts.yml from the root .gitignore file.

    vim hosts.yml
  3. Set up environment configuration by copying the env file template:

    cp ansible/playbooks/templates/env .env.production
  4. Edit this configuration and reference the official Lad documentation for a list of all available environment variables (or see .env.defaults). You will need to open this file in your preferred editor and set the values for any fields containing TODO, whereby you replace TODO with the appropriate value. Preserve double quotes where they are already defined.

    vim .env.production
  5. Generate pm2 ecosystem files using our automatic template generator. We created an ansible-playbook.js which loads the .env.production environment variables rendered with @ladjs/env into process.env, which then gets used in the playbooks. This is a superior, simple, and the only known dotenv approach we know of in Ansible. Newly created ecosystem-api.json, ecosystem-bree.json, ecosystem-web.json, and ecosystem-smtp.json files will now be created for you in the root of the repository. If you ever more add or change IP addresses, you can simply re-run this command.

    node ansible-playbook ansible/playbooks/ecosystem.yml -l 'localhost'
  6. Set up the web and API server(s) (see patterns and ansible-playbook flags docs if you need help). If you completely (or partially) run this playbook (or any others below), then the second time you try to run it may not succeed. This is because we prevent root user access through security hardening. To workaround this, run the same command but without --user root appended as it will default to the devops user created.

    node ansible-playbook ansible/playbooks/http.yml --user root -l 'http'
  7. Set up the Bree server(s):

    node ansible-playbook ansible/playbooks/bree.yml --user root -l 'bree'
  8. Set up the SMTP server(s):

    node ansible-playbook ansible/playbooks/smtp.yml --user root -l 'smtp'
  9. Set up GitHub deployment keys for all the servers. Note that the deployment-keys directory is ignored from git, so if you have a private repository and wish to commit it, then remove deployment-keys from the .gitignore file.

    node ansible-playbook ansible/playbooks/deployment-keys.yml -l 'smtp:http:bree' --user deploy
  10. Go to your repository "Settings" page on GitHub, click on "Deploy keys", and then add a deployment key for each servers' deployment key copied to the deployment-keys directory. If you're on macOS, you can use the pbcopy command to copy each file's contents to your clipboard. Use tab completion for speed, and replace the server names and paths with yours. You can also use the gh CLI at https://cli.github.com/manual/gh_repo_deploy-key_add as shown below (switch the repo/org/repo paths and deployment key paths below to yours):

    gh repo deploy-key add deployment-keys/api-vu-sj-ca.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/api-do-am-nl.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/web-vu-sj-ca.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/web-do-am-nl.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/bree-vu-sj-ca.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/smtp-vu-sj-ca.pub -R forwardemail/forwardemail.net
    gh repo deploy-key add deployment-keys/smtp-do-am-nl.pub -R forwardemail/forwardemail.net
  11. Set up PM2 deployment directories on all the servers:

    pm2 deploy ecosystem-web.json production setup
    pm2 deploy ecosystem-api.json production setup
    pm2 deploy ecosystem-bree.json production setup
    pm2 deploy ecosystem-smtp.json production setup
  12. Create a SSL certificate at Namecheap (we recommend a 5 year wildcard certificate), set up the certificate, and download and extract the ZIP file with the certificate (emailed to you) to your computer. We do not recommend using tools like LetsEncrypt and certbot due to complexity when you have (or scale to) a cluster of servers set up behind load balancers. In other words, we've tried approaches like lsyncd in combination with crontab for certbot renewals and automatic checking. Furthermore, using this exposes the server(s) to downtime as ports 80 and 443 may need to be shut down so that certbot can use them for certificate generation. This is not a reliable approach, and simply renewing certificates once a year is vastly simpler and also makes using load balancers trivial. Instead you can use a provider like Namecheap to get a cheap SSL certificate, then run a few commands as we've documented below. This command will prompt you for an absolute file path to the certificates you downloaded. Renewed your certificate after 1 year? Simply follow this step again. Do not set a password on the certificate files. When using the openssl command (see Namecheap instructions), you need to use *.example.com with an asterisk followed by a period if you are registering a wildcard certificate.

    ansible-playbook ansible/playbooks/certificates.yml --user deploy

    Important: If you renew or change certificates in the future, then after running the previous command, you will subsequently need to reload the processes as such:

    #
    # NOTE: See the "Important" note above BEFORE running this command.
    #       This command ONLY APPLIES for certificate renewals/changes.
    #
    pm2 deploy ecosystem-web.json production exec "pm2 reload all"
    pm2 deploy ecosystem-api.json production exec "pm2 reload all"
    pm2 deploy ecosystem-smtp.json production exec "pm2 reload all"
  13. (Optional) Create a Google application credentials profile file and store it locally. You only need this if you want to support automatic translation. The following command will prompt you for the absolute file path (e.g. /path/to/client-profile.json). See the mandarin docs for more information.

    ansible-playbook ansible/playbooks/gapp-creds.yml -l 'smtp:http:bree' --user deploy
  14. Copy the .env.production to the servers:

    node ansible-playbook ansible/playbooks/env.yml -l 'smtp:http:bree' --user deploy
  15. Run an initial deploy to all the servers:

    pm2 deploy ecosystem-web.json production
    pm2 deploy ecosystem-api.json production
    pm2 deploy ecosystem-bree.json production
    pm2 deploy ecosystem-smtp.json production
  16. Save the process list on the servers so when if the server were to reboot, it will automatically boot back up the processes:

    pm2 deploy ecosystem-web.json production exec "pm2 save"
    pm2 deploy ecosystem-api.json production exec "pm2 save"
    pm2 deploy ecosystem-bree.json production exec "pm2 save"
    pm2 deploy ecosystem-smtp.json production exec "pm2 save"
  17. Test by visiting your web and API server in your browser (click "proceed to unsafe" site and bypass certificate warning).

  18. Configure your DNS records for the web and API server hostnames and respective IP addresses.

  19. Test by visiting your web and API server in your browser (in an incognito window). There should not be any certificate warnings (similar to the one that occurred in step 15).

  20. (Optional) Remove the local .env.production file for security purposes. If you do this, then make sure you have a backup, or securely back up off the server in the future before destroying the server.

    rm .env.production
  21. (Optional) Remove the local certificate files you downloaded locally and specified in step 11. If you do this, then make sure you have a backup, or securely back up off the server in the future before destroying the server.

  22. Finished. If you need to deploy again, then push your changes to GitHub master branch and then follow step 14 again. We recommend you to read the Ansible getting started guide, as it provides you with insight into commands like ansible all -a "echo hello" which can be run across all or specific servers.

License

Business Source License 1.1 © Forward Email

#

More Repositories

1

email-templates

Create, preview (browser/iOS Simulator), and send custom email templates for Node.js. Made for @forwardemail, @ladjs, @cabinjs, @spamscanner, and @breejs.
JavaScript
3,594
star
2

free-email-forwarding

The best free email forwarding for custom domains. Visit our website to get started (SMTP server)
JavaScript
2,370
star
3

test-preview-emails-cross-browsers-ios-simulator-nodejs-javascript

Automatically opens your browser and iOS Simulator to preview Node.js email messages sent with Nodemailer. Made for @forwardemail and @ladjs. Cross-browser and cross-platform email testing.
JavaScript
196
star
4

reserved-email-addresses-list

List of 1250+ generic, admin, mailer-daemon, and no-reply usernames reserved for security concerns. Made for @forwardemail.
JavaScript
144
star
5

font-awesome-assets

💄 Convert any of @FortAwesome's Font-Awesome icons to an asset, such as an <svg> tag or a Base64-encoded PNG/SVG <img> tag! It supports Retina devices and custom tag attributes too!
HTML
130
star
6

custom-fonts-in-emails

An extremely easy way to use custom fonts in emails without having to use art software.
JavaScript
119
star
7

nodejs-dns-over-https-tangerine

Node.js DNS over HTTPS - 🍊 Tangerine is the best drop-in replacement for dns.promises.Resolver using DNS over HTTPS ("DoH") via undici with built-in retries, timeouts, smart server rotation, AbortControllers, and caching support for multiple backends (with TTL and purge support). Made for @forwardemail.
JavaScript
107
star
8

nodemailer-base64-to-s3

⚡ Convert your Base64-Encoded Data URI's in `<img>` tags to Amazon S3/CloudFront URL's. A better alternative than embedding images with CID using Nodemailer.
JavaScript
30
star
9

status.forwardemail.net

Status Page
Markdown
13
star
10

get-fqdn

Lookup the fully qualified domain name ("FQDN") of the current server's IP (default) or a custom IP. 90x faster than `hostname -f` and works with Node v6.4+.
JavaScript
6
star
11

authheaders

Node.js wrapper around the Python pip package authheaders exposing a function to generate Authentication-Results headers
JavaScript
5
star
12

python-spfcheck2

Node.js wrapper around Python's spf.check2 function which conforms to both RFC4408 and RFC7208
JavaScript
5
star
13

browser-extension

The best privacy-focused browser extension with one-click disposable addresses, unlimited email aliases, and access to your Forward Email account.
3
star
14

dkimpy

Node.js wrapper around the Python pip package dkimpy exposing DKIM and ARC signing and verification functions
JavaScript
2
star
15

python-dkim-verify

Node.js wrapper around Python's dkim.verify function which conforms to RFC spec
JavaScript
2
star
16

python-arf

Node.js wrapper around the Python package arf, which is a processor for Abuse Reporting Format (ARF) messages.
JavaScript
2
star
17

authentication-headers

Our independently maintained fork of @adam-iris authentication-headers repo which contains a fix in the Python package "authheaders".
Python
1
star
18

mta-sts.forwardemail.net

HTML
1
star