Logto OIDC: Identity Infrastructure

The Architecture Rationale

Modern application frameworks like Laravel often rely on heavy external SaaS providers for single sign-on (SSO), multi-tenant enterprise federation (SAML), and social authentication. To avoid high platform dependencies, API rate-limiting, and external vendor data-locking, I engineered a self-hosted Identity & Access Management (IAM) layer utilizing Logto running in an isolated Debian Linux LXC.

This system acts as a centralized OIDC identity provider, utilizing my high-performance, remote PostgreSQL LXC to store cryptographic credentials, authentication states, and user profile data securely.

Phase 1: LXC Preparation & Runtime Setup

The foundation is built on a clean, optimized Debian Linux LXC using Proxmox Helper Scripts. Because Logto is a modern Node.js application, installing an up-to-date runtime environment is crucial.

Node.js Runtime Installation via NVM

Log in to your Debian LXC console and initialize Node Version Manager (NVM) to fetch the required environment packages:

Bash

# Update the OS package database
sudo apt update

# Fetch and execute the NVM installation script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# Load NVM variables into the active shell execution context
\. "$HOME/.nvm/nvm.sh"

# Install and lock down Node.js LTS version 22
nvm install 22

# Verify environment binaries are active
node -v
npm -v

Phase 2: Logto Core Engine Provisioning

With a running Node.js workspace, download, seed, and bootstrap Logto into a target instance directory using the official Logto CLI utility:

Bash

# Execute the interactive or silent initialization tool pointing to your remote Postgres DB
npx @logto/cli init -p ./logto --db-url "postgres://postgres:3.Dmanime999123%40%[email protected]:5432/logto"

⚠️ ConnectionString Architecture: Special characters in database credentials (such as @) must be properly percent-encoded to prevent standard connection string parsers from breaking. For instance, the character @ translates directly to %40%40 (e.g., 3.Dmanime999123%40%40).

Phase 3: Identity Routing & Proxy Hardening

To integrate with an edge proxy like Nginx, Logto must be configured to trust proxy-forwarded HTTP headers. Navigating to the directory where Logto was unpacked, create and populate the .env settings file:

Bash

cd ./logto
nano .env

Define the system integration parameters:

Ini, TOML

# Remote PostgreSQL DSN (Isolated Data Layer)
DB_URL=postgres://postgres:3.Dmanime999123%40%[email protected]:5432/logto

# Trust upstream forwarding headers (X-Forwarded-For, X-Forwarded-Proto) from Nginx
TRUST_PROXY_HEADER=true

# Public endpoints mapped to Nginx domains
ENDPOINT=https://login.armghan.com
ADMIN_ENDPOINT=https://admin.armghan.com

Phase 4: Local Internal Resolvers (Host Resolution)

Because the Logto engine and the Nginx proxy run inside isolated, virtualized LAN boundaries on Proxmox, the Logto service needs to perform direct, low-latency internal queries.

To prevent internal curl and API requests from looping back out to the WAN or depending on external DNS, define local resolution parameters directly on the host level:

Bash

nano /etc/hosts

Configure your DNS overrides so virtual paths resolve instantly to their respective internal LXC nodes:

Plaintext

# Resolve internal curl requests for Logto local nodes straight to Nginx Edge
192.168.100.20 login.armghan.com
192.168.100.20 admin.armghan.com 

# Resolve direct SMTP/API outbound configurations to Stalwart Mail LXC
192.168.100.52 stalwart.armghan.com

The Architectural Evaluation: Why Logto Outclassed the Alternatives

Before standardizing on Logto, I evaluated several other major open-source IAM and Single Sign-On (SSO) solutions. While each of these tools is powerful, they introduced significant operational friction or structural bloat that made them less ideal for my unified, clean Proxmox ecosystem:

  • Keycloak: Widely considered the enterprise standard, Keycloak is incredibly feature-rich but written in Java. It has a massive memory footprint, a notoriously steep learning curve, and a clunky, dated administrative interface. For a lean virtualized environment, Keycloak represents massive operational overhead.
  • Authentik & Authelia: Both are fantastic solutions for protecting raw homelab infrastructure (such as placing a portal page in front of unauthenticated reverse proxy endpoints). However, their administration configurations—often relying heavily on complex YAML files or cluttered dashboards—make them feel less like slick developer-facing customer identity engines (CIAM) and more like infrastructure-access firewalls.
  • Zitadel: A strong modern competitor, but its multi-tenancy architecture and data schema are heavily opinionated, making integration with standard application frameworks like Laravel more rigid than necessary.
  • The Logto Difference: Logto provided the cleanest “developer experience.” It offers modern, out-of-the-box SDKs, an incredibly polished administrative interface, native support for OIDC/OAuth 2.1, and an extremely lightweight Node.js footprint. It gives you the “WorkOS style” developer experience without forcing you into a proprietary cloud subscription.

Updated Comparative Assessment: Identity Layers

Identity LayerInfrastructure ControlUI/UX CleanlinessResource FootprintCost Profile
Logto (Self-Hosted)CompleteExceptionalLow (Node.js)Free / Self-Hosted
KeycloakCompletePoor / LegacyHigh (Java/JVM)Free / Self-Hosted
Authentik / AutheliaCompleteModerate (Infra-focused)Low to ModerateFree / Self-Hosted
ZitadelCompleteGoodModerate (Go)Free / Self-Hosted
WorkOS / Auth0Minimal (SaaS lock-in)ExceptionalZero (External SaaS)High (Usage-based)