Security Azure

Tinyauth on Ubuntu 24.04 on Azure User Guide

| Product: Tinyauth on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Tinyauth 5.1.3 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Tinyauth is a lightweight open source authentication gateway — the simplest way to put a login screen in front of the self-hosted apps you run behind a reverse proxy. Instead of every app needing its own accounts, you place Tinyauth in front of them: a protected route asks Tinyauth whether the visitor is signed in, and if not they are sent to a single, clean login portal. Once authenticated they are allowed through, and the same session covers every app Tinyauth protects.

The image installs the official Tinyauth v5.1.3 release binary (a single, statically-linked Go binary) verified by SHA-256 at install time, and ships the AGPL-3.0 licence text alongside it. Local users are stored as username and bcrypt-hash pairs; Tinyauth also supports OAuth and OIDC providers, LDAP, TOTP two-factor and per-app access-control rules. Sessions are held in a local SQLite database, so there is no external database, no Redis and no database port to secure.

Security model. Because Tinyauth is itself the thing that guards your other apps, the image ships with no usable credential at all: it contains zero configured users and the tinyauth service is held back until first boot, when it generates a fresh admin password unique to your instance, hashes it with bcrypt and writes the credential to a root-only file. Tinyauth binds to 127.0.0.1:3000 only and is fronted by nginx on port 443 with a per-instance self-signed TLS certificate; plain HTTP on port 80 permanently redirects to HTTPS. Session cookies are marked Secure. A protected demo route (/demo/) is included so you can see the auth gate working the moment the VM boots. The only ports exposed are SSH (22) and the web portal (80 and 443).

What is included:

  • Tinyauth 5.1.3 official release binary at /usr/local/bin/tinyauth (SHA-256-verified)

  • tinyauth.service systemd unit running the server bound to 127.0.0.1:3000

  • nginx reverse proxy on port 443 (self-signed TLS; port 80 redirects to 443): the login portal, the Tinyauth API and the forward-auth endpoint, plus a demo route protected by Tinyauth

  • tinyauth-firstboot.service systemd oneshot that mints the per-VM admin user and TLS certificate on first boot

  • A local SQLite session database at /var/lib/tinyauth/tinyauth.db

  • A credential self-test at /usr/local/sbin/tinyauth-credcheck.sh

  • The AGPL-3.0 licence text at /usr/local/share/tinyauth/LICENSE

  • Ubuntu 24.04 LTS base with latest security patches applied at build time

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription

  • A subscription to the Tinyauth on Ubuntu 24.04 listing on Azure Marketplace

  • An SSH public key for VM authentication

  • A virtual network and subnet in the target region

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM). Tinyauth is extremely lightweight; scale up only if you protect many applications with very high request volumes.

Step 1: Deploy from the Azure Portal

Navigate to Marketplace in the Azure Portal, search for Tinyauth, select the cloudimg publisher entry, and click Create.

On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range and TCP 443 (and 80, which redirects to 443) from the client networks that will reach the login portal and protected apps.

Click Review + create, wait for validation, then Create. Deployment takes around two minutes.

Step 2: Deploy from the Azure CLI

RG="tinyauth-prod"
LOCATION="eastus"
az group create --name "$RG" --location "$LOCATION"

az vm create \
  --resource-group "$RG" \
  --name tinyauth-01 \
  --image <publisher>:<offer>:<sku>:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

# Allow SSH (22) and the login portal / protected apps (80 redirects to 443)
az vm open-port --resource-group "$RG" --name tinyauth-01 --port 22 --priority 1001
az vm open-port --resource-group "$RG" --name tinyauth-01 --port 80 --priority 1002
az vm open-port --resource-group "$RG" --name tinyauth-01 --port 443 --priority 1003

Replace <publisher>:<offer>:<sku> with the URN shown on the Marketplace listing's Usage Information tab.

Step 3: Connect via SSH

ssh azureuser@<vm-public-ip>

Use the private key that matches the public key you supplied at deploy time. The login user for this image is azureuser.

Step 4: Verify the Tinyauth Service

Confirm the Tinyauth server and the nginx proxy are running, and check the listening sockets. Tinyauth binds to 127.0.0.1:3000 only — it is reachable off the VM solely through nginx on port 443. The AGPL-3.0 licence ships with the image.

