This repository contains a NestJS implementation of an EasyTFA relay server, written in Typescript. It can be used to self-host the server but a free hosted version is available at https://eu-relay1.easytfa.com.
The easiest and recommended way to self-host this server is by using the provided docker image easytfa/easy-tfa-server
.
This documentation uses docker-compose
to manage docker containers, but feel free to use a different way that suits your setup.
To support HTTPS (which is required by EasyTFA), a reverse proxy can be used. If you do not have a reverse proxy
running yet, then you can use the docker-compose file provided below.
It uses nginx-proxy as reverse proxy and automatically requests a
letsencrypt certificate with acme-companion.
To get started, create a docker-compose.yml
file in a separate folder with the following content:
⚠️ The docker-compose file instructs docker to expose ports 80 and 443. It also creates a docker network namedproxy
that will be used later. Read the documentation of the docker images linked above for more information and configuration options.
# nginx-proxy/docker-compose.yml
version: '3.5'
services:
nginx-proxy:
image: nginxproxy/nginx-proxy:alpine
labels:
- com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- nginx_certs:/etc/nginx/certs:ro
- nginx_dhparams:/etc/nginx/dhparam
- nginx_vhost:/etc/nginx/vhost.d
- nginx_html:/usr/share/nginx/html
networks:
- proxy
nginx-proxy-letsencrypt:
depends_on:
- nginx-proxy
image: nginxproxy/acme-companion
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- nginx_certs:/etc/nginx/certs
- nginx_vhost:/etc/nginx/vhost.d
- nginx_html:/usr/share/nginx/html
- le_acme:/etc/acme.sh
networks:
- proxy
networks:
proxy:
name: proxy
volumes:
nginx_certs:
nginx_dhparams:
nginx_vhost:
nginx_html:
le_acme:
Then, run
docker-compose up -d
to start the nginx reverse proxy.
The easy-tfa-server
docker image exposes port 80
and handles all requests and websocket connections.
If the nginx-proxy
from above is running, then you can specify the VIRTUAL_HOST
and LETSENCRYPT_HOST
environment
variables to instruct nginx-proxy
that easy-tfa-server
will handle your requests.
To get started, create a docker-compose.yml
file in a separate folder with the following content. Replace
the domain names with your custom domain.
# easytfa/docker-compose.yml
version: '3.5'
services:
easy-tfa-server:
image: easytfa/easy-tfa-server:latest # TODO - replace latest with a specific (major) version after the first full release
restart: unless-stopped
environment:
- VIRTUAL_HOST=example.com # TODO - replace this with your domain name
- LETSENCRYPT_HOST=example.com # TODO - replace this with your domain name
networks:
- proxy
networks:
proxy:
name: proxy
Then, start the server by executing
docker-compose up -d
You can check whether the server is running by navigating to https://example.com/config
, replacing the domain with your custom domain.
If everything is running, you should get a response like this:
{
"success": true,
"version": "Some.Server.Version",
"push": {
"supported": false,
"apiKey": "",
"applicationId": "",
"projectId": ""
}
}
EasyTFA uses Firebase to deliver push notifications to mobile devices. To enable push notifications for your own server, you first have to create a project at Firebase. Then, follow the steps below to get all needed access keys.
- On the project overview, add a new Android App to the project
- As app name, specify
com.beemdevelopment.aegis
- Register the App
- Download the
google-services.json
file and save it for later use - Return to the Firebase console
- Go to the project settings, and select "Service accounts"
- Click "Generate new private key"
- Download the
[projectname]-firebase-adminsdk-[...].json
file. You can rename it toeasytfa-firebase-adminsdk.json
for easier use later - Copy the
easytfa-firebase-adminsdk.json
file into the folder with the easy-tfa-serverdocker-compose.yml
file
Now, extend the docker-compose.yml
file so that it contains the notification settings as shown below.
Replace the environment variables with the respective values from the google-services.json
file.
This docker-compose
file also specifies a data
volume. The server will use this to store a small file that will
contain a list of all registered notification endpoints. This allows the server to remember which devices should
receive which notifications after a restart.
version: '3.5'
services:
easy-tfa-server:
image: easytfa/easy-tfa-server:latest # TODO - replace latest with a specific (major) version after the first full release
restart: unless-stopped
environment:
- VIRTUAL_HOST=example.com
- LETSENCRYPT_HOST=example.com
- PUSHNOTIFICATIONS_ENABLED=true
- PUSHNOTIFICATIONS_APIKEY=AIza... # TODO: Replace with client.api_key.current_key from google-services.json
- PUSHNOTIFICATIONS_APPLICATIONID=1:7820:android:bfa5a... # TODO: Replace with client.client_info.mobilesdk_app_id from google-services.json
- PUSHNOTIFICATIONS_PROJECTID=easytfa # TODO: Replace with project_info.project_id from google-services.json
networks:
- proxy
volumes:
- ./easytfa-firebase-adminsdk.json:/app/easytfa-firebase-adminsdk.json:ro
- data:/app/data
networks:
proxy:
name: proxy
volumes:
data:
Then, (re)start the server by running
docker-compose up -d
and open https://example.com/config
(replacing the domain with your domain name) to check whether the server started
with notifications enabled (Note that you might have to hard refresh the page using Ctrl+F5 because otherwise it might be cached).
You can also check the server connection in the EasyTFA browser extension. The response should look like this:
{
"success": true,
"version": "Some.Server.Version",
"push": {
"supported": true,
"apiKey": "your-api-key",
"applicationId": "your-application-id",
"projectId": "your-project-id"
}
}