[{"data":1,"prerenderedAt":2302},["ShallowReactive",2],{"navigation_docs_en":3,"-en-serveex-security-tinyauth-":377,"-en-serveex-security-tinyauth--surround":2297},[4,16,94,262,271,332],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":15},"About","i-noto-star","\u002Fen\u002Fabout","en\u002F1.about",[10],{"title":11,"path":12,"stem":13,"icon":14},"Welcome","\u002Fen\u002Fabout\u002Fwelcome","en\u002F1.about\u002F1.welcome","i-lucide-home",false,{"title":17,"icon":18,"path":19,"stem":20,"children":21,"page":15},"General","i-noto-open-book","\u002Fen\u002Fgeneral","en\u002F2.general",[22,26,44,58,76],{"title":17,"path":23,"stem":24,"icon":25},"\u002Fen\u002Fgeneral\u002Fsummary","en\u002F2.general\u002F1.summary","i-lucide-bookmark",{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":15},"Networking","i-lucide-network","\u002Fen\u002Fgeneral\u002Fnetworking","en\u002F2.general\u002F2.networking",[32,36,40],{"title":33,"path":34,"stem":35},"NAT & DHCP","\u002Fen\u002Fgeneral\u002Fnetworking\u002Fnat","en\u002F2.general\u002F2.networking\u002F1.nat",{"title":37,"path":38,"stem":39},"DNS Zone","\u002Fen\u002Fgeneral\u002Fnetworking\u002Fdns","en\u002F2.general\u002F2.networking\u002F2.dns",{"title":41,"path":42,"stem":43},"Samba","\u002Fen\u002Fgeneral\u002Fnetworking\u002Fsamba","en\u002F2.general\u002F2.networking\u002F3.samba",{"title":45,"icon":46,"path":47,"stem":48,"children":49,"page":15},"Storage","i-lucide-hard-drive","\u002Fen\u002Fgeneral\u002Fstorage","en\u002F2.general\u002F3.storage",[50,54],{"title":51,"path":52,"stem":53},"RAID","\u002Fen\u002Fgeneral\u002Fstorage\u002Fraid","en\u002F2.general\u002F3.storage\u002F1.raid",{"title":55,"path":56,"stem":57},"ZFS","\u002Fen\u002Fgeneral\u002Fstorage\u002Fzfs","en\u002F2.general\u002F3.storage\u002F2.zfs",{"title":59,"icon":60,"path":61,"stem":62,"children":63,"page":15},"Hardware","i-lucide-server","\u002Fen\u002Fgeneral\u002Fhardware","en\u002F2.general\u002F4.hardware",[64,68,72],{"title":65,"path":66,"stem":67},"The Basics","\u002Fen\u002Fgeneral\u002Fhardware\u002Fbasics","en\u002F2.general\u002F4.hardware\u002F1.basics",{"title":69,"path":70,"stem":71},"Network","\u002Fen\u002Fgeneral\u002Fhardware\u002Fnetwork","en\u002F2.general\u002F4.hardware\u002F2.network",{"title":73,"path":74,"stem":75},"The ProloNAS","\u002Fen\u002Fgeneral\u002Fhardware\u002Fprolonas","en\u002F2.general\u002F4.hardware\u002F3.prolonas",{"title":77,"icon":78,"path":79,"stem":80,"children":81,"page":15},"Linux tips for dummies","i-lucide-terminal","\u002Fen\u002Fgeneral\u002Flinux","en\u002F2.general\u002F5.linux",[82,86,90],{"title":83,"path":84,"stem":85},"Command line basics","\u002Fen\u002Fgeneral\u002Flinux\u002Fcli-basics","en\u002F2.general\u002F5.linux\u002F1.cli-basics",{"title":87,"path":88,"stem":89},"Folders and partitions","\u002Fen\u002Fgeneral\u002Flinux\u002Ffilesystem","en\u002F2.general\u002F5.linux\u002F2.filesystem",{"title":91,"path":92,"stem":93},"Handy CLI tools","\u002Fen\u002Fgeneral\u002Flinux\u002Fhandy-tools","en\u002F2.general\u002F5.linux\u002F3.handy-tools",{"title":95,"icon":96,"path":97,"stem":98,"children":99,"page":15},"Serveex","i-noto-microscope","\u002Fen\u002Fserveex","en\u002F3.serveex",[100,104,126,144,170,188,202,216,234,248],{"title":101,"path":102,"stem":103,"icon":25},"Introduction","\u002Fen\u002Fserveex\u002Fintroduction","en\u002F3.serveex\u002F1.introduction",{"title":105,"icon":106,"path":107,"stem":108,"children":109,"page":15},"Server core","i-lucide-server-cog","\u002Fen\u002Fserveex\u002Fcore","en\u002F3.serveex\u002F2.core",[110,114,118,122],{"title":111,"path":112,"stem":113},"Debian 13","\u002Fen\u002Fserveex\u002Fcore\u002Finstallation","en\u002F3.serveex\u002F2.core\u002F1.installation",{"title":115,"path":116,"stem":117},"Docker","\u002Fen\u002Fserveex\u002Fcore\u002Fdocker","en\u002F3.serveex\u002F2.core\u002F2.docker",{"title":119,"path":120,"stem":121},"Wireguard","\u002Fen\u002Fserveex\u002Fcore\u002Fwireguard","en\u002F3.serveex\u002F2.core\u002F3.wireguard",{"title":123,"path":124,"stem":125},"SWAG","\u002Fen\u002Fserveex\u002Fcore\u002Fswag","en\u002F3.serveex\u002F2.core\u002F4.swag",{"title":127,"icon":128,"path":129,"stem":130,"children":131,"page":15},"Security","i-lucide-shield","\u002Fen\u002Fserveex\u002Fsecurity","en\u002F3.serveex\u002F3.security",[132,136,140],{"title":133,"path":134,"stem":135},"Cloudflare Zero Trust","\u002Fen\u002Fserveex\u002Fsecurity\u002Fcloudflare","en\u002F3.serveex\u002F3.security\u002F2.cloudflare",{"title":137,"path":138,"stem":139},"TinyAuth","\u002Fen\u002Fserveex\u002Fsecurity\u002Ftinyauth","en\u002F3.serveex\u002F3.security\u002F3.tinyauth",{"title":141,"path":142,"stem":143},"Pocket ID","\u002Fen\u002Fserveex\u002Fsecurity\u002Fpocket-id","en\u002F3.serveex\u002F3.security\u002F4.pocket-id",{"title":145,"icon":146,"path":147,"stem":148,"children":149,"page":15},"Monitoring","i-lucide-chart-no-axes-column","\u002Fen\u002Fserveex\u002Fmonitoring","en\u002F3.serveex\u002F4.monitoring",[150,154,158,162,166],{"title":151,"path":152,"stem":153},"Uptime-Kuma","\u002Fen\u002Fserveex\u002Fmonitoring\u002Fuptime-kuma","en\u002F3.serveex\u002F4.monitoring\u002F1.uptime-kuma",{"title":155,"path":156,"stem":157},"Dozzle","\u002Fen\u002Fserveex\u002Fmonitoring\u002Fdozzle","en\u002F3.serveex\u002F4.monitoring\u002F2.dozzle",{"title":159,"path":160,"stem":161},"Speedtest Tracker","\u002Fen\u002Fserveex\u002Fmonitoring\u002Fspeedtest-tracker","en\u002F3.serveex\u002F4.monitoring\u002F3.speedtest-tracker",{"title":163,"path":164,"stem":165},"Beszel","\u002Fen\u002Fserveex\u002Fmonitoring\u002Fbeszel","en\u002F3.serveex\u002F4.monitoring\u002F4.beszel",{"title":167,"path":168,"stem":169},"UpSnap","\u002Fen\u002Fserveex\u002Fmonitoring\u002Fupsnap","en\u002F3.serveex\u002F4.monitoring\u002F5.upsnap",{"title":171,"icon":172,"path":173,"stem":174,"children":175,"page":15},"Media & Seedbox","i-lucide-list-video","\u002Fen\u002Fserveex\u002Fmedia","en\u002F3.serveex\u002F5.media",[176,180,184],{"title":177,"path":178,"stem":179},"Jellyfin","\u002Fen\u002Fserveex\u002Fmedia\u002Fjellyfin","en\u002F3.serveex\u002F5.media\u002F1.jellyfin",{"title":181,"path":182,"stem":183},"Qbittorrent","\u002Fen\u002Fserveex\u002Fmedia\u002Fqbittorrent","en\u002F3.serveex\u002F5.media\u002F2.qbittorrent",{"title":185,"path":186,"stem":187},"Automation","\u002Fen\u002Fserveex\u002Fmedia\u002Fservarr","en\u002F3.serveex\u002F5.media\u002F3.servarr",{"title":189,"icon":190,"path":191,"stem":192,"children":193,"page":15},"Cloud Drive & Photos","i-lucide-cloud-upload","\u002Fen\u002Fserveex\u002Fcloud","en\u002F3.serveex\u002F6.cloud",[194,198],{"title":195,"path":196,"stem":197},"Immich","\u002Fen\u002Fserveex\u002Fcloud\u002Fimmich","en\u002F3.serveex\u002F6.cloud\u002F1.immich",{"title":199,"path":200,"stem":201},"Nextcloud","\u002Fen\u002Fserveex\u002Fcloud\u002Fnextcloud","en\u002F3.serveex\u002F6.cloud\u002F2.nextcloud",{"title":203,"icon":204,"path":205,"stem":206,"children":207,"page":15},"File & share","i-lucide-folder-tree","\u002Fen\u002Fserveex\u002Ffiles","en\u002F3.serveex\u002F7.files",[208,212],{"title":209,"path":210,"stem":211},"File Browser Quantum","\u002Fen\u002Fserveex\u002Ffiles\u002Ffile-browser-quantum","en\u002F3.serveex\u002F7.files\u002F1.file-browser-quantum",{"title":213,"path":214,"stem":215},"Pingvin","\u002Fen\u002Fserveex\u002Ffiles\u002Fpingvin","en\u002F3.serveex\u002F7.files\u002F2.pingvin",{"title":217,"icon":218,"path":219,"stem":220,"children":221,"page":15},"Developpement","i-lucide-code-xml","\u002Fen\u002Fserveex\u002Fdevelopment","en\u002F3.serveex\u002F8.development",[222,226,230],{"title":223,"path":224,"stem":225},"Code-Server","\u002Fen\u002Fserveex\u002Fdevelopment\u002Fcode-server","en\u002F3.serveex\u002F8.development\u002F1.code-server",{"title":227,"path":228,"stem":229},"Forgejo","\u002Fen\u002Fserveex\u002Fdevelopment\u002Fforgejo","en\u002F3.serveex\u002F8.development\u002F2.forgejo",{"title":231,"path":232,"stem":233},"IT Tools","\u002Fen\u002Fserveex\u002Fdevelopment\u002Fit-tools","en\u002F3.serveex\u002F8.development\u002F3.it-tools",{"title":235,"icon":236,"path":237,"stem":238,"children":239,"page":15},"Useful Apps","i-lucide-award","\u002Fen\u002Fserveex\u002Fapps","en\u002F3.serveex\u002F9.apps",[240,244],{"title":241,"path":242,"stem":243},"Adguard Home","\u002Fen\u002Fserveex\u002Fapps\u002Fadguard","en\u002F3.serveex\u002F9.apps\u002F1.adguard",{"title":245,"path":246,"stem":247},"Vaultwarden","\u002Fen\u002Fserveex\u002Fapps\u002Fvaultwarden","en\u002F3.serveex\u002F9.apps\u002F2.vaultwarden",{"title":249,"icon":250,"path":251,"stem":252,"children":253,"page":15},"Advanced","i-lucide-flask-conical","\u002Fen\u002Fserveex\u002Fadvanced","en\u002F3.serveex\u002F91.advanced",[254,258],{"title":255,"path":256,"stem":257},"Authentik","\u002Fen\u002Fserveex\u002Fadvanced\u002Fauthentik","en\u002F3.serveex\u002F91.advanced\u002F1.authentik",{"title":259,"path":260,"stem":261},"Arcane","\u002Fen\u002Fserveex\u002Fadvanced\u002Farcane","en\u002F3.serveex\u002F91.advanced\u002F2.arcane",{"title":263,"icon":264,"path":265,"stem":266,"children":267,"page":15},"Stockeex","i-noto-computer-disk","\u002Fen\u002Fstockeex","en\u002F4.stockeex",[268],{"title":101,"path":269,"stem":270,"icon":25},"\u002Fen\u002Fstockeex\u002Fintroduction","en\u002F4.stockeex\u002F1.introduction",{"title":272,"icon":273,"path":274,"stem":275,"children":276,"page":15},"My nonsense","i-noto-test-tube","\u002Fen\u002Fnonsense","en\u002F5.nonsense",[277,280,302],{"title":272,"path":278,"stem":279,"icon":25},"\u002Fen\u002Fnonsense\u002Fsummary","en\u002F5.nonsense\u002F1.summary",{"title":281,"icon":282,"path":283,"stem":284,"children":285,"page":15},"Python","i-lucide-file-code-2","\u002Fen\u002Fnonsense\u002Fpython","en\u002F5.nonsense\u002F2.python",[286,290,294,298],{"title":287,"path":288,"stem":289},"Nvidia Stock Bot","\u002Fen\u002Fnonsense\u002Fpython\u002Fnvidia-stock-bot","en\u002F5.nonsense\u002F2.python\u002F1.nvidia-stock-bot",{"title":291,"path":292,"stem":293},"Adguard CIDRE","\u002Fen\u002Fnonsense\u002Fpython\u002Fadguard-cidre","en\u002F5.nonsense\u002F2.python\u002F2.adguard-cidre",{"title":295,"path":296,"stem":297},"Lumeex","\u002Fen\u002Fnonsense\u002Fpython\u002Flumeex","en\u002F5.nonsense\u002F2.python\u002F3.lumeex",{"title":299,"path":300,"stem":301},"Instameex","\u002Fen\u002Fnonsense\u002Fpython\u002Finstameex","en\u002F5.nonsense\u002F2.python\u002F4.instameex",{"title":303,"icon":304,"path":305,"stem":306,"children":307,"page":15},"Bash","i-lucide-file-terminal","\u002Fen\u002Fnonsense\u002Fbash","en\u002F5.nonsense\u002F3.bash",[308,312,316,320,324,328],{"title":309,"path":310,"stem":311},"Servarr corrector","\u002Fen\u002Fnonsense\u002Fbash\u002Fservarr-duplicates","en\u002F5.nonsense\u002F3.bash\u002F1.servarr-duplicates",{"title":313,"path":314,"stem":315},"LUKS Backup","\u002Fen\u002Fnonsense\u002Fbash\u002Fluks-backup","en\u002F5.nonsense\u002F3.bash\u002F2.luks-backup",{"title":317,"path":318,"stem":319},"Socat Proxy","\u002Fen\u002Fnonsense\u002Fbash\u002Fsocat-proxy","en\u002F5.nonsense\u002F3.bash\u002F3.socat-proxy",{"title":321,"path":322,"stem":323},"HotDisk","\u002Fen\u002Fnonsense\u002Fbash\u002Fhotdisk","en\u002F5.nonsense\u002F3.bash\u002F4.hotdisk",{"title":325,"path":326,"stem":327},"Backrest Docker Stop","\u002Fen\u002Fnonsense\u002Fbash\u002Fbackrest-docker-stop","en\u002F5.nonsense\u002F3.bash\u002F5.backrest-docker-stop",{"title":329,"path":330,"stem":331},"rm Confirmation Guard","\u002Fen\u002Fnonsense\u002Fbash\u002Frm-confirmation","en\u002F5.nonsense\u002F3.bash\u002F6.rm-confirmation",{"title":333,"icon":334,"path":335,"stem":336,"children":337,"page":15},"Recycled","i-noto-recycling-symbol","\u002Fen\u002Frecycled","en\u002F6.recycled",[338,341,355],{"title":333,"path":339,"stem":340,"icon":25},"\u002Fen\u002Frecycled\u002Fsummary","en\u002F6.recycled\u002F1.summary",{"title":342,"icon":343,"path":344,"stem":345,"children":346,"page":15},"Deprecated","i-lucide-trash-2","\u002Fen\u002Frecycled\u002Fdeprecated","en\u002F6.recycled\u002F2.deprecated",[347,351],{"title":348,"path":349,"stem":350},"Wireguard 14","\u002Fen\u002Frecycled\u002Fdeprecated\u002Fwireguard-14","en\u002F6.recycled\u002F2.deprecated\u002F1.wireguard-14",{"title":352,"path":353,"stem":354},"File Browser","\u002Fen\u002Frecycled\u002Fdeprecated\u002Ffile-browser","en\u002F6.recycled\u002F2.deprecated\u002F2.file-browser",{"title":356,"icon":357,"path":358,"stem":359,"children":360,"page":15},"Alternatives","i-lucide-arrow-left-right","\u002Fen\u002Frecycled\u002Falternatives","en\u002F6.recycled\u002F3.alternatives",[361,365,369,373],{"title":362,"path":363,"stem":364},"Plex","\u002Fen\u002Frecycled\u002Falternatives\u002Fplex","en\u002F6.recycled\u002F3.alternatives\u002F1.plex",{"title":366,"path":367,"stem":368},"Qbittorrent for Plex","\u002Fen\u002Frecycled\u002Falternatives\u002Fqbittorrent-for-plex","en\u002F6.recycled\u002F3.alternatives\u002F2.qbittorrent for plex",{"title":370,"path":371,"stem":372},"Servarr for Plex","\u002Fen\u002Frecycled\u002Falternatives\u002Fservarr-for-plex","en\u002F6.recycled\u002F3.alternatives\u002F3.servarr for plex",{"title":374,"path":375,"stem":376},"Gitea","\u002Fen\u002Frecycled\u002Falternatives\u002Fgitea","en\u002F6.recycled\u002F3.alternatives\u002F4.gitea",{"id":378,"title":137,"body":379,"contributors":2289,"description":2291,"extension":2292,"hideCopyPage":15,"hideHeader":15,"hideToc":15,"links":2293,"meta":2294,"navigation":1059,"path":138,"seo":2295,"stem":139,"__hash__":2296},"docs_en\u002Fen\u002F3.serveex\u002F3.security\u002F3.tinyauth.md",{"type":380,"value":381,"toc":2263},"minimark",[382,390,400,407,419,437,442,446,814,818,821,938,941,945,948,984,1402,1406,1413,1821,1836,1839,1843,1846,1866,1869,2256,2259],[383,384],"ellipsis",{"blur":385,"left":386,"top":387,"width":388,"z-index":389},"140px","0px","10rem","40rem","60",[391,392,393,399],"p",{},[394,395,137],"a",{"href":396,"rel":397},"https:\u002F\u002Ftinyauth.app",[398],"nofollow"," is a small forward-auth proxy: a single login page that Swag can insert in front of any app before letting a request through, checking whether a visitor is authenticated before forwarding them on.",[391,401,402],{},[403,404],"img",{"alt":405,"src":406},"tinyauth","\u002Fimg\u002Fserveex\u002Ftinyauth.png",[391,408,409,410,413,414,418],{},"It supports a simple local username\u002Fpassword login out of the box, which is what we'll set up here. It can also delegate login to an external OIDC provider like ",[394,411,141],{"href":412},"\u002Fserveex\u002Fsecurity\u002Fpocket-id"," instead, so anyone visiting a protected app authenticates with a passkey via Pocket ID and then gets forwarded through: install Pocket ID afterwards and follow ",[394,415,417],{"href":416},"\u002Fserveex\u002Fsecurity\u002Fpocket-id#connecting-pocket-id-to-tinyauth","its guide"," to connect the two.",[420,421,422,430],"ul",{},[423,424,425],"li",{},[394,426,429],{"href":427,"rel":428},"https:\u002F\u002Ftinyauth.app\u002Fdocs",[398],"TinyAuth documentation",[423,431,432],{},[394,433,436],{"href":434,"rel":435},"https:\u002F\u002Fgithub.com\u002Ftinyauthapp\u002Ftinyauth",[398],"TinyAuth on GitHub",[438,439,441],"h2",{"id":440},"installation","Installation",[443,444],"file-tree",{":tree":445},"{\"\u002F\":[{\"srv\":[{\"docker\":[{\"tinyauth\":[\"compose.yaml\",\".env\",\"data\u002F\"]}]}]}]}",[447,448,450,455,486,490,526,534,538,548,663,710,714,720,748,803,810],"steps",{"level":449},"3",[451,452,454],"h3",{"id":453},"create-the-data-folder","Create the data folder",[456,457,463],"pre",{"className":458,"code":459,"filename":460,"language":461,"meta":462,"style":462},"language-bash shiki shiki-themes github-dark material-theme github-dark","sudo mkdir -p \u002Fsrv\u002Fdocker\u002Ftinyauth\u002Fdata\n","Terminal","bash","",[464,465,466],"code",{"__ignoreMap":462},[467,468,471,475,479,483],"span",{"class":469,"line":470},"line",1,[467,472,474],{"class":473},"sEgDM","sudo",[467,476,478],{"class":477},"s11XM"," mkdir",[467,480,482],{"class":481},"sJWha"," -p",[467,484,485],{"class":477}," \u002Fsrv\u002Fdocker\u002Ftinyauth\u002Fdata\n",[451,487,489],{"id":488},"generate-a-password-hash","Generate a password hash",[456,491,493],{"className":458,"code":492,"filename":460,"language":461,"meta":462,"style":462},"sudo docker run -i -t --rm ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5 user create --interactive\n",[464,494,495],{"__ignoreMap":462},[467,496,497,499,502,505,508,511,514,517,520,523],{"class":469,"line":470},[467,498,474],{"class":473},[467,500,501],{"class":477}," docker",[467,503,504],{"class":477}," run",[467,506,507],{"class":481}," -i",[467,509,510],{"class":481}," -t",[467,512,513],{"class":481}," --rm",[467,515,516],{"class":477}," ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5",[467,518,519],{"class":477}," user",[467,521,522],{"class":477}," create",[467,524,525],{"class":481}," --interactive\n",[527,528,529,530,533],"note",{},"Enable \"Format for Docker\" when prompted, so the generated hash is already escaped for use in a ",[464,531,532],{},".env"," file.",[451,535,537],{"id":536},"deploy-the-stack","Deploy the stack",[391,539,540,541,544,545,547],{},"Open Dockge, click ",[464,542,543],{},"compose",", name the stack ",[464,546,405],{},", and add the following config:",[456,549,554],{"className":550,"code":551,"filename":552,"language":553,"meta":462,"style":462},"language-yaml shiki shiki-themes github-dark material-theme github-dark","---\nservices:\n  tinyauth:\n    image: ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5\n    container_name: tinyauth\n    restart: unless-stopped\n    env_file:\n      - .env\n    volumes:\n      - \u002Fsrv\u002Fdocker\u002Ftinyauth\u002Fdata:\u002Fdata\n    ports:\n      - 3000:3000\n","compose.yaml","yaml",[464,555,556,561,572,580,592,603,614,622,631,639,647,655],{"__ignoreMap":462},[467,557,558],{"class":469,"line":470},[467,559,560],{"class":473},"---\n",[467,562,564,568],{"class":469,"line":563},2,[467,565,567],{"class":566},"sRuoG","services",[467,569,571],{"class":570},"s8jd1",":\n",[467,573,575,578],{"class":469,"line":574},3,[467,576,577],{"class":566},"  tinyauth",[467,579,571],{"class":570},[467,581,583,586,589],{"class":469,"line":582},4,[467,584,585],{"class":566},"    image",[467,587,588],{"class":570},":",[467,590,591],{"class":477}," ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5\n",[467,593,595,598,600],{"class":469,"line":594},5,[467,596,597],{"class":566},"    container_name",[467,599,588],{"class":570},[467,601,602],{"class":477}," tinyauth\n",[467,604,606,609,611],{"class":469,"line":605},6,[467,607,608],{"class":566},"    restart",[467,610,588],{"class":570},[467,612,613],{"class":477}," unless-stopped\n",[467,615,617,620],{"class":469,"line":616},7,[467,618,619],{"class":566},"    env_file",[467,621,571],{"class":570},[467,623,625,628],{"class":469,"line":624},8,[467,626,627],{"class":570},"      -",[467,629,630],{"class":477}," .env\n",[467,632,634,637],{"class":469,"line":633},9,[467,635,636],{"class":566},"    volumes",[467,638,571],{"class":570},[467,640,642,644],{"class":469,"line":641},10,[467,643,627],{"class":570},[467,645,646],{"class":477}," \u002Fsrv\u002Fdocker\u002Ftinyauth\u002Fdata:\u002Fdata\n",[467,648,650,653],{"class":469,"line":649},11,[467,651,652],{"class":566},"    ports",[467,654,571],{"class":570},[467,656,658,660],{"class":469,"line":657},12,[467,659,627],{"class":570},[467,661,662],{"class":477}," 3000:3000\n",[664,665,666,669],"tip",{"icon":462},[391,667,668],{},"✨ Add the Watchtower label to automate updates:",[456,670,672],{"className":550,"code":671,"filename":552,"language":553,"meta":462,"style":462},"---\nservices:\n  tinyauth:\n    #...\n    labels:\n      - com.centurylinklabs.watchtower.enable=true\n",[464,673,674,678,684,690,696,703],{"__ignoreMap":462},[467,675,676],{"class":469,"line":470},[467,677,560],{"class":473},[467,679,680,682],{"class":469,"line":563},[467,681,567],{"class":566},[467,683,571],{"class":570},[467,685,686,688],{"class":469,"line":574},[467,687,577],{"class":566},[467,689,571],{"class":570},[467,691,692],{"class":469,"line":582},[467,693,695],{"class":694},"sDvJj","    #...\n",[467,697,698,701],{"class":469,"line":594},[467,699,700],{"class":566},"    labels",[467,702,571],{"class":570},[467,704,705,707],{"class":469,"line":605},[467,706,627],{"class":570},[467,708,709],{"class":477}," com.centurylinklabs.watchtower.enable=true\n",[451,711,713],{"id":712},"set-your-environment-variables","Set your environment variables",[391,715,716,717,719],{},"Fill in the ",[464,718,532],{}," file:",[456,721,725],{"className":722,"code":723,"filename":532,"language":724,"meta":462,"style":462},"language-properties shiki shiki-themes github-dark material-theme github-dark","TINYAUTH_APPURL=https:\u002F\u002Ftinyauth.mydomain.com\nTINYAUTH_AUTH_USERS=\n","properties",[464,726,727,740],{"__ignoreMap":462},[467,728,729,733,736],{"class":469,"line":470},[467,730,732],{"class":731},"szyEh","TINYAUTH_APPURL",[467,734,735],{"class":570},"=",[467,737,739],{"class":738},"slcoZ","https:\u002F\u002Ftinyauth.mydomain.com\n",[467,741,742,745],{"class":469,"line":563},[467,743,744],{"class":731},"TINYAUTH_AUTH_USERS",[467,746,747],{"class":570},"=\n",[749,750,751,767],"table",{},[752,753,754],"thead",{},[755,756,757,761,764],"tr",{},[758,759,760],"th",{},"Variable",[758,762,763],{},"Value",[758,765,766],{},"Example",[768,769,770,787],"tbody",{},[755,771,772,779,782],{},[773,774,775],"td",{},[464,776,777],{"className":722,"language":724,"style":462},[467,778,732],{"class":738},[773,780,781],{},"The public URL you'll use to reach TinyAuth (see exposure below)",[773,783,784],{},[464,785,786],{},"https:\u002F\u002Ftinyauth.mydomain.com",[755,788,789,795,798],{},[773,790,791],{},[464,792,793],{"className":722,"language":724,"style":462},[467,794,744],{"class":738},[773,796,797],{},"The hash generated above",[773,799,800],{},[464,801,802],{},"user:$$2a$$10$$UdLYoJ5lgPsC0RKq...",[391,804,805,806,809],{},"Deploy the stack. The local interface is available at ",[464,807,808],{},"http:\u002F\u002Fyourserverip:3000",".",[451,811,813],{"id":812},"done","Done !",[438,815,817],{"id":816},"enabling-two-factor-authentication","Enabling Two-Factor Authentication",[391,819,820],{},"TinyAuth can require a TOTP code from an authenticator app (Google Authenticator, Aegis...) alongside the local password, per user. This is a property of the user entry itself, not a toggle in the web UI.",[447,822,823,827,856,866,881,885,894,935],{"level":449},[451,824,826],{"id":825},"generate-a-totp-secret","Generate a TOTP secret",[456,828,830],{"className":458,"code":829,"filename":460,"language":461,"meta":462,"style":462},"sudo docker run -i -t --rm ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5 totp generate --interactive\n",[464,831,832],{"__ignoreMap":462},[467,833,834,836,838,840,842,844,846,848,851,854],{"class":469,"line":470},[467,835,474],{"class":473},[467,837,501],{"class":477},[467,839,504],{"class":477},[467,841,507],{"class":481},[467,843,510],{"class":481},[467,845,513],{"class":481},[467,847,516],{"class":477},[467,849,850],{"class":477}," totp",[467,852,853],{"class":477}," generate",[467,855,525],{"class":481},[391,857,858,859,862,863,809],{},"Enter the ",[464,860,861],{},"username:hash"," pair you generated during installation. TinyAuth prints a QR code to scan with your authenticator app, then outputs the updated login string as ",[464,864,865],{},"username:hash:secret",[527,867,868,869,872,873,876,877,880],{},"Both ",[464,870,871],{},"docker run"," and ",[464,874,875],{},"docker exec"," need the ",[464,878,879],{},"-it"," flags here: the command is interactive and renders the QR code in the terminal, which needs a TTY (and a wide enough window) to display correctly.",[451,882,884],{"id":883},"update-your-environment-variable","Update your environment variable",[391,886,887,888,890,891,893],{},"Replace that user's entry in ",[464,889,744],{}," with the new ",[464,892,865],{}," string, then redeploy the stack.",[664,895,896,904,932],{"icon":462},[391,897,898,899,903],{},"✨ ",[900,901,902],"strong",{},"Tip:"," Verify the flow works before relying on it:",[456,905,907],{"className":458,"code":906,"filename":460,"language":461,"meta":462,"style":462},"sudo docker run -i -t --rm ghcr.io\u002Ftinyauthapp\u002Ftinyauth:v5 user verify --interactive\n",[464,908,909],{"__ignoreMap":462},[467,910,911,913,915,917,919,921,923,925,927,930],{"class":469,"line":470},[467,912,474],{"class":473},[467,914,501],{"class":477},[467,916,504],{"class":477},[467,918,507],{"class":481},[467,920,510],{"class":481},[467,922,513],{"class":481},[467,924,516],{"class":477},[467,926,519],{"class":477},[467,928,929],{"class":477}," verify",[467,931,525],{"class":481},[391,933,934],{},"It re-prompts for the username, password, and current 6-digit code.",[451,936,813],{"id":937},"done-1",[391,939,940],{},"From now on, that user needs both their password and a valid code from their authenticator app to log in.",[438,942,944],{"id":943},"exposing-tinyauth-with-swag","Exposing TinyAuth with Swag",[391,946,947],{},"TinyAuth needs its own subdomain: it's the page users land on before being forwarded to the app they actually want.",[527,949,950,951,954,955,958,959,962,963,967,968,972,973,976,977,979,980,809],{},"We assume you have the subdomain ",[464,952,953],{},"tinyauth.mydomain.com"," with a ",[464,956,957],{},"CNAME"," pointing to ",[464,960,961],{},"mydomain.com"," in your ",[394,964,966],{"href":965},"\u002Fgeneral\u002Fnetworking\u002Fdns","DNS zone",". And of course, ",[394,969,971],{"href":970},"\u002Fserveex\u002Fsecurity\u002Fcloudflare","unless you use Cloudflare Zero Trust",", your box's port ",[464,974,975],{},"443"," must be forwarded to your server's port ",[464,978,975],{}," in ",[394,981,983],{"href":982},"\u002Fgeneral\u002Fnetworking\u002Fnat","NAT rules",[447,985,986,990,993,1114,1117,1127,1131,1137,1146,1161,1164,1366,1382,1386,1392,1399],{"level":449},[451,987,989],{"id":988},"add-tinyauths-network-to-swag","Add TinyAuth's network to SWAG",[391,991,992],{},"Go to Dockge and edit SWAG's compose file by adding TinyAuth's network:",[456,994,996],{"className":550,"code":995,"filename":552,"language":553,"meta":462,"style":462},"---\nservices:\n  swag:\n     container_name: # ...\n      # ... \n     networks:               # Attach container to custom network \n      # ...           \n      - tinyauth             # Name of the declared network\n\nnetworks:                    # Define the custom network\n  # ...\n  tinyauth:                  # Declared network name\n    name: tinyauth_default   # Actual external network name\n    external: true           # Marks it as externally defined\n",[464,997,998,1002,1008,1015,1025,1030,1040,1045,1055,1061,1071,1076,1085,1099],{"__ignoreMap":462},[467,999,1000],{"class":469,"line":470},[467,1001,560],{"class":473},[467,1003,1004,1006],{"class":469,"line":563},[467,1005,567],{"class":566},[467,1007,571],{"class":570},[467,1009,1010,1013],{"class":469,"line":574},[467,1011,1012],{"class":566},"  swag",[467,1014,571],{"class":570},[467,1016,1017,1020,1022],{"class":469,"line":582},[467,1018,1019],{"class":566},"     container_name",[467,1021,588],{"class":570},[467,1023,1024],{"class":694}," # ...\n",[467,1026,1027],{"class":469,"line":594},[467,1028,1029],{"class":694},"      # ... \n",[467,1031,1032,1035,1037],{"class":469,"line":605},[467,1033,1034],{"class":566},"     networks",[467,1036,588],{"class":570},[467,1038,1039],{"class":694},"               # Attach container to custom network \n",[467,1041,1042],{"class":469,"line":616},[467,1043,1044],{"class":694},"      # ...           \n",[467,1046,1047,1049,1052],{"class":469,"line":624},[467,1048,627],{"class":570},[467,1050,1051],{"class":477}," tinyauth",[467,1053,1054],{"class":694},"             # Name of the declared network\n",[467,1056,1057],{"class":469,"line":633},[467,1058,1060],{"emptyLinePlaceholder":1059},true,"\n",[467,1062,1063,1066,1068],{"class":469,"line":641},[467,1064,1065],{"class":566},"networks",[467,1067,588],{"class":570},[467,1069,1070],{"class":694},"                    # Define the custom network\n",[467,1072,1073],{"class":469,"line":649},[467,1074,1075],{"class":694},"  # ...\n",[467,1077,1078,1080,1082],{"class":469,"line":657},[467,1079,577],{"class":566},[467,1081,588],{"class":570},[467,1083,1084],{"class":694},"                  # Declared network name\n",[467,1086,1088,1091,1093,1096],{"class":469,"line":1087},13,[467,1089,1090],{"class":566},"    name",[467,1092,588],{"class":570},[467,1094,1095],{"class":477}," tinyauth_default",[467,1097,1098],{"class":694},"   # Actual external network name\n",[467,1100,1102,1105,1107,1111],{"class":469,"line":1101},14,[467,1103,1104],{"class":566},"    external",[467,1106,588],{"class":570},[467,1108,1110],{"class":1109},"s08Ry"," true",[467,1112,1113],{"class":694},"           # Marks it as externally defined\n",[391,1115,1116],{},"Redeploy the stack and wait for SWAG to be fully operational.",[527,1118,1119,1120,1123,1124,809],{},"Here we assume the TinyAuth network name is ",[464,1121,1122],{},"tinyauth_default",". You can check the connection by visiting SWAG's dashboard at ",[464,1125,1126],{},"http:\u002F\u002Fyourserverip:81",[451,1128,1130],{"id":1129},"create-the-subdomainconf-file","Create the subdomain.conf file",[391,1132,1133,1134,588],{},"In the Swag folders, create the file ",[464,1135,1136],{},"tinyauth.subdomain.conf",[664,1138,898,1140,1142,1143,1145],{"icon":462,"to":1139},"\u002Fserveex\u002Ffiles\u002Ffile-browser-quantum",[900,1141,902],{}," Use ",[900,1144,209],{}," to navigate and edit files instead of using terminal commands.",[456,1147,1149],{"className":458,"code":1148,"filename":460,"language":461,"meta":462,"style":462},"sudo nano \u002Fsrv\u002Fdocker\u002Fswag\u002Fconfig\u002Fnginx\u002Fproxy-confs\u002Ftinyauth.subdomain.conf\n",[464,1150,1151],{"__ignoreMap":462},[467,1152,1153,1155,1158],{"class":469,"line":470},[467,1154,474],{"class":473},[467,1156,1157],{"class":477}," nano",[467,1159,1160],{"class":477}," \u002Fsrv\u002Fdocker\u002Fswag\u002Fconfig\u002Fnginx\u002Fproxy-confs\u002Ftinyauth.subdomain.conf\n",[391,1162,1163],{},"Paste the following configuration:",[456,1165,1169],{"className":1166,"code":1167,"filename":1136,"language":1168,"meta":462,"style":462},"language-nginx shiki shiki-themes github-dark material-theme github-dark","## Version 2023\u002F12\u002F19\n\nserver {\n    listen 443 ssl;\n    listen [::]:443 ssl;\n\n    server_name tinyauth.*;\n\n    include \u002Fconfig\u002Fnginx\u002Fssl.conf;\n\n    client_max_body_size 0;\n\n    location \u002F {\n        include \u002Fconfig\u002Fnginx\u002Fproxy.conf;\n        include \u002Fconfig\u002Fnginx\u002Fresolver.conf;\n        set $upstream_app tinyauth;\n        set $upstream_port 3000;\n        set $upstream_proto http;\n        proxy_pass $upstream_proto:\u002F\u002F$upstream_app:$upstream_port;\n    }\n}\n","nginx",[464,1170,1171,1176,1180,1189,1204,1213,1217,1227,1231,1241,1245,1255,1259,1270,1280,1290,1304,1319,1331,1354,1360],{"__ignoreMap":462},[467,1172,1173],{"class":469,"line":470},[467,1174,1175],{"class":694},"## Version 2023\u002F12\u002F19\n",[467,1177,1178],{"class":469,"line":563},[467,1179,1060],{"emptyLinePlaceholder":1059},[467,1181,1182,1186],{"class":469,"line":574},[467,1183,1185],{"class":1184},"sAoO4","server",[467,1187,1188],{"class":738}," {\n",[467,1190,1191,1195,1198,1201],{"class":469,"line":582},[467,1192,1194],{"class":1193},"sJPTy","    listen ",[467,1196,975],{"class":1197},"swwWl",[467,1199,1200],{"class":738}," ssl",[467,1202,1203],{"class":570},";\n",[467,1205,1206,1208,1211],{"class":469,"line":594},[467,1207,1194],{"class":1193},[467,1209,1210],{"class":738},"[::]:443 ssl",[467,1212,1203],{"class":570},[467,1214,1215],{"class":469,"line":605},[467,1216,1060],{"emptyLinePlaceholder":1059},[467,1218,1219,1222,1225],{"class":469,"line":616},[467,1220,1221],{"class":1193},"    server_name ",[467,1223,1224],{"class":738},"tinyauth.*",[467,1226,1203],{"class":570},[467,1228,1229],{"class":469,"line":624},[467,1230,1060],{"emptyLinePlaceholder":1059},[467,1232,1233,1236,1239],{"class":469,"line":633},[467,1234,1235],{"class":1193},"    include ",[467,1237,1238],{"class":738},"\u002Fconfig\u002Fnginx\u002Fssl.conf",[467,1240,1203],{"class":570},[467,1242,1243],{"class":469,"line":641},[467,1244,1060],{"emptyLinePlaceholder":1059},[467,1246,1247,1250,1253],{"class":469,"line":649},[467,1248,1249],{"class":1193},"    client_max_body_size ",[467,1251,1252],{"class":1197},"0",[467,1254,1203],{"class":570},[467,1256,1257],{"class":469,"line":657},[467,1258,1060],{"emptyLinePlaceholder":1059},[467,1260,1261,1264,1267],{"class":469,"line":1087},[467,1262,1263],{"class":1184},"    location",[467,1265,1266],{"class":473}," \u002F ",[467,1268,1269],{"class":738},"{\n",[467,1271,1272,1275,1278],{"class":469,"line":1101},[467,1273,1274],{"class":1193},"        include ",[467,1276,1277],{"class":738},"\u002Fconfig\u002Fnginx\u002Fproxy.conf",[467,1279,1203],{"class":570},[467,1281,1283,1285,1288],{"class":469,"line":1282},15,[467,1284,1274],{"class":1193},[467,1286,1287],{"class":738},"\u002Fconfig\u002Fnginx\u002Fresolver.conf",[467,1289,1203],{"class":570},[467,1291,1293,1296,1299,1302],{"class":469,"line":1292},16,[467,1294,1295],{"class":1193},"        set ",[467,1297,1298],{"class":570},"$",[467,1300,1301],{"class":738},"upstream_app tinyauth",[467,1303,1203],{"class":570},[467,1305,1307,1309,1311,1314,1317],{"class":469,"line":1306},17,[467,1308,1295],{"class":1193},[467,1310,1298],{"class":570},[467,1312,1313],{"class":738},"upstream_port ",[467,1315,1316],{"class":1197},"3000",[467,1318,1203],{"class":570},[467,1320,1322,1324,1326,1329],{"class":469,"line":1321},18,[467,1323,1295],{"class":1193},[467,1325,1298],{"class":570},[467,1327,1328],{"class":738},"upstream_proto http",[467,1330,1203],{"class":570},[467,1332,1334,1337,1339,1342,1344,1347,1349,1352],{"class":469,"line":1333},19,[467,1335,1336],{"class":1193},"        proxy_pass ",[467,1338,1298],{"class":570},[467,1340,1341],{"class":738},"upstream_proto:\u002F\u002F",[467,1343,1298],{"class":570},[467,1345,1346],{"class":738},"upstream_app:",[467,1348,1298],{"class":570},[467,1350,1351],{"class":738},"upstream_port",[467,1353,1203],{"class":570},[467,1355,1357],{"class":469,"line":1356},20,[467,1358,1359],{"class":738},"    }\n",[467,1361,1363],{"class":469,"line":1362},21,[467,1364,1365],{"class":738},"}\n",[391,1367,1368,1369,1373,1374,1377,1378,1381],{},"Press ",[1370,1371],"kbd",{"value":1372},"Ctrl+O",", then ",[1370,1375],{"value":1376},"Enter"," to save, and ",[1370,1379],{"value":1380},"Ctrl+X"," to exit.",[451,1383,1385],{"id":1384},"visit-your-new-subdomain","Visit your new subdomain",[391,1387,1388,1389,1391],{},"Wait a few minutes, then open ",[464,1390,786],{}," in your browser and log in with the username\u002Fpassword you created above.",[1393,1394,1395,1398],"caution",{},[900,1396,1397],{},"If it fails:"," check your firewall rules.",[451,1400,813],{"id":1401},"done-2",[438,1403,1405],{"id":1404},"protecting-an-app-via-reverse-proxy","Protecting an app via reverse proxy",[391,1407,1408,1409,1412],{},"Swag doesn't ship a ready-made include file for TinyAuth, so we'll add the forward-auth check directly to the app's own ",[464,1410,1411],{},"*.subdomain.conf",". We'll use Dockge as an example.",[447,1414,1415,1419,1433,1437,1451,1795,1810,1818],{"level":449},[451,1416,1418],{"id":1417},"open-the-apps-subdomainconf-file","Open the app's subdomain.conf file",[456,1420,1422],{"className":458,"code":1421,"filename":460,"language":461,"meta":462,"style":462},"sudo nano \u002Fsrv\u002Fdocker\u002Fswag\u002Fconfig\u002Fnginx\u002Fproxy-confs\u002Fdockge.subdomain.conf\n",[464,1423,1424],{"__ignoreMap":462},[467,1425,1426,1428,1430],{"class":469,"line":470},[467,1427,474],{"class":473},[467,1429,1157],{"class":477},[467,1431,1432],{"class":477}," \u002Fsrv\u002Fdocker\u002Fswag\u002Fconfig\u002Fnginx\u002Fproxy-confs\u002Fdockge.subdomain.conf\n",[451,1434,1436],{"id":1435},"add-the-forward-auth-check","Add the forward-auth check",[391,1438,1439,1440,1443,1444,1447,1448,588],{},"Add an internal ",[464,1441,1442],{},"\u002Ftinyauth"," location, and reference it from the app's ",[464,1445,1446],{},"location \u002F"," block with ",[464,1449,1450],{},"auth_request",[456,1452,1457],{"className":1166,"code":1453,"filename":1454,"highlights":1455,"language":1168,"meta":462,"style":462},"server {\n    listen 443 ssl;\n    listen [::]:443 ssl;\n\n    server_name dockge.*;\n\n    include \u002Fconfig\u002Fnginx\u002Fssl.conf;\n\n    client_max_body_size 0;\n\n    location \u002Ftinyauth {\n        internal;\n        proxy_pass http:\u002F\u002Ftinyauth:3000\u002Fapi\u002Fauth\u002Fnginx;\n        proxy_pass_request_body off;\n        proxy_set_header Content-Length \"\";\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header X-Forwarded-Host $http_host;\n        proxy_set_header X-Forwarded-Uri $request_uri;\n    }\n\n    location @tinyauth_login {\n        return 302 https:\u002F\u002Ftinyauth.mydomain.com\u002Flogin?redirect_uri=$scheme:\u002F\u002F$http_host$request_uri;\n    }\n\n    location \u002F {\n        auth_request \u002Ftinyauth;\n        error_page 401 = @tinyauth_login;\n\n        include \u002Fconfig\u002Fnginx\u002Fproxy.conf;\n        include \u002Fconfig\u002Fnginx\u002Fresolver.conf;\n        set $upstream_app dockge;\n        set $upstream_port 5001;\n        set $upstream_proto http;\n        proxy_pass $upstream_proto:\u002F\u002F$upstream_app:$upstream_port;\n    }\n}\n","dockge.subdomain.conf",[633,641,649,1456],25,[464,1458,1459,1465,1475,1483,1487,1496,1500,1508,1512,1522,1527,1537,1544,1553,1564,1577,1591,1605,1619,1623,1627,1636,1663,1668,1673,1682,1692,1706,1711,1720,1729,1741,1755,1766,1785,1790],{"__ignoreMap":462},[467,1460,1461,1463],{"class":469,"line":470},[467,1462,1185],{"class":1184},[467,1464,1188],{"class":738},[467,1466,1467,1469,1471,1473],{"class":469,"line":563},[467,1468,1194],{"class":1193},[467,1470,975],{"class":1197},[467,1472,1200],{"class":738},[467,1474,1203],{"class":570},[467,1476,1477,1479,1481],{"class":469,"line":574},[467,1478,1194],{"class":1193},[467,1480,1210],{"class":738},[467,1482,1203],{"class":570},[467,1484,1485],{"class":469,"line":582},[467,1486,1060],{"emptyLinePlaceholder":1059},[467,1488,1489,1491,1494],{"class":469,"line":594},[467,1490,1221],{"class":1193},[467,1492,1493],{"class":738},"dockge.*",[467,1495,1203],{"class":570},[467,1497,1498],{"class":469,"line":605},[467,1499,1060],{"emptyLinePlaceholder":1059},[467,1501,1502,1504,1506],{"class":469,"line":616},[467,1503,1235],{"class":1193},[467,1505,1238],{"class":738},[467,1507,1203],{"class":570},[467,1509,1510],{"class":469,"line":624},[467,1511,1060],{"emptyLinePlaceholder":1059},[467,1513,1516,1518,1520],{"class":1514,"line":633},[469,1515],"highlight",[467,1517,1249],{"class":1193},[467,1519,1252],{"class":1197},[467,1521,1203],{"class":570},[467,1523,1525],{"class":1524,"line":641},[469,1515],[467,1526,1060],{"emptyLinePlaceholder":1059},[467,1528,1530,1532,1535],{"class":1529,"line":649},[469,1515],[467,1531,1263],{"class":1184},[467,1533,1534],{"class":473}," \u002Ftinyauth ",[467,1536,1269],{"class":738},[467,1538,1539,1542],{"class":469,"line":657},[467,1540,1541],{"class":1193},"        internal",[467,1543,1203],{"class":570},[467,1545,1546,1548,1551],{"class":469,"line":1087},[467,1547,1336],{"class":1193},[467,1549,1550],{"class":738},"http:\u002F\u002Ftinyauth:3000\u002Fapi\u002Fauth\u002Fnginx",[467,1552,1203],{"class":570},[467,1554,1555,1558,1562],{"class":469,"line":1101},[467,1556,1557],{"class":1193},"        proxy_pass_request_body ",[467,1559,1561],{"class":1560},"soUAX","off",[467,1563,1203],{"class":570},[467,1565,1566,1569,1572,1575],{"class":469,"line":1282},[467,1567,1568],{"class":1193},"        proxy_set_header ",[467,1570,1571],{"class":738},"Content-Length ",[467,1573,1574],{"class":477},"\"\"",[467,1576,1203],{"class":570},[467,1578,1579,1581,1584,1586,1589],{"class":469,"line":1292},[467,1580,1568],{"class":1193},[467,1582,1583],{"class":738},"X-Forwarded-Proto ",[467,1585,1298],{"class":570},[467,1587,1588],{"class":738},"scheme",[467,1590,1203],{"class":570},[467,1592,1593,1595,1598,1600,1603],{"class":469,"line":1306},[467,1594,1568],{"class":1193},[467,1596,1597],{"class":738},"X-Forwarded-Host ",[467,1599,1298],{"class":570},[467,1601,1602],{"class":738},"http_host",[467,1604,1203],{"class":570},[467,1606,1607,1609,1612,1614,1617],{"class":469,"line":1321},[467,1608,1568],{"class":1193},[467,1610,1611],{"class":738},"X-Forwarded-Uri ",[467,1613,1298],{"class":570},[467,1615,1616],{"class":738},"request_uri",[467,1618,1203],{"class":570},[467,1620,1621],{"class":469,"line":1333},[467,1622,1359],{"class":738},[467,1624,1625],{"class":469,"line":1356},[467,1626,1060],{"emptyLinePlaceholder":1059},[467,1628,1629,1631,1634],{"class":469,"line":1362},[467,1630,1263],{"class":1184},[467,1632,1633],{"class":473}," @tinyauth_login ",[467,1635,1269],{"class":738},[467,1637,1639,1643,1646,1649,1651,1654,1656,1658,1660],{"class":469,"line":1638},22,[467,1640,1642],{"class":1641},"sJLGa","        return",[467,1644,1645],{"class":1197}," 302",[467,1647,1648],{"class":738}," https:\u002F\u002Ftinyauth.mydomain.com\u002Flogin?redirect_uri=",[467,1650,1298],{"class":570},[467,1652,1653],{"class":738},"scheme:\u002F\u002F",[467,1655,1298],{"class":570},[467,1657,1602],{"class":738},[467,1659,1298],{"class":570},[467,1661,1662],{"class":738},"request_uri;\n",[467,1664,1666],{"class":469,"line":1665},23,[467,1667,1359],{"class":738},[467,1669,1671],{"class":469,"line":1670},24,[467,1672,1060],{"emptyLinePlaceholder":1059},[467,1674,1676,1678,1680],{"class":1675,"line":1456},[469,1515],[467,1677,1263],{"class":1184},[467,1679,1266],{"class":473},[467,1681,1269],{"class":738},[467,1683,1685,1688,1690],{"class":469,"line":1684},26,[467,1686,1687],{"class":1193},"        auth_request ",[467,1689,1442],{"class":738},[467,1691,1203],{"class":570},[467,1693,1695,1698,1701,1704],{"class":469,"line":1694},27,[467,1696,1697],{"class":1193},"        error_page ",[467,1699,1700],{"class":1197},"401",[467,1702,1703],{"class":738}," = @tinyauth_login",[467,1705,1203],{"class":570},[467,1707,1709],{"class":469,"line":1708},28,[467,1710,1060],{"emptyLinePlaceholder":1059},[467,1712,1714,1716,1718],{"class":469,"line":1713},29,[467,1715,1274],{"class":1193},[467,1717,1277],{"class":738},[467,1719,1203],{"class":570},[467,1721,1723,1725,1727],{"class":469,"line":1722},30,[467,1724,1274],{"class":1193},[467,1726,1287],{"class":738},[467,1728,1203],{"class":570},[467,1730,1732,1734,1736,1739],{"class":469,"line":1731},31,[467,1733,1295],{"class":1193},[467,1735,1298],{"class":570},[467,1737,1738],{"class":738},"upstream_app dockge",[467,1740,1203],{"class":570},[467,1742,1744,1746,1748,1750,1753],{"class":469,"line":1743},32,[467,1745,1295],{"class":1193},[467,1747,1298],{"class":570},[467,1749,1313],{"class":738},[467,1751,1752],{"class":1197},"5001",[467,1754,1203],{"class":570},[467,1756,1758,1760,1762,1764],{"class":469,"line":1757},33,[467,1759,1295],{"class":1193},[467,1761,1298],{"class":570},[467,1763,1328],{"class":738},[467,1765,1203],{"class":570},[467,1767,1769,1771,1773,1775,1777,1779,1781,1783],{"class":469,"line":1768},34,[467,1770,1336],{"class":1193},[467,1772,1298],{"class":570},[467,1774,1341],{"class":738},[467,1776,1298],{"class":570},[467,1778,1346],{"class":738},[467,1780,1298],{"class":570},[467,1782,1351],{"class":738},[467,1784,1203],{"class":570},[467,1786,1788],{"class":469,"line":1787},35,[467,1789,1359],{"class":738},[467,1791,1793],{"class":469,"line":1792},36,[467,1794,1365],{"class":738},[527,1796,1798,1799,1802,1803,1805,1806,1809],{"to":1797},"\u002Fserveex\u002Fsecurity\u002Ftinyauth#exposing-tinyauth-with-swag","The ",[464,1800,1801],{},"location \u002Ftinyauth"," block runs inside SWAG's own container, so SWAG needs to be on TinyAuth's Docker network to reach it by name (",[464,1804,405],{}," here). This should already be set up from ",[900,1807,1808],{},"exposing TinyAuth itself",". If you run into an error, double-check SWAG's compose file still has that network attached.",[391,1811,1368,1812,1373,1814,1377,1816,1381],{},[1370,1813],{"value":1372},[1370,1815],{"value":1376},[1370,1817],{"value":1380},[451,1819,813],{"id":1820},"done-3",[391,1822,1823,1824,1827,1828,1266,1830,1832,1833,1835],{},"That's it! Visiting ",[464,1825,1826],{},"https:\u002F\u002Fdockge.mydomain.com"," now redirects to TinyAuth first. Repeat this ",[464,1829,1801],{},[464,1831,1450],{}," pattern in any other app's ",[464,1834,1411],{}," to protect it the same way.",[527,1837,1838],{},"Repeat this process for each app you want to protect (unless it has native OIDC support, in which case you can point it directly at Pocket ID instead).",[438,1840,1842],{"id":1841},"leaving-specific-paths-public","Leaving specific paths public",[391,1844,1845],{},"Sometimes you want most of an app locked behind TinyAuth, but a handful of paths left open, for example a public status page, or the API endpoints a mobile app relies on. Unlike Authentik, TinyAuth has no built-in \"authenticated paths\" setting for this: it's a plain nginx problem, and it's solved with nginx's own location matching.",[391,1847,1848,1849,1852,1853,1855,1856,1859,1860,1863,1864,809],{},"A regex ",[464,1850,1851],{},"location"," block always takes priority over the plain ",[464,1854,1446],{}," block, no matter which one appears first in the file. So any path matched by a regex location you define runs its own ",[464,1857,1858],{},"proxy_pass",", without ever reaching the ",[464,1861,1862],{},"auth_request \u002Ftinyauth;"," line in ",[464,1865,1446],{},[391,1867,1868],{},"For example, to leave Uptime-Kuma's public status page and its assets open while protecting everything else:",[456,1870,1873],{"className":1166,"code":1871,"filename":1454,"highlights":1872,"language":1168,"meta":462,"style":462},"server {\n    listen 443 ssl;\n    listen [::]:443 ssl;\n\n    server_name stats.*;\n\n    include \u002Fconfig\u002Fnginx\u002Fssl.conf;\n\n    location ~ ^\u002F(status|assets|icon\\.svg|api|upload|metrics) {\n        include \u002Fconfig\u002Fnginx\u002Fproxy.conf;\n        include \u002Fconfig\u002Fnginx\u002Fresolver.conf;\n        set $upstream_app uptime-kuma;\n        set $upstream_port 3001;\n        set $upstream_proto http;\n        proxy_pass $upstream_proto:\u002F\u002F$upstream_app:$upstream_port;\n    }\n\n    location \u002Ftinyauth {\n        internal;\n        proxy_pass http:\u002F\u002Ftinyauth:3000\u002Fapi\u002Fauth\u002Fnginx;\n        proxy_pass_request_body off;\n        proxy_set_header Content-Length \"\";\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header X-Forwarded-Host $http_host;\n        proxy_set_header X-Forwarded-Uri $request_uri;\n    }\n\n    location @tinyauth_login {\n        return 302 https:\u002F\u002Ftinyauth.mydomain.com\u002Flogin?redirect_uri=$scheme:\u002F\u002F$http_host$request_uri;\n    }\n\n    location \u002F {\n        auth_request \u002Ftinyauth;\n        error_page 401 = @tinyauth_login;\n\n        include \u002Fconfig\u002Fnginx\u002Fproxy.conf;\n        include \u002Fconfig\u002Fnginx\u002Fresolver.conf;\n        set $upstream_app uptime-kuma;\n        set $upstream_port 3001;\n        set $upstream_proto http;\n        proxy_pass $upstream_proto:\u002F\u002F$upstream_app:$upstream_port;\n    }\n}\n",[633,641,649,657,1087,1101,1282,1292],[464,1874,1875,1881,1891,1899,1903,1912,1916,1924,1928,1942,1951,1960,1972,1986,1997,2016,2021,2025,2033,2039,2047,2055,2065,2077,2089,2101,2105,2109,2117,2137,2141,2145,2153,2161,2171,2175,2183,2192,2203,2216,2227,2246,2251],{"__ignoreMap":462},[467,1876,1877,1879],{"class":469,"line":470},[467,1878,1185],{"class":1184},[467,1880,1188],{"class":738},[467,1882,1883,1885,1887,1889],{"class":469,"line":563},[467,1884,1194],{"class":1193},[467,1886,975],{"class":1197},[467,1888,1200],{"class":738},[467,1890,1203],{"class":570},[467,1892,1893,1895,1897],{"class":469,"line":574},[467,1894,1194],{"class":1193},[467,1896,1210],{"class":738},[467,1898,1203],{"class":570},[467,1900,1901],{"class":469,"line":582},[467,1902,1060],{"emptyLinePlaceholder":1059},[467,1904,1905,1907,1910],{"class":469,"line":594},[467,1906,1221],{"class":1193},[467,1908,1909],{"class":738},"stats.*",[467,1911,1203],{"class":570},[467,1913,1914],{"class":469,"line":605},[467,1915,1060],{"emptyLinePlaceholder":1059},[467,1917,1918,1920,1922],{"class":469,"line":616},[467,1919,1235],{"class":1193},[467,1921,1238],{"class":738},[467,1923,1203],{"class":570},[467,1925,1926],{"class":469,"line":624},[467,1927,1060],{"emptyLinePlaceholder":1059},[467,1929,1931,1933,1936,1940],{"class":1930,"line":633},[469,1515],[467,1932,1263],{"class":1184},[467,1934,1935],{"class":1193}," ~",[467,1937,1939],{"class":1938},"sxjBU"," ^\u002F(status|assets|icon\\.svg|api|upload|metrics) ",[467,1941,1269],{"class":738},[467,1943,1945,1947,1949],{"class":1944,"line":641},[469,1515],[467,1946,1274],{"class":1193},[467,1948,1277],{"class":738},[467,1950,1203],{"class":570},[467,1952,1954,1956,1958],{"class":1953,"line":649},[469,1515],[467,1955,1274],{"class":1193},[467,1957,1287],{"class":738},[467,1959,1203],{"class":570},[467,1961,1963,1965,1967,1970],{"class":1962,"line":657},[469,1515],[467,1964,1295],{"class":1193},[467,1966,1298],{"class":570},[467,1968,1969],{"class":738},"upstream_app uptime-kuma",[467,1971,1203],{"class":570},[467,1973,1975,1977,1979,1981,1984],{"class":1974,"line":1087},[469,1515],[467,1976,1295],{"class":1193},[467,1978,1298],{"class":570},[467,1980,1313],{"class":738},[467,1982,1983],{"class":1197},"3001",[467,1985,1203],{"class":570},[467,1987,1989,1991,1993,1995],{"class":1988,"line":1101},[469,1515],[467,1990,1295],{"class":1193},[467,1992,1298],{"class":570},[467,1994,1328],{"class":738},[467,1996,1203],{"class":570},[467,1998,2000,2002,2004,2006,2008,2010,2012,2014],{"class":1999,"line":1282},[469,1515],[467,2001,1336],{"class":1193},[467,2003,1298],{"class":570},[467,2005,1341],{"class":738},[467,2007,1298],{"class":570},[467,2009,1346],{"class":738},[467,2011,1298],{"class":570},[467,2013,1351],{"class":738},[467,2015,1203],{"class":570},[467,2017,2019],{"class":2018,"line":1292},[469,1515],[467,2020,1359],{"class":738},[467,2022,2023],{"class":469,"line":1306},[467,2024,1060],{"emptyLinePlaceholder":1059},[467,2026,2027,2029,2031],{"class":469,"line":1321},[467,2028,1263],{"class":1184},[467,2030,1534],{"class":473},[467,2032,1269],{"class":738},[467,2034,2035,2037],{"class":469,"line":1333},[467,2036,1541],{"class":1193},[467,2038,1203],{"class":570},[467,2040,2041,2043,2045],{"class":469,"line":1356},[467,2042,1336],{"class":1193},[467,2044,1550],{"class":738},[467,2046,1203],{"class":570},[467,2048,2049,2051,2053],{"class":469,"line":1362},[467,2050,1557],{"class":1193},[467,2052,1561],{"class":1560},[467,2054,1203],{"class":570},[467,2056,2057,2059,2061,2063],{"class":469,"line":1638},[467,2058,1568],{"class":1193},[467,2060,1571],{"class":738},[467,2062,1574],{"class":477},[467,2064,1203],{"class":570},[467,2066,2067,2069,2071,2073,2075],{"class":469,"line":1665},[467,2068,1568],{"class":1193},[467,2070,1583],{"class":738},[467,2072,1298],{"class":570},[467,2074,1588],{"class":738},[467,2076,1203],{"class":570},[467,2078,2079,2081,2083,2085,2087],{"class":469,"line":1670},[467,2080,1568],{"class":1193},[467,2082,1597],{"class":738},[467,2084,1298],{"class":570},[467,2086,1602],{"class":738},[467,2088,1203],{"class":570},[467,2090,2091,2093,2095,2097,2099],{"class":469,"line":1456},[467,2092,1568],{"class":1193},[467,2094,1611],{"class":738},[467,2096,1298],{"class":570},[467,2098,1616],{"class":738},[467,2100,1203],{"class":570},[467,2102,2103],{"class":469,"line":1684},[467,2104,1359],{"class":738},[467,2106,2107],{"class":469,"line":1694},[467,2108,1060],{"emptyLinePlaceholder":1059},[467,2110,2111,2113,2115],{"class":469,"line":1708},[467,2112,1263],{"class":1184},[467,2114,1633],{"class":473},[467,2116,1269],{"class":738},[467,2118,2119,2121,2123,2125,2127,2129,2131,2133,2135],{"class":469,"line":1713},[467,2120,1642],{"class":1641},[467,2122,1645],{"class":1197},[467,2124,1648],{"class":738},[467,2126,1298],{"class":570},[467,2128,1653],{"class":738},[467,2130,1298],{"class":570},[467,2132,1602],{"class":738},[467,2134,1298],{"class":570},[467,2136,1662],{"class":738},[467,2138,2139],{"class":469,"line":1722},[467,2140,1359],{"class":738},[467,2142,2143],{"class":469,"line":1731},[467,2144,1060],{"emptyLinePlaceholder":1059},[467,2146,2147,2149,2151],{"class":469,"line":1743},[467,2148,1263],{"class":1184},[467,2150,1266],{"class":473},[467,2152,1269],{"class":738},[467,2154,2155,2157,2159],{"class":469,"line":1757},[467,2156,1687],{"class":1193},[467,2158,1442],{"class":738},[467,2160,1203],{"class":570},[467,2162,2163,2165,2167,2169],{"class":469,"line":1768},[467,2164,1697],{"class":1193},[467,2166,1700],{"class":1197},[467,2168,1703],{"class":738},[467,2170,1203],{"class":570},[467,2172,2173],{"class":469,"line":1787},[467,2174,1060],{"emptyLinePlaceholder":1059},[467,2176,2177,2179,2181],{"class":469,"line":1792},[467,2178,1274],{"class":1193},[467,2180,1277],{"class":738},[467,2182,1203],{"class":570},[467,2184,2186,2188,2190],{"class":469,"line":2185},37,[467,2187,1274],{"class":1193},[467,2189,1287],{"class":738},[467,2191,1203],{"class":570},[467,2193,2195,2197,2199,2201],{"class":469,"line":2194},38,[467,2196,1295],{"class":1193},[467,2198,1298],{"class":570},[467,2200,1969],{"class":738},[467,2202,1203],{"class":570},[467,2204,2206,2208,2210,2212,2214],{"class":469,"line":2205},39,[467,2207,1295],{"class":1193},[467,2209,1298],{"class":570},[467,2211,1313],{"class":738},[467,2213,1983],{"class":1197},[467,2215,1203],{"class":570},[467,2217,2219,2221,2223,2225],{"class":469,"line":2218},40,[467,2220,1295],{"class":1193},[467,2222,1298],{"class":570},[467,2224,1328],{"class":738},[467,2226,1203],{"class":570},[467,2228,2230,2232,2234,2236,2238,2240,2242,2244],{"class":469,"line":2229},41,[467,2231,1336],{"class":1193},[467,2233,1298],{"class":570},[467,2235,1341],{"class":738},[467,2237,1298],{"class":570},[467,2239,1346],{"class":738},[467,2241,1298],{"class":570},[467,2243,1351],{"class":738},[467,2245,1203],{"class":570},[467,2247,2249],{"class":469,"line":2248},42,[467,2250,1359],{"class":738},[467,2252,2254],{"class":469,"line":2253},43,[467,2255,1365],{"class":738},[527,2257,2258],{},"Adjust the list of excluded paths to what the app you're protecting actually needs public. Never leave an admin or settings path in that list, only what the app itself documents as safe to expose unauthenticated.",[2260,2261,2262],"style",{},"html pre.shiki code .sEgDM, html code.shiki .sEgDM{--shiki-light:#B392F0;--shiki-default:#FFCB6B;--shiki-dark:#B392F0}html pre.shiki code .s11XM, html code.shiki .s11XM{--shiki-light:#9ECBFF;--shiki-default:#C3E88D;--shiki-dark:#9ECBFF}html pre.shiki code .sJWha, html code.shiki .sJWha{--shiki-light:#79B8FF;--shiki-default:#C3E88D;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sRuoG, html code.shiki .sRuoG{--shiki-light:#85E89D;--shiki-default:#F07178;--shiki-dark:#85E89D}html pre.shiki code .s8jd1, html code.shiki .s8jd1{--shiki-light:#E1E4E8;--shiki-default:#89DDFF;--shiki-dark:#E1E4E8}html pre.shiki code .sDvJj, html code.shiki .sDvJj{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .szyEh, html code.shiki .szyEh{--shiki-light:#F97583;--shiki-default:#F07178;--shiki-dark:#F97583}html pre.shiki code .slcoZ, html code.shiki .slcoZ{--shiki-light:#E1E4E8;--shiki-default:#EEFFFF;--shiki-dark:#E1E4E8}html pre.shiki code .s08Ry, html code.shiki .s08Ry{--shiki-light:#79B8FF;--shiki-default:#FF9CAC;--shiki-dark:#79B8FF}html pre.shiki code .sAoO4, html code.shiki .sAoO4{--shiki-light:#F97583;--shiki-default:#C792EA;--shiki-dark:#F97583}html pre.shiki code .sJPTy, html code.shiki .sJPTy{--shiki-light:#F97583;--shiki-default:#89DDFF;--shiki-dark:#F97583}html pre.shiki code .swwWl, html code.shiki .swwWl{--shiki-light:#79B8FF;--shiki-default:#F78C6C;--shiki-dark:#79B8FF}html pre.shiki code .soUAX, html code.shiki .soUAX{--shiki-light:#79B8FF;--shiki-default:#89DDFF;--shiki-dark:#79B8FF}html pre.shiki code .sJLGa, html code.shiki .sJLGa{--shiki-light:#F97583;--shiki-light-font-style:inherit;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sxjBU, html code.shiki .sxjBU{--shiki-light:#DBEDFF;--shiki-default:#C3E88D;--shiki-dark:#DBEDFF}",{"title":462,"searchDepth":563,"depth":563,"links":2264},[2265,2272,2277,2283,2288],{"id":440,"depth":563,"text":441,"children":2266},[2267,2268,2269,2270,2271],{"id":453,"depth":574,"text":454},{"id":488,"depth":574,"text":489},{"id":536,"depth":574,"text":537},{"id":712,"depth":574,"text":713},{"id":812,"depth":574,"text":813},{"id":816,"depth":563,"text":817,"children":2273},[2274,2275,2276],{"id":825,"depth":574,"text":826},{"id":883,"depth":574,"text":884},{"id":937,"depth":574,"text":813},{"id":943,"depth":563,"text":944,"children":2278},[2279,2280,2281,2282],{"id":988,"depth":574,"text":989},{"id":1129,"depth":574,"text":1130},{"id":1384,"depth":574,"text":1385},{"id":1401,"depth":574,"text":813},{"id":1404,"depth":563,"text":1405,"children":2284},[2285,2286,2287],{"id":1417,"depth":574,"text":1418},{"id":1435,"depth":574,"text":1436},{"id":1820,"depth":574,"text":813},{"id":1841,"depth":563,"text":1842},[2290],"Djeex","Install TinyAuth, a lightweight forward-auth proxy, and pair it with Pocket ID to add SSO login in front of your self-hosted apps. Protect your app behind Swag with forward-auth.","md",null,{},{"title":137,"description":2291},"zzuSXyNCJ379cyuaEWJadXz5f3kimt1zezxVJg4z4Vc",[2298,2300],{"title":133,"path":134,"stem":135,"description":2299,"children":-1},"Use Cloudflare Tunnels and Zero Trust to expose homelab services without opening ports, configure SWAG and manage multiple tunnels.",{"title":141,"path":142,"stem":143,"description":2301,"children":-1},"Install Pocket ID, a lightweight self-hosted OIDC provider that lets you log in to your other apps with a passkey instead of a password.",1788645845853]