[{"data":1,"prerenderedAt":244},["ShallowReactive",2],{"seo-verification":3,"blog-self-host-zitadel-vps-open-source-iam-developers-ma-en":6,"promo-bar-likely":243},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-self-host-zitadel-vps-open-source-iam-developers-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":197,"ctaBody":198,"ctaButton":199,"ctaUrl":200,"relatedPosts":201},351,"self-host-zitadel-vps-open-source-iam-developers",{"fr":12,"en":10,"ar":13,"es":14},"deployer-zitadel-vps","zitadel-vps-iam-maftouh-almassdar-lilmutatawireen","instalar-zitadel-vps-iam-codigo-abierto-desarrolladores","Self-Host ZITADEL on a VPS: Open-Source IAM for Developers","Deploy ZITADEL self-hosted on a VPS: OIDC, OAuth 2.0, passkeys and native multi-tenancy with Docker Compose in under 5 minutes.",11,0,false,"2026-01-08T00:00:00+00:00","2026-11-04T16:30:27+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-zitadel-vps-poster.svg",{"categorySlug":34,"appSlug":35},"security","zitadel","ZITADEL is an open-source IAM platform written in Go: OIDC\u002FOAuth 2.0 SSO, passkeys and native multi-tenancy, self-hosted. This guide deploys it on a ServOrbit VPS with Docker Compose, corrects figures the previous version repeated without a source, and documents what does not work yet: domain discovery, an open bug on v4 since September 2025. Guide provided, no support included.",[38,41,44,46,55,57,70,72,74,76,83,85,87,89,91,97,99,101,105,107,109,117,119,121,153,155,157,175,182,184,190,193,195],{"type":39,"title":40},"h2","Why choose ZITADEL over Authentik or Keycloak?",{"type":42,"body":43},"p","ZITADEL occupies a precise niche among open-source authentication platforms. Unlike **Authelia** (an authentication proxy without its own user management) or **Authentik** (a feature-rich full-stack IdP), it targets development teams that want enterprise-grade IAM from day one: native multi-tenancy, complete gRPC + REST APIs, and an official Terraform provider (`zitadel\u002Fzitadel` on the Terraform registry).\n\nBe careful with memory figures. The operations documentation says ZITADEL itself needs about 512 MB of RAM and less than one CPU core, database excluded, with CPU spikes during password hashing. The previous version of this article claimed \"under 100 MB\": that figure is not in the documentation, so do not size your VPS on it. The resource comparison with Keycloak is not quantified here because no sourced measurement exists.",{"type":39,"title":45},"Sized prerequisites",{"type":47,"items":48},"ul",[49,50,51,52,53,54],"**VPS**: 2 vCPU and 2 GB of RAM (the upstream Docker Compose guide asks for at least 2 GB), Ubuntu 24.04. Plan for more as the database grows: upstream counts about 4 GB of RAM per database core.","**Docker**: Docker Engine 24 or later with Compose v2; the legacy `docker-compose` (v1) binary is not supported.","**PostgreSQL**: versions 14 to 18 are supported. The ServOrbit template deploys PostgreSQL 16.","**Ports**: ZITADEL listens internally on `8080`. Only `443` should be public (plus `80` if you let Let's Encrypt issue the certificate). The template binds `8080` to `127.0.0.1` and lets nginx serve the outside.","**Domain**: a name or subdomain pointing to the VPS IP, for example `auth.your-domain.com`, over HTTPS.","**Masterkey**: `ZITADEL_MASTERKEY` must be exactly 32 characters and cannot change after initialization without losing access to encrypted data. The template generates it; back it up off the VPS.",{"type":39,"title":56},"Install ZITADEL from the Marketplace",{"type":58,"title":59,"steps":60},"steps","Installation in 3 steps",[61,64,67],{"title":62,"body":63},"Create the VPS","From your ServOrbit client area, choose the VPS range and click **Configure**. In the Application field, select **ZITADEL**. Enter your domain (e.g. `auth.your-domain.com`).\n\nIf you do not have a domain, the free ServOrbit subdomain is available immediately, HTTPS included.",{"title":65,"body":66},"Automatic startup","The installation script generates the `MASTERKEY`, the PostgreSQL password and the admin password, then launches PostgreSQL 16 and ZITADEL via Docker Compose. Typical duration: 2 to 4 minutes.",{"title":68,"body":69},"Access the console","Once installation is complete, your credentials are displayed in the client area.\n- URL: `https:\u002F\u002F\u003Cyour-domain>\u002Fui\u002Fconsole`\n- Username: `admin`. If the page rejects it, try `admin@zitadel.\u003Cyour-domain>`: ZITADEL builds login names as user@organization.domain, as in upstream's `zitadel-admin@zitadel.localhost` example.\n- Password: the generated one\n\nLog in and change it immediately.",{"type":39,"title":71},"What the template deploys",{"type":42,"body":73},"The template is a Docker Compose file with two services: `db` (PostgreSQL 16) and `zitadel`, started with `start-from-init --tlsMode disabled --masterkeyFromEnv`. TLS is therefore terminated by nginx, not by ZITADEL. The image followed is the `stable` tag of `ghcr.io\u002Fzitadel\u002Fzitadel`, which means the version actually running depends on the day the image was pulled: check it with `docker compose images` (see the section on updates).\n\nThe domain is passed to `ZITADEL_EXTERNALDOMAIN`, with `ZITADEL_EXTERNALPORT=443` and `ZITADEL_EXTERNALSECURE=true`. The template treats the domain as fixed at first boot: pick the right one from the start.",{"type":39,"title":75},"External domain, TLS and reverse proxy",{"type":47,"items":77},[78,79,80,81,82],"**Three values to align** — `ZITADEL_EXTERNALDOMAIN`, `ZITADEL_EXTERNALPORT` and `ZITADEL_EXTERNALSECURE` must describe the real public URL. ZITADEL only serves requests sent to the expected protocol, host and port; otherwise you get \"Instance not found\".","**Changing domain** — upstream documents that these options can be changed at any time, provided you rerun the setup phase. So it is not impossible, as the previous version claimed, but it is not a trivial operation: every client application references the old URL.","**Host preserved** — the reverse proxy must forward the original `Host` header and `X-Forwarded-Proto: https`. The upstream nginx example terminates TLS, then talks to ZITADEL over unencrypted HTTP\u002F2 (h2c) with `grpc_pass`.","**End-to-end HTTP\u002F2** — the console requires HTTP\u002F2 all the way to ZITADEL. The proxies upstream tested are Traefik v3, NGINX 1.x stable, Caddy v2 and Apache httpd 2.4.","**CDN or WAF in front** — the documentation states that a proxy, WAF or CDN placed in front of ZITADEL must also support HTTP\u002F2. Test the console after any DNS switch to a proxied mode.",{"type":39,"title":84},"Create your first OIDC application",{"type":42,"body":86},"Once logged in to the ZITADEL console:\n\n1. Go to **Projects** then **Create**\n2. Name your project (e.g. `My App`)\n3. Click **Add Application**\n4. Choose the type: **Web** (server-side apps), **Native** (mobile\u002Fdesktop) or **API** (machine-to-machine)\n5. For a Web app, choose **PKCE** (recommended) and enter your **Redirect URIs**\n\nZITADEL generates the **Client ID**. Note the OIDC discovery endpoint: `https:\u002F\u002F\u003Cyour-domain>\u002F.well-known\u002Fopenid-configuration`.",{"type":39,"title":88},"Integrate ZITADEL with your self-hosted applications",{"type":42,"body":90},"Any application that speaks OIDC can rely on ZITADEL: you only need the Client ID, the secret if any, and the discovery endpoint. Common examples:",{"type":47,"items":92},[93,94,95,96],"**Gitea**: Site Administration, Authentication, add an OAuth2 source of type OpenID Connect, then enter Client ID, secret and discovery endpoint","**Grafana**: `[auth.generic_oauth]` section of `grafana.ini` with ZITADEL's authorization, token and user info URLs","**Nextcloud**: `Social Login` or `OpenID Connect user backend` app","**Any other OIDC application**: enter the discovery endpoint, the Client ID and the Redirect URIs declared in the project; check the application's documentation for the exact settings",{"type":39,"title":98},"Multi-tenant management: organizations and projects",{"type":42,"body":100},"ZITADEL relies on a native multi-tenant model: you create several **Organizations** (for example one per customer of your SaaS), each with its own users and login policies. Each organization can have its own **Projects** and **Roles**.\n\nNote that roles are not added to tokens automatically, contrary to what the previous version claimed. You must tick **Assert Roles on Authentication** in the project to get them through userinfo, or **User Roles Inside ID Token** in the application, and request the role scope `urn:zitadel:iam:org:project:{projectId}:roles`. Also add `urn:zitadel:iam:org:project:id:{projectId}:aud` if you get \"Invalid audience\".",{"type":102,"title":103,"body":104},"tip","Tip: enable passkeys from the start","In the instance settings, enable Passkey\u002FWebAuthn authentication. Your users sign in without a password from their browser.",{"type":39,"title":106},"Domain discovery: what should work",{"type":42,"body":108},"Domain discovery routes a user to the right organization based on the domain of their email address. In the scenario described upstream, a user at `alice@alpha.com` is redirected to their company's identity provider, a user at `bob@beta.com` sees a password-and-MFA login page, and an unknown domain falls into the default organization.\n\nThe conditions described in the upstream guide are:",{"type":47,"items":110},[111,112,113,114,115,116],"**Instance** — under Login Behavior and Security, the \"Domain discovery allowed\" option is enabled","**Default organization** — it receives all users without a match","**Verified domain** — each domain is verified in the organization's Organization Domains, by DNS TXT record or HTTP challenge; keep the DNS record, because ZITADEL re-checks periodically","**Organization login policy** — \"External IDP allowed\" enabled, and for a purely federated organization \"Username Password allowed\" disabled","**Identity provider** — configured and attached to that organization; with a single provider the redirect is automatic, with several the user chooses","**Email sign-in** — the login name entered must be able to be an email address whose domain matches",{"type":39,"title":118},"Known limits: zitadel\u002Fzitadel issue #10662",{"type":42,"body":120},"On self-hosted ZITADEL v4.1.2, domain discovery does not work for some deployments despite organizations with a verified domain and a configured identity provider. Issue #10662 (\"Domain Discovery doesn't work\") was opened in September 2025 and is still open as this article is written. The table separates what the team or the documentation establishes from what users report.",{"type":122,"title":123,"headers":124,"rows":128},"comparison","Issue #10662: confirmed and reported",[125,126,127],"Point","Confirmed (team or documentation)","Reported by users, not confirmed",[129,133,137,141,145,149],[130,131,132],"Symptom","The issue is open, set to medium priority in October 2026, with the labels area\u002Fconsole, area\u002FloginV1 and ng-v4-legacy","\"User not found in the system\" message for an address on the verified domain, on v4.1.2, identical on OKD and on Docker",[134,135,136],"Announced fix","A maintainer said in October 2025 that PR #10729 fixed it, then the issue was reopened","The defect persists on v4.3.1, then on Login V1 on v4.5.0, v4.6.3, v4.7.0 and v4.11.0",[138,139,140],"Cause","No cause is publicly established","No verified hypothesis",[142,143,144],"Scope","Sub-issues exist (status on 16 July 2026: one done, two in progress, one not started), attached to the parent effort #12337","Reproduced on Login V2 (initial report) then on Login V1; the case of several domains in one organization remains unanswered",[146,147,148],"Console","On 27 July 2026 a contributor says the Console is to be deprecated within 12 months and that no fix is prioritized until then; the issue is kept open","Nothing to report",[150,151,152],"Workaround","No workaround is documented in the thread","None has been proven by participants",{"type":42,"body":154},"In practice: do not build an enterprise SSO architecture on domain discovery alone while this issue is open. Plan a second path (a per-provider sign-in link, see below) and test the routing with a real user before going live. On 27 October 2026 a team member asked for the issue's status to be verified: follow the issue rather than this article for its outcome.",{"type":39,"title":156},"Troubleshooting SSO sign-in and the verified domain",{"type":58,"title":158,"steps":159},"Diagnosis in 5 steps",[160,163,166,169,172],{"title":161,"body":162},"Check the instance","In the instance settings, Login Behavior and Security section, check that \"Domain discovery allowed\" is enabled. Without it no organization rule is consulted.",{"title":164,"body":165},"Check the domain","In the target organization, open Organization Domains: the domain must have the verified status. If verification fails, restore the TXT record or the requested HTTP challenge, and never delete the record afterwards.",{"title":167,"body":168},"Check the login policy","In the same organization, \"External IDP allowed\" must be enabled and the identity provider active. If \"Username Password allowed\" stays enabled, the user may land on the password prompt instead of being redirected, a symptom described in the issue.",{"title":170,"body":171},"Test the login name","In a private window, enter a full address whose domain is exactly the verified one. A typo in the domain, a subdomain, or a user who already exists in another organization changes the outcome.",{"title":173,"body":174},"Bypass discovery","If everything is compliant and \"User not found in the system\" persists, you are probably in the case of issue #10662. The scope `urn:zitadel:iam:org:idp:id:\u003Cidp_id>` redirects the user straight to the chosen identity provider: the documentation describes it, but it has not been proven on this defect.",{"type":47,"items":176},[177,178,179,180,181],"**\"User not found in the system\"**: apply the five steps above; if they are compliant, it is the defect in the issue","**\"Instance not found\" (404)**: the host, port and protocol received do not match `ZITADEL_EXTERNALDOMAIN`, `ZITADEL_EXTERNALPORT` and `ZITADEL_EXTERNALSECURE`; check that nginx keeps the `Host` header","**Blank console or failing API calls behind a proxy or CDN**: check HTTP\u002F2 end to end","**`admin` username rejected**: try the `admin@zitadel.\u003Cyour-domain>` form given above","**Domain verification failing**: the upstream guide notes that the ACME verification challenge can be disabled in the default settings, but only do so knowingly",{"type":39,"title":183},"Updates and security",{"type":47,"items":185},[186,187,188,189],"**Current version** — as this is written, the latest stable release is v4.20.0, published in October 2026; read the release notes before every upgrade","**Advisory GHSA-jh92-5mrj-p2w2** — account takeover through predictable session IDs in Login V2 (high severity, no CVE identifier listed). Versions 4.0.0 to 4.19.1 are affected, fixed in 4.19.2; a deployment using only Login V1 is not affected","**Session cookie secret** — the fix asks for `ZITADEL_SESSION_COOKIE_SECRET` (at least 32 characters, identical on all replicas); users must sign in again after the upgrade","**3.x branch** — it reached end of life on 31 August 2026 and will not get a fix: move to a recent 4.x",{"type":102,"title":191,"body":192},"Before updating","Back up the database with `pg_dump` and the masterkey, then run `docker compose pull` followed by `docker compose up -d` from the Compose folder. Since the template follows the `stable` tag, check the running version afterwards with `docker compose images`.",{"type":39,"title":194},"Install ZITADEL via the ServOrbit Marketplace",{"type":42,"body":196},"You can install ZITADEL directly from the [ServOrbit Marketplace](\u002Fapplications\u002Fsecurity\u002Fzitadel): VPS pre-configured with Docker Compose, nginx, HTTPS and automatically generated secrets. The template is provided as a starting point, with no support for your identity configuration.","Deploy ZITADEL on your VPS","Open-source IAM, OIDC\u002FOAuth 2.0, passkeys and native multi-tenancy — pre-configured with Docker Compose and HTTPS included.","Deploy ZITADEL","\u002Fapplications\u002Fcybersecurity-bastion\u002Fzitadel",[202,225],{"id":203,"slug":204,"slugs":205,"title":209,"excerpt":210,"readTime":211,"views":18,"isPinned":19,"noindex":19,"publishedAt":212,"updatedAt":213,"category":214,"categories":219,"featuredImage":30,"bgImage":31,"posterImage":221,"relatedSolution":222},112,"deploy-keycloak-for-sso-on-your-vps",{"fr":206,"en":204,"ar":207,"es":208},"keycloak-sso-vps","نشر-keycloak-لتسجيل-الدخول-الموحد-sso-على-خادمك-vps","desplegar-keycloak-sso-en-un-vps","Deploy Keycloak for SSO on Your VPS","Deploy Keycloak on your VPS for enterprise-grade SSO: OIDC, SAML, realms and federation. A complete Docker guide and comparison.",10,"2026-02-28T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":215,"name":216,"slug":217,"color":218,"icon":34},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400",[220],{"id":215,"name":216,"slug":217,"color":218,"icon":34},"\u002Fblog\u002Fcovers\u002Fkeycloak-sso-vps-poster.svg",{"categorySlug":223,"appSlug":224},"cybersecurity-bastion","keycloak",{"id":226,"slug":227,"slugs":228,"title":232,"excerpt":233,"readTime":234,"views":235,"isPinned":19,"noindex":19,"publishedAt":236,"updatedAt":21,"category":237,"categories":238,"featuredImage":30,"bgImage":31,"posterImage":240,"relatedSolution":241},272,"authentik-authelia-or-keycloak-choosing-your-sso-on-vps",{"fr":229,"en":227,"ar":230,"es":231},"authentik-vs-authelia-keycloak-sso-vps-2026","authentik-أو-authelia-أو-keycloak-اختيار-sso-على-vps","authentik-authelia-o-keycloak-elegir-sso-en-vps","Authentik, Authelia or Keycloak: Choosing Your SSO on VPS","Authentik, Authelia or Keycloak on VPS: compare real memory footprint, covered protocols and Keycloak 26.7.1 CVEs to choose the right self-hosted SSO.",6,3,"2026-08-16T00:00:00+00:00",{"id":215,"name":216,"slug":217,"color":218,"icon":34},[239],{"id":215,"name":216,"slug":217,"color":218,"icon":34},"\u002Fblog\u002Fcovers\u002Fauthentik-vs-authelia-keycloak-sso-vps-2026-poster.svg",{"categorySlug":223,"appSlug":242},"authentik",true,1794270498959]