tinyauth version
systemctl is-active tinyauth nginx
sudo ss -ltn | grep -E ':443 |:3000 '
head -2 /usr/local/share/tinyauth/LICENSE

Expected output:

Version: v5.1.3
Commit Hash: ad700e75e065e7d966f0ba4cb16fc851cad224c6
Build Timestamp: 2026-07-30T18:00:43
active
active
LISTEN 0  4096  127.0.0.1:3000  0.0.0.0:*
LISTEN 0   511    0.0.0.0:443    0.0.0.0:*
LISTEN 0   511       [::]:443       [::]:*
                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

Tinyauth and nginx active; the server is bound to loopback only, and the AGPL-3.0 licence ships with the image

Step 5: Retrieve Your Per-VM Admin Credential

On the first boot of your virtual machine, tinyauth-firstboot.service generated an admin password unique to your instance, hashed it with bcrypt into Tinyauth's configuration, and wrote the plaintext to a root-only file. Retrieve it with:

sudo cat /root/tinyauth-credentials.txt

The file reports the login URL and the admin credential:

tinyauth.url=https://<vm-public-ip>.sslip.io/
tinyauth.apphost=<vm-public-ip>.sslip.io
tinyauth.admin.user=admin
tinyauth.admin.pass=<generated-per-vm>

The URL uses sslip.io magic DNS: <vm-public-ip>.sslip.io resolves to your VM's public IP and matches the TLS certificate, so the login portal has a real hostname out of the box.

A shipped self-test confirms the whole auth-gate model without printing any secret — it proves the login portal renders over TLS, the per-VM admin credential authenticates, a wrong password is refused, the forward-auth endpoint returns 401 for an anonymous request and 200 for an authenticated one, and the protected demo route is gated:

sudo bash /usr/local/sbin/tinyauth-credcheck.sh

Expected output:

OK

The per-VM credentials file (values redacted) and the credential self-test reporting OK

Step 6: See the Auth Gate Working

Tinyauth's job is to allow authenticated requests through and bounce anonymous ones to the login portal. The image includes a demo route at /demo/ protected by Tinyauth via nginx auth_request. You can see both halves with curl — logging in to get a session cookie, then hitting the forward-auth endpoint and the protected route with and without it:

HOST=$(sudo grep '^tinyauth.apphost=' /root/tinyauth-credentials.txt | cut -d= -f2-)
AP=$(sudo grep '^tinyauth.admin.pass=' /root/tinyauth-credentials.txt | cut -d= -f2-)
C="curl -s -k --resolve ${HOST}:443:127.0.0.1"
$C -c /tmp/cj -H 'Content-Type: application/json' \
  --data "{\"username\":\"admin\",\"password\":\"$AP\"}" \
  -o /dev/null -w 'login              -> HTTP %{http_code}\n' https://${HOST}/api/user/login
FWD="-H X-Forwarded-Proto:https -H X-Forwarded-Host:${HOST} -H X-Forwarded-Uri:/demo/"
$C $FWD -o /dev/null -w 'forward-auth anon  -> HTTP %{http_code}\n'   https://${HOST}/api/auth/nginx
$C $FWD -b /tmp/cj -o /dev/null -w 'forward-auth authed-> HTTP %{http_code}\n' https://${HOST}/api/auth/nginx
$C        -o /dev/null -w '/demo/ anon        -> HTTP %{http_code}\n' https://${HOST}/demo/
$C -b /tmp/cj -o /dev/null -w '/demo/ authed      -> HTTP %{http_code}\n' https://${HOST}/demo/
rm -f /tmp/cj

Expected output:

login              -> HTTP 200
forward-auth anon  -> HTTP 401
forward-auth authed-> HTTP 200
/demo/ anon        -> HTTP 302
/demo/ authed      -> HTTP 200

The anonymous request to /demo/ returns 302 — nginx redirects it to the Tinyauth login portal. With a valid session it returns 200 and the protected page renders.

The forward-auth endpoint returns 401 without a session and 200 with one; the protected /demo/ route redirects anonymous visitors to the login portal and serves the page once authenticated

Step 7: Sign In to the Login Portal

In a browser, go to https://<vm-public-ip>.sslip.io/. Because the certificate is self-signed, your browser will warn once — accept the exception (or install a real certificate, see Step 10). Sign in with user admin and the tinyauth.admin.pass from Step 5:

