2FAuth
Stack
Web app for your two-factor authentication codes, a self-hosted stand-in for Google Authenticator: add accounts by scanning or uploading their QR codes, then copy codes from any browser. Source: https://github.com/Bubka/2FAuth
Image details
Source details
Configuration
TypeComposelinux2fauth/2fauth:8${TWOFAUTH_PORT:-8200}:8000/2fauth : 2fauth-dataAPP_KEY=${TWOFAUTH_APP_KEY:?Set an app key of exactly 32 characters}APP_URL=TWOFAUTH_APP_KEY=''TWOFAUTH_PORT=8200unless-stoppedTemplate by NotAFlightRisk·Source
Report issueNotes
openssl rand -hex 16 makes one), since the stack won't start without it. Keep it the same from then on, as it signs logins and encrypts your codes if you turn on encryption. Then open http://<your-host>:8200 (or whichever port you picked) and register: the first account becomes the admin. Anyone who can reach it can register after that, so once you're in, tick Disable registration under Admin panel --> Authentication (the menu under your email). Scanning a QR code with the camera and passkeys both need HTTPS, so behind plain http you'll be uploading QR screenshots and signing in with a password. Everything lives in the 2fauth-data volume, and since that's every 2FA secret you've got, back it up. Docs: docs.2fauth.appStandalone Install
Select an install method, to see config/commands for deploying 2FAuth
Install on Portainer
Import all app templates into your Portainer instance, for easy 1-click deploys
- Ensure both Docker and Portainer are installed, and up-to-date
- Log into your Portainer web UI
- Under Settings → App Templates, paste the below URL
- Head to Home → App Templates, and the list of apps will show up
- Select 2FAuth, fill in any config options, and hit Deploy
Template Import URL
https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json
Show Me
Original stackfile
The compose file this template deploys, straight from its repo:
services:
2fauth:
image: 2fauth/2fauth:8
restart: unless-stopped
ports:
- "${TWOFAUTH_PORT:-8200}:8000"
environment:
APP_KEY: ${TWOFAUTH_APP_KEY:?Set an app key of exactly 32 characters}
APP_URL: ""
volumes:
- 2fauth-data:/2fauth
volumes:
2fauth-data:
Or deploy it directly from the source:
git clone https://github.com/NotAFlightRisk/portainer-templates-extras
cd portainer-templates-extras
docker compose -f apps/2fauth/compose.yml up -dMore install options in our documentation, or see Bubka/2FAuth for app-specific guidance.
Docker
You can run 2fauth in a single Docker container.
Features
- Compatible with:
amd64,386,arm64,arm/v6andarm/v7 - Stores data in an Sqlite database file
- Runs without root as user with id
1000and group id1000
Setup
We assume your current directory is/yourpath.- Create a directory on your host:
```sh
mkdir 2fauth
```- If your host is not Windows: since the container runs without root as user
1000:1000, you need to fix the ownership and permissions of that directory:
```sh
chown 1000:1000 2fauth
chmod 700 2fauth
```
💁 if you feel like using another ID, you can [build the image with build arguments](#build-the-image-with-build-arguments).- Run the container interactively:
```sh
docker run -it --rm -p 8000:8000/tcp \
-v /yourpath/2fauth:/2fauth 2fauth/2fauth
-e AUTHENTICATION_GUARD=web-guard #fix for issue #68
```- Access it at http://localhost:8000
You can stop it with
CTRL+C.- You can also run it in the background by replacing
-it --rmwith-d. - You can set environment variables available (see the .env.example) with
-e, for example-e APP_NAME=2FAuth. - You can also use the docker-compose.yml with
docker-composeand modify it as you wish.
Use an existing SQLite file
If you already have an SQLite file, move it to/yourpath/2fauth/database.sqlite on your host before starting the container. Don't forget to fix its ownership and permissions if you run on nix:chown 1000:1000 /yourpath/2fauth/database.sqlite
chmod 700 /yourpath/2fauth/database.sqliteThe container will automagically pick it up.
Update
⚠️ At the very least, backup yourdatabase.sqlite file to avoid bad surprises!The Docker image
2fauth/2fauth is built on every commit pushed to the master branch.You can therefore pull the image with
docker pull 2fauth/2fauth and restart the container to update it.You can also use tagged images, see Docker Hub tags which are produced on Github releases.
Build the image
You can build the image from themaster branch with docker and git using:docker build -t 2fauth/2fauth https://github.com/Bubka/2FAuth.gitBuild the image for a specific release
You can build a specific release by appending the release tag with#<release-tag> to the command. For example:docker build -t 2fauth/2fauth https://github.com/Bubka/2FAuth.git#v3.0.0Build the image for a specific commit
You can build a specific commit (see master's commits) by appending the commit hash with#<commit-hash> to the command. For example:docker build -t 2fauth/2fauth https://github.com/Bubka/2FAuth.git#fba9e29bd4e3bb697296bb0bde60ae869537528bBuild the image with build arguments
There are the following build arguments you can use to customize the image using--build-arg key=value:| Build argument | Default | Description |
|---|---|---|
UID | 1000 | The UID of the user to run the container as |
GID | 1000 | The GID of the user to run the container as |
DEBIANVERSION | buster-slim | The Debian version to use |
PHPVERSION | 8.2-buster | The PHP version to use to get composer dependencies |
COMPOSERVERSION | 2.7 | The version of composer to use |
SUPERVISORDVERSION | v0.7.3 | The version of supervisord to use |
VERSION | unknown | The version of the image |
CREATED | an unknown date | The date of the image build time |
COMMIT | unknown | The commit hash of the Git commit used |
Mail settings
Refer your email provider documentation to configure your mail settings
Set a value for every available setting to avoid issue
| Build argument | Recommendation | Description |
|---|---|---|
MAILMAILER | SMTP | The driver type |
MAILHOST | smtp.yourdomain.com | The SMTP hostname |
MAILPORT | 587 | The corresponding SMTP port (587 with STARTTLS) or (465 with SSL recommended) |
MAILUSERNAME | [email protected] | The SMTP username |
MAILPASSWORD | password1234 | The SMTP password |
MAILENCRYPTION | TLS | The encrytion type (TLS -> STARTTLS) or SSL |
MAILFROMNAME | 2FAuth | The sender name |
MAILFROMADDRESS | [email protected] | The sender adress |
Example:
-e MAIL_MAILER=SMTP
-e MAIL_HOST=smtp.example.com
-e MAIL_PORT=587 # STARTTLS
-e [email protected]
-e MAIL_PASSWORD=password1234
-e MAIL_ENCRYPTION=TLS # STARTTLS
-e MAIL_FROM_NAME=2FAuth
-e [email protected]Implementation details
- The final Docker image is based on
alpine:3.14with minimal packages installed - The container runs
supervisordto handle both an Nginx server and a PHP-FPM server together - The
/srvdirectory holds the repository data and PHP code. - The
/2fauthdirectory is targeted for the container end users. - By default the container logs the Nginx logs and the PHP-FPM logs. The application logs (if any) can be found in
/2fauth/storage/logs.
Check the logs first
Nine times out of ten the logs tell you exactly what went wrong.
- In Portainer, go to Containers, click the container, then Logs. Or run
docker logs <container> - Exit codes help too:
137means killed, usually out of memory.126or127means the command inside the image is broken.
Image won't pull
Test the pull directly on the host: docker pull 2fauth/2fauth:8
- "manifest unknown" means the tag no longer exists.
- "toomanyrequests" is the Docker Hub rate limit. Log in with
docker loginto raise it. - "no space left on device" means a full disk. Reclaim space with
docker system prune
"exec format error"
This means the image was built for a different CPU architecture than your server.
- This image supports:
amd64, arm64, arm/v7, arm/v6, 386 - Check yours with
uname -m: x86_64 is amd64, aarch64 is arm64. Raspberry Pi and other ARM boards are the usual culprits.
Container keeps restarting
The unless-stopped restart policy relaunches the app after every crash, so the real error can scroll past.
- Check the logs right after a restart, the last few lines before it died are the useful ones.
- Get the exit code with
docker inspect <container> --format '{{.State.ExitCode}}' - Still stuck? Redeploy once with the restart policy set to
noso the failure stays visible.
Required settings are blank
APP_URL, TWOFAUTH_APP_KEY have no default value, and 2fauth may crash or misbehave if left empty.
- Fill them in on the deploy screen before hitting deploy.
Stack won't deploy
Compose stacks fail fast on small mistakes, and Portainer shows the reason just above the editor.
- YAML only accepts spaces for indentation, a single tab breaks the whole file.
Raise an issue
Found something which isn't working as it should? Here's how to report it.
- Bug within the app: Open an issue on Bubka/2FAuth
- Template not working: Open an issue on NotAFlightRisk/portainer-templates-extras
- This website not working: Open an issue on lissy93/portainer-templates
A Compose stack
2FAuth is a Compose stack, a set of containers defined in one file and brought up together by Portainer, then started and stopped as a single app.
The app image
An image is the app packed up ready to go, everything 2FAuth needs bundled into one download. This template pulls 2fauth/2fauth:8, which Docker fetches once (about 40 MB) and then starts your own copy from.
Where the image comes from
Docker pulls its images from registries, public libraries of ready-built apps. 2FAuth's comes from Docker Hub, published by 2fauth.
Version tags
The bit after the colon in the image name is the version tag. This one pins 8, so every redeploy gives you that exact build until you bump it yourself.
Which machines it runs on
Every image is built for particular CPU types. This one ships for amd64, arm64, arm/v7, arm/v6, 386, so it runs on both regular x86 servers and ARM boards like a Raspberry Pi.
Volumes
A volume is where 2FAuth keeps its files so they survive an update or a restart. Without one, anything it saves would sit inside the container and vanish the moment it's recreated. This template mounts:
/2fauthkept in the2fauth-datavolume Docker manages
Environment variables
Environment variables are the settings you hand over when you deploy, things like a password or a timezone. 2FAuth takes 4 of them, and 3 need a value before it'll start properly:
APP_KEY, needs a valueAPP_URL, needs a valueTWOFAUTH_APP_KEY, needs a value. Exactly 32 characters. Generate one with: openssl rand -hex 16. Keep it the same when you redeploy.TWOFAUTH_PORT, defaults to8200. Host port for the web UI
Restart policy
The restart policy here is unless-stopped, so Docker restarts 2FAuth after a crash or reboot, but leaves it off when you stop it on purpose. You can change this on the deploy screen. The choices are no (never restart), on-failure (only after a crash), unless-stopped (restart unless you stop it), and always (bring it back no matter what).
Networking
Nothing custom is set, so 2FAuth sits on Docker's default bridge network: its own private space that reaches the outside world only through the ports it publishes.
Container name
Once it's deployed, Portainer names the container 2fauth. That's what you'll spot in the containers list and use in commands like docker logs 2fauth.
Platform
The platform is linux, the kind of system the container is built to run on. Docker and Portainer handle this on a normal Linux server.
Open source license
2FAuth is open source, released under the AGPL-3.0 license. In plain terms the code is out in the open, so you're free to run it and change it to fit what you need.
Portainer app templates
Zooming out, this whole page comes from a Portainer app template: a short recipe telling Portainer how to set 2FAuth up. Add the template list to Portainer once, then deploying 2FAuth is a click rather than a wall of config.