turkushan-auth
Docker app from turkushan-auth's Repository
Overview
Readme
View on GitHubturkushan-auth
A self-hosted login portal for your subdomains behind Nginx Proxy Manager (forward auth, like Tinyauth). People create their own account, you decide per site who gets in, and one login works on all your subdomains.
Everything runs in one container: a Go backend and a Svelte frontend in a single binary, with SQLite in /data. No database server, no Redis, no compose.

Features
- Sign in, create account, forgot password: dark, mobile-friendly pages
- Continue with Discord or Google (optional)
- Unlock sites by Discord server or role: everyone with a certain role in your Discord server gets into the sites you choose, automatically, without a bot
- Single sign-on across
*.your-domainwith one session cookie - Per site: "needs approval" or "open for everyone signed in", and optionally "needs a verified email"
- Back to where you were: after signing in, visitors land on the page they opened
- Admin panel:
- approve/deny requests
- manage users (create or invite, access per site, block, unlock, reset password, delete), with search, filters and sorting
- groups that give site access and panel rights, with auto-add rules; several admins
- add sites with a ready-to-paste NPM config and a Copy button
- audit log of every admin action
- 25 languages with a searchable language picker. The portal follows the visitor's browser language, and mails go out in the language they chose. You can set a default and limit which languages are offered.
- Your own look: logo, site name, accent color, font and background (image, color or gradient), set in the admin panel with a live preview
- Email via any SMTP provider (Resend recommended): verify addresses, reset passwords
- Discord notifications for new accounts and access requests
- Security: argon2id, server-side sessions, CSRF protection, rate limits, lockout, open-redirect protection, strict security headers; see SECURITY.md
Screenshots
Users: who can open what, groups, login methods, search and filters |
Groups: site access, panel rights and auto-add rules |
Requests: approve or deny |
Sites: rules per site and the NPM config to paste |
Appearance: logo, colors, font, background |
Settings: email, Discord/Google login, notifications |
Waiting for approval |
First sign-in with Discord or Google |
Verified email needed |
Account page |

