Analytics cookies only (Google Analytics, PostHog). No ad networks, no cross-site tracking. See our privacy policy.
Self-host 2FAuth
updated Oct 2026deployed by usprices checked · Jul 2026Install verified on Ubuntu 26.04 · Oct 2026 · how we test
We earn commissions when you shop through the links below. Full disclosure →
A web-based self-hosted alternative to one-time-passcode apps like Google Authenticator, designed for both mobile and desktop: store TOTP and HOTP accounts, add them from a QR code and read the codes in a browser. Generates codes per RFC 4226 and RFC 6238, with optional encryption of sensitive data in the database. AGPL-3.0 PHP (Laravel); SQLite by default.
Runs on a VPS from $4/mo (Kamatera 1GB, 1 GB RAM) · prices checked Sep 2026
Our recommendation
Pick 2FAuth when you want your one-time codes on your own server instead of in a phone app tied to one device: it holds your TOTP and HOTP accounts, generates the codes in the browser, and works from a desktop as well as a phone. The README lists optional encryption of the stored secrets, and codes follow RFC 4226 and RFC 6238, so it is a drop-in for any service that offers an authenticator-app setup. It is AGPL-3.0 and runs as one PHP container on SQLite. Our snippet is the docs' Compose example with a generated `APP_KEY`, a named volume for the data and the image pinned to an immutable release tag. We did not find an upstream RAM minimum, so our 256 MB floor is an estimate. Think before you pair it with a password manager: the catalog's Vaultwarden and Bitwarden can also hold TOTP codes, but keeping passwords and second factors in one place weakens the point of a second factor.
What you need
Any VPS with at least 256 MB of RAM
A domain you control — most self-hosted setups need HTTPS in front of them
2FAuth's README and Docker docs flag these before you put real accounts in it:
non-negotiableAPP_KEY is mandatory and must be unique to you; the docs say how to generate one, and our snippet creates a base64: key into .env. Encryption of the sensitive data in the database is an option that is off by default, and the README strongly recommends backing up the APP_KEY value (or the whole .env) when it is on, because losing the key means losing the secrets.
non-negotiableBack up the data volume: it holds the SQLite database (/2fauth in the container), and a lost database is a set of accounts you have to re-enrol one by one with each service. Export what 2FAuth offers regularly, and keep your services' recovery codes somewhere else.
non-negotiableThe image runs as user 1000:1000, so a bind mount instead of our named volume needs chown 1000:1000 on the host directory. APP_URL should be the address you open in the browser.
non-negotiablePort 8000 is plain HTTP, and the secrets worth stealing here are one-time-code seeds. Serve it over TLS from a reverse proxy before you sign in from anywhere but the machine itself. The image tags are pinned releases (8.0.3); the project also publishes a moving latest and a dev tag.