The Tinyauth login portal served over TLS, asking for a username and password

Once signed in you land on the Tinyauth account page, which shows your signed-in user and a logout control. This is the session that Tinyauth uses to authorize every app you place behind it:

The Tinyauth account page after signing in, showing the authenticated user

Step 8: Watch the Gate Protect the Demo App

Open https://<vm-public-ip>.sslip.io/demo/. While you are signed in, the protected demo page renders — nginx asked Tinyauth to authorize the request and Tinyauth let it through because you have a valid session:

The protected demo application page rendering because the visitor has a valid Tinyauth session

If you open the same URL in a private window (no session), Tinyauth bounces you straight to the login portal — that is the entire point of the gateway. Any app you place behind Tinyauth is protected the same way.

Step 9: Protect Your Own Apps

To protect an app you run on the VM, front it with nginx and defer the authorization decision to Tinyauth. The pattern used by the demo route is:

# In your app's nginx server block:
location / {
    auth_request /tinyauth-verify;
    auth_request_set $tinyauth_login $upstream_http_x_tinyauth_location;
    error_page 401 = @tinyauth_login;

    proxy_pass http://127.0.0.1:<your-app-port>;
}

location = /tinyauth-verify {
    internal;
    proxy_pass http://127.0.0.1:3000/api/auth/nginx;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host  $http_host;
    proxy_set_header X-Forwarded-Uri   $request_uri;
}

location @tinyauth_login { return 302 $tinyauth_login; }

The shipped vhost at /etc/nginx/sites-available/tinyauth is a complete working example. Tinyauth also supports fine-grained per-app access-control rules (allow/block specific users or OAuth/LDAP groups per app) — see the Tinyauth access-controls guide.

Step 10: Add More Users, OAuth, OIDC and LDAP

Tinyauth's configuration lives in /etc/tinyauth/config.yaml. To add another local user, generate a bcrypt entry and add it under auth.users:

sudo tinyauth user create --interactive
# copy the printed "username:hash" value, then add it under auth.users in the config:
sudoedit /etc/tinyauth/config.yaml
sudo systemctl restart tinyauth

For single sign-on with Google, GitHub or any generic OIDC provider, add an oauth.providers block; for directory logins add an ldap block; for two-factor add a TOTP secret to a user. Each is documented in the Tinyauth configuration reference.

Step 11: Install a Real TLS Certificate (Production)

The image ships a per-VM self-signed certificate so the portal is HTTPS out of the box. For production, point a DNS name at the VM's public IP, open port 443 in the network security group, and install a Let's Encrypt certificate into the bundled nginx:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

Then update appUrl in /etc/tinyauth/config.yaml to https://your-domain.example.com/ and restart Tinyauth so redirects and cookies use the real domain:

sudoedit /etc/tinyauth/config.yaml
sudo systemctl restart tinyauth

Step 12: Managing the Tinyauth Service

# Status and logs
systemctl status tinyauth --no-pager
sudo journalctl -u tinyauth -n 100 --no-pager

# Restart after changing /etc/tinyauth/config.yaml
sudo systemctl restart tinyauth

# nginx (the reverse proxy)
sudo nginx -t && sudo systemctl reload nginx

Architecture Summary

  • Tinyauth 5.1.3 — a single statically-linked Go binary at /usr/local/bin/tinyauth, run as the non-root tinyauth service account under systemd, bound to 127.0.0.1:3000.

  • nginx terminates TLS on port 443 (self-signed per-VM certificate; port 80 redirects to 443) and serves the login portal, the Tinyauth API, the forward-auth endpoint and the protected /demo/ route.

  • Configuration in /etc/tinyauth/config.yaml — the shipped image contains no users; first boot writes the per-VM appUrl and a bcrypt admin user.

  • Sessions in a local SQLite database at /var/lib/tinyauth/tinyauth.db — no external database, no database port.

  • First boot (tinyauth-firstboot.service) mints the per-VM admin password and TLS certificate, writes the root-only credentials file, then starts the stack.

  • Ports: SSH (22) and the web portal (80 redirecting to 443). Tinyauth on 3000 is bound to loopback and never exposed directly.

This image is maintained by cloudimg with 24/7 support (support@cloudimg.co.uk, 24 hour response SLA).