Back to articles
Technology Insight

Self-Hosting Zitadel SSO on a 2GB VPS: A Cost-Effective, High-Security Auth0 Alternative for Agency App Ecosystems

May 26, 2026

Introduction: The Identity Crisis in Modern Agency Workflows

Digital agencies frequently manage a complex web of internal tools, client portals, staging environments, and proprietary applications. As the application ecosystem grows, managing user identities securely becomes a massive operational headache. For years, Identity-as-a-Service (IDaaS) providers like Auth0 or Okta were the default choice. However, their pricing models—often scaling aggressively based on Monthly Active Users (MAU) or specific enterprise features like SAML and multi-tenancy—can quickly erode an agency's profit margins.

Enter Zitadel, an open-source, cloud-native identity management platform that serves as a powerful, cost-effective alternative. By self-hosting Zitadel, agencies can maintain absolute control over their data, implement true multi-tenancy for clients, and secure their entire application suite. Best of all, with proper optimization, Zitadel can run efficiently on a lightweight Virtual Private Server (VPS) with just 2GB of RAM. This post provides an engineering blueprint for deploying and optimizing Zitadel for an agency environment.

Why Zitadel? The Ultimate Auth0 Alternative for Agencies

While there are several open-source identity providers available (such as Keycloak), Zitadel stands out for modern web development workflows due to several distinct advantages:

  • Built-in Multi-Tenancy: Zitadel was designed from the ground up with an organizational hierarchy. This allows agencies to manage multiple clients under a single instance, isolating client users and configurations cleanly.
  • Audit Trails and Event Sourcing: Every action within Zitadel is stored as an event. This provides an unalterable audit log, a crucial requirement for enterprise clients and compliance audits.
  • Modern Protocol Support: Full, out-of-the-box support for OpenID Connect (OIDC), OAuth 2.0, and SAML ensures seamless integration with modern frameworks (Next.js, Vue, NestJS) and legacy systems alike.
  • Resource Efficiency: Unlike Java-based heavyweights like Keycloak, Zitadel is written in Go. This makes it incredibly lightweight, fast to boot, and highly performant even under constrained hardware resources.

The 2GB RAM Challenge: Optimizing the Stack

Running an enterprise identity provider on a 2GB RAM VPS requires a deliberate approach to architecture. Zitadel relies on a database backend to manage its event store. It officially supports CockroachDB and PostgreSQL.

Operational Note: While CockroachDB offers incredible horizontal scalability, its memory footprint is too heavy for a 2GB RAM single-node VPS. For resource-constrained environments, PostgreSQL is mandatory.

To ensure system stability and prevent the Linux Out-Of-Memory (OOM) killer from terminating your authentication service, follow this optimized architecture strategy:

  1. PostgreSQL Tuning: Limit PostgreSQL's shared buffers to roughly 25% of total RAM (approx. 512MB) to leave ample breathing room for Zitadel and the OS.
  2. Configure Swap Space: Always allocate at least 2GB of swap space on your VPS SSD. While swap is slower than RAM, it acts as a critical safety net during temporary traffic spikes or database migrations.
  3. Containerization: Use Docker Compose to isolate the Zitadel binary and the PostgreSQL database, allowing strict resource limits to be enforced if necessary.

Step-by-Step Deployment Guide

1. Prerequisites and DNS Setup

Before executing commands, ensure you have a VPS running a clean installation of Ubuntu 22.04 or 24.04 LTS with at least 2GB RAM and 1 vCPU. Point your domain or subdomain (e.g., auth.youragency.com) to the public IP address of your VPS.

2. Docker and Compose Installation

Update your system package index and install Docker and Docker Compose to orchestrate our micro-services:

sudo apt update && sudo apt upgrade -y
sudo apt install docker.io docker-compose-plugin -y
sudo systemctl enable --now docker

3. Crafting the Docker Compose Configuration

Create a dedicated directory and define the docker-compose.yaml file. We will use a reverse proxy like Traefik or Nginx to handle SSL termination, but for simplicity, the following manifest configures Zitadel and a tuned PostgreSQL instance:

version: '3.8'

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: zitadel_user
      POSTGRES_PASSWORD: SecretSecurePassword123
      POSTGRES_DB: zitadel
    volumes:
      - pgdata:/var/lib/postgresql/data
    command: ["postgres", "-c", "shared_buffers=512MB", "-c", "max_connections=50"]
    restart: always

  zitadel:
    image: ghcr.io/zitadel/zitadel:latest
    command: start-from-init --masterkey "MasterKeyMustBeExactly32BytesLong!"
    environment:
      - ZITADEL_DATABASE_POSTGRES_HOST=db
      - ZITADEL_DATABASE_POSTGRES_PORT=5432
      - ZITADEL_DATABASE_POSTGRES_DATABASE=zitadel
      - ZITADEL_DATABASE_POSTGRES_USER_USERNAME=zitadel_user
      - ZITADEL_DATABASE_POSTGRES_USER_PASSWORD=SecretSecurePassword123
      - ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME=zitadel_user
      - ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD=SecretSecurePassword123
      - ZITADEL_EXTERNALDOMAIN=auth.youragency.com
      - ZITADEL_TLS_ENABLED=false
    ports:
      - "8080:8080"
    depends_on:
      - db
    restart: always

volumes:
  pgdata:

Make sure to replace MasterKeyMustBeExactly32BytesLong!, passwords, and the ZITADEL_EXTERNALDOMAIN with your actual production credentials and domain name.

4. Initializing and Running the Stack

Launch the containers in detached mode. The initial setup might take a minute as Zitadel runs database migrations to set up its event-sourced architecture:

docker compose up -d

Monitor the logs using docker compose logs -f zitadel to capture the automatically generated administrator credentials on the first boot. Look for the initial username (usually [email protected] or similar) and temporary password printed in the console output.

Securing Your Self-Hosted SSO Instance

An identity provider is the keys to your kingdom. Operating it self-hosted requires adherence to strict security best practices:

  • SSL/TLS Enforcement: Never run Zitadel over plain HTTP in production. Use a reverse proxy like Nginx, Traefik, or Cloudflare Tunnels to enforce TLS 1.3 encryption.
  • Automated Database Backups: Because Zitadel relies on event sourcing, losing the database means losing all historical state and access tokens. Implement a cron job utilizing pg_dump to securely back up the database daily to an offsite S3-compatible cloud storage bucket.
  • Enable MFA Everywhere: Force Multi-Factor Authentication (MFA) for your agency administrators and client accounts using Time-based One-Time Passwords (TOTP) or WebAuthn (Passkeys).

Conclusion: Empowering Your Agency's Growth

Self-hosting Zitadel on a 2GB VPS provides agencies with an incredible balance of economy, customizability, and data sovereignty. By replacing expensive IDaaS subscriptions with a lightweight, open-source stack, you protect your agency's financial margins while offering clients an enterprise-grade identity layer. As traffic grows, Zitadel's architecture allows you to scale smoothly from a single 2GB VPS to a robust, highly available multi-node cluster.

Self-Hosting Zitadel SSO on a 2GB VPS: A Cost-Effective, High-Security Auth0 Alternative for Agency App Ecosystems | DPTCloud