Example: unlock sites with a Discord role
Give everyone with a certain role in your Discord server access to a site, without approving them one by one:
- Turn on Discord login in Settings → Sign in with Discord or Google (how).
- Groups → New group, e.g. "Discord VIP". Under Sites, tick Can open for the sites the role unlocks.
- Under Auto-add rules, choose Discord role and paste your server ID and role ID (Discord → Settings → Advanced → Developer Mode, then right-click the server or role → Copy ID).
From then on, everyone with that role gets in right after signing in with Discord. Take the role away and they're out at their next Discord sign-in. Roles are read when someone signs in, so no bot is needed. Details: guide, step 8.4.
Get started
📖 Read the guide. It covers installing on Unraid, the NPM setup, protecting your first site, email with Resend, Discord, backups and troubleshooting.
Quick version:
- Install
turkushan-authfrom Community Apps, or via the template intemplates/. SetAPP_URL,ADMIN_USERandADMIN_PASSWORD. - In NPM, add a proxy host
auth.your-domain→<server-ip>:3010with SSL, and Block Common Exploits off. - Sign in at
https://auth.your-domain→ Admin panel → Sites → Add site. - Copy the site's NPM config into the Advanced tab of that site's proxy host in NPM.
Settings
| Variable | Default | |
|---|---|---|
APP_URL |
required | public portal URL, e.g. https://auth.example.com |
ADMIN_USER / ADMIN_PASSWORD |
admin created on first start; the password is not overwritten on restart | |
COOKIE_DOMAIN |
derived from APP_URL |
auth.example.com gives .example.com, shared by all subdomains |
TRUSTED_PROXIES |
172.16.0.0/12 |
proxy addresses allowed to pass client IP headers |
PORTAL_INTERNAL_URL |
how NPM reaches the portal; can also be set in the admin panel | |
SESSION_SECRET |
auto-generated in /data/secret |
|
PUID / PGID |
99 / 100 |
user the app runs as |
PORT |
3010 |
port inside the container |
DATA_DIR |
/data |
where the database, secret and uploads live |
LOG_LEVEL |
info |
debug, info, warn or error |
LOG_FORMAT |
text |
text, or json for log collectors |
Email, Discord and the portal address are set in Admin panel → Settings.
Images and versions
ghcr.io/turkushan490/turkushan-auth is published for amd64 and arm64.
| Tag | Follows |
|---|---|
latest |
every change on main |
1 |
everything up to the next big change |
1.0 |
bug fixes only |
1.0.0 |
stays on exactly that version |
What changed in each version is in the changelog.
Backup and recovery
Back up the database while the portal runs, in one of these ways:
- Admin panel → Settings → Download backup
docker exec turkushan-auth /turkushan-auth backup(writes to/data/backups/)
Locked out of the admin account without a verified email? This asks for the new password:
docker exec -it turkushan-auth /turkushan-auth reset-password <username>
Languages
The portal and its mails are available in English, Dutch, Turkish, German, French, Spanish, Portuguese, Italian, Polish, Russian, Ukrainian, Arabic, Persian, Hindi, Japanese, Korean, Chinese (Simplified and Traditional), Indonesian, Vietnamese, Thai, Swedish, Danish, Norwegian and Finnish. Arabic and Persian are shown right to left.
Which language a visitor sees:
- The language they picked in the picker. It's saved on their account, so their mails use it too.
- Otherwise, their browser's language.
- Otherwise, the default you set in Admin panel → Appearance → Language. You can also limit which languages are offered there.
The translations were made with machine help. Found a clumsy sentence? Corrections are very welcome as a pull request:
- web texts:
web/src/locales/<code>.json - mail texts:
internal/i18n/mail/<code>.json
npm run check-locales in web/ checks that every language has the same keys and placeholders as English.
Development
GitHub Actions (.github/workflows/build.yml) does the following:
- builds and checks the frontend;
- runs
gofmt,go vet,go test -raceandgovulncheck; - scans the image with Trivy;
- pushes
ghcr.io/turkushan490/turkushan-auth:latest(amd64 + arm64) on every push tomain.
A v1.2.3 tag also pushes :1.2.3, :1.2 and :1, and creates a GitHub Release from that version's section in CHANGELOG.md. Dependabot keeps Go, npm, Actions and the Docker base images up to date.
cd web && npm install && npm run build && cd ..
APP_URL=http://localhost:3010 DATA_DIR=./data ADMIN_USER=admin ADMIN_PASSWORD='Change!me' go run ./cmd/turkushan-auth
For frontend work, npm run dev in web/ proxies /api to a portal running on port 3010.
License
MIT
Media gallery
1 / 5Requirements
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/turkushan490/turkushan-auth:latestRuntime arguments
- Network
bridge- Privileged
- false
Template configuration
Port Nginx Proxy Manager uses to reach the portal.
- Target
- 3010
- Default
- 3010
- Value
- 3010
SQLite database and generated secret.
- Target
- /data
- Default
- /mnt/user/appdata/turkushan-auth
- Value
- /mnt/user/appdata/turkushan-auth
Public URL of the portal, e.g. https://auth.example.com
Admin account created on first start.
Admin password, only needed on the first start (remove it afterwards): at least 6 characters, with 1 capital letter and 1 symbol (e.g. ! @ # ?).
Optional. Cookie domain shared by all protected subdomains. Empty = derived from APP_URL (auth.example.com gives .example.com).
Optional. How Nginx Proxy Manager reaches this container, e.g. http://192.168.1.10:3010. Filled into the nginx snippets the admin panel generates.
IPs/CIDRs of your proxy. Client IP headers are only trusted from these. Default covers Docker networks.
- Default
- 172.16.0.0/12
- Value
- 172.16.0.0/12
User the app runs as (99 = nobody).
- Default
- 99
- Value
- 99
Group the app runs as (100 = users).
- Default
- 100
- Value
- 100
Optional. debug, info, warn or error.
- Default
- info
- Value
- info
Optional. text, or json for log collectors.
- Default
- text
- Value
- text
Optional (min 32 characters). Empty = generated once and stored in /data/secret.
Users: who can open what, groups, login methods, search and filters
Groups: site access, panel rights and auto-add rules
Requests: approve or deny
Sites: rules per site and the NPM config to paste
Appearance: logo, colors, font, background
Settings: email, Discord/Google login, notifications
Waiting for approval
First sign-in with Discord or Google
Verified email needed
Account page