[{"data":1,"prerenderedAt":208},["ShallowReactive",2],{"seo-verification":3,"blog-self-host-logto-on-a-vps-your-own-authentication-layer-ma-en":6,"promo-bar-likely":207},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-self-host-logto-on-a-vps-your-own-authentication-layer-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":137,"ctaBody":138,"ctaButton":139,"ctaUrl":140,"relatedPosts":141},226,"self-host-logto-on-a-vps-your-own-authentication-layer",{"fr":12,"en":10,"ar":13,"es":14},"self-host-logto-vps","استضافة-logto-على-خادم-افتراضي-طبقة-المصادقة-عندك","autoalojar-logto-en-un-vps","Self-host Logto on a VPS: your own authentication layer","Deploy Logto on your ServOrbit VPS: OIDC authentication, social login, MFA and SDKs — no per-user pricing, no third-party data storage.",10,1,false,"2026-08-05T00:00:00+00:00","2026-11-04T16:30:26+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fself-host-logto-vps-poster.svg",{"categorySlug":34,"appSlug":35},"cybersecurity-bastion","logto","Hosted authentication services charge per monthly active user and store your users' login data on their own servers. Logto is the open-source alternative: a complete OIDC\u002FOAuth 2.0 authentication platform you deploy on your own VPS and control end to end. One Docker Compose file, two containers (Logto and PostgreSQL 17), and your applications have production-ready authentication — sign-up, social login, MFA, role-based access control — with no per-user cost.",[38,42,45,48,58,80,95,98,101,131,134],{"type":39,"title":40,"body":41},"h2","What Logto actually is — and what it is not","Logto is an **auth SDK platform**: you integrate it into your application's code via a 15-line SDK snippet, and it handles the complete user lifecycle on your own server. This is different from the two other authentication tools in the ServOrbit catalogue:\n\n- **Authelia** adds MFA and SSO *in front of* existing apps via forward auth, without changing their code — it protects apps that have no login at all.\n- **Authentik** is a full identity provider for centralising SSO across your self-hosted tools (Grafana, Gitea, Nextcloud).\n- **Logto** replaces Auth0 or Clerk: you call its SDK from your React, Python, or Go application, and it manages user accounts, sessions, social connectors, and tokens.\n\nIf you're building a product where users create accounts, Logto is the right tool.",{"type":39,"title":43,"body":44},"Prerequisites","Before deploying Logto 1.19+, verify the following on your ServOrbit VPS:\n\n- **RAM**: at least **2 GB** (4 GB recommended if you expect more than 5,000 active users). Logto runs on Node.js 20 LTS and shares the same instance as PostgreSQL 17.\n- **CPU**: 1 vCPU is enough to get started, but 2 vCPU avoids login latency under load.\n- **Disk**: reserve at least **10 GB** free — PostgreSQL allocates WAL logs and active sessions accumulate quickly with the default audit logging enabled.\n- **Docker** ≥ 24.0 and **Docker Compose** ≥ 2.20 — pre-installed on all ServOrbit VPS plans.\n- **PostgreSQL 17 minimum** (included in the official Logto image) — older versions lack the required extensions.\n- **A domain name or subdomain** pointing to your VPS and resolving publicly: Logto bakes this domain into every OIDC token it issues. It must be set before the first start and cannot be changed without resetting all user data.",{"type":39,"title":46,"body":47},"How Logto works in production","Logto starts two containers: `db` (PostgreSQL 17 for users, apps, sessions, audit logs) and `logto` (Node.js serving the OIDC endpoint on port 3001 and the admin console on port 3002). The nginx reverse proxy on your VPS forwards HTTPS traffic on your domain to port 3001 — that's the endpoint your applications authenticate against. Port 3002 (admin console) is bound to localhost only and is accessible only via SSH tunnel, which keeps your user database management off the public internet.",{"type":49,"title":50,"items":51},"ul","What Logto provides out of the box",[52,53,54,55,56,57],"**OIDC\u002FOAuth 2.0 compliant tokens** — signed JWTs that any standard library (passport.js, python-jose, go-oidc) can verify without custom code.","**Social login connectors** — enable Google, GitHub, Apple, Microsoft, Discord and 30+ providers from the admin console in one click; each requires a 5-minute OAuth App setup on the provider side.","**Passwordless authentication** — send magic links (email) or OTP codes (SMS via Twilio, SendGrid, Mailgun) without maintaining a separate notification service.","**MFA** — TOTP (Google Authenticator, Authy), WebAuthn\u002FFIDO2 hardware keys, and backup codes, enforced by policy from the admin console.","**Role-based access control** — define roles and permissions in the console; receive them as `scope` claims in the JWT and enforce them in your API with a single middleware line.","**SDKs for 20+ frameworks** — React, Next.js, Vue, Angular, React Native, Flutter, Python, FastAPI, Go, PHP, Laravel, .NET, Java, Spring Boot and more.",{"type":59,"title":60,"steps":61},"steps","Docker Compose deployment step by step",[62,65,68,71,74,77],{"title":63,"body":64},"Create the working directory and Compose file","Connect to your VPS via SSH and create the working directory:\n\n```\nmkdir -p \u002Fopt\u002Flogto && cd \u002Fopt\u002Flogto\n```\n\nCreate the `docker-compose.yml` file with the following content. Replace `auth.your-domain.com` with your own domain:\n\n```yaml\nversion: '3.9'\nservices:\n  db:\n    image: postgres:17-alpine\n    restart: unless-stopped\n    environment:\n      POSTGRES_DB: logto\n      POSTGRES_USER: logto\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - logto_db:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n  logto:\n    image: svhd\u002Flogto:latest\n    restart: unless-stopped\n    depends_on:\n      - db\n    ports:\n      - '127.0.0.1:3001:3001'\n      - '127.0.0.1:3002:3002'\n    environment:\n      DB_URL: postgresql:\u002F\u002Flogto:${DB_PASSWORD}@db:5432\u002Flogto\n      ENDPOINT: https:\u002F\u002Fauth.your-domain.com\n      ADMIN_ENDPOINT: https:\u002F\u002Fauth.your-domain.com:3002\n      SECRET_VAULT_KEK: ${SECRET_VAULT_KEK}\nvolumes:\n  logto_db:\n```",{"title":66,"body":67},"Generate secrets and create the .env file","Generate a strong database password and an AES-256 key:\n\n```bash\nDB_PASSWORD=$(openssl rand -hex 32)\nSECRET_VAULT_KEK=$(openssl rand -hex 32)\nprintf \"DB_PASSWORD=%s\\nSECRET_VAULT_KEK=%s\\n\" \"$DB_PASSWORD\" \"$SECRET_VAULT_KEK\" > .env\nchmod 600 .env\n```\n\nVerify that `.env` contains two non-empty lines before proceeding.",{"title":69,"body":70},"Configure nginx as a reverse proxy","Create the vhost `\u002Fetc\u002Fnginx\u002Fsites-available\u002Flogto`:\n\n```nginx\nserver {\n    listen 443 ssl;\n    server_name auth.your-domain.com;\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fauth.your-domain.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fauth.your-domain.com\u002Fprivkey.pem;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3001;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto https;\n    }\n}\n```\n\nEnable the site and reload nginx:\n\n```bash\nln -s \u002Fetc\u002Fnginx\u002Fsites-available\u002Flogto \u002Fetc\u002Fnginx\u002Fsites-enabled\u002F\nnginx -t && systemctl reload nginx\n```",{"title":72,"body":73},"Start the stack and verify","Launch both containers:\n\n```bash\ndocker compose up -d\n```\n\nFollow the logs for 60 seconds to confirm PostgreSQL is ready and Logto has completed its migrations:\n\n```bash\ndocker compose logs -f --tail=50\n```\n\nYou should see the line `App is running at https:\u002F\u002Fauth.your-domain.com` — that is the signal the service is operational.",{"title":75,"body":76},"Verify the OIDC discovery document","From your local machine, check that the OIDC endpoint responds:\n\n```bash\ncurl -s https:\u002F\u002Fauth.your-domain.com\u002F.well-known\u002Fopenid-configuration | python3 -m json.tool | head -10\n```\n\nThe response must contain `issuer`, `authorization_endpoint` and `jwks_uri`. If the command returns a 502 error, Logto has not yet completed its migrations — wait 30 seconds and try again.",{"title":78,"body":79},"Set up automatic backups","Add a cron job to export the database daily:\n\n```bash\ncrontab -e\n# Add the following line:\n0 3 * * * docker exec $(docker compose -f \u002Fopt\u002Flogto\u002Fdocker-compose.yml ps -q db) pg_dump -U logto logto | gzip > \u002Fvar\u002Fbackups\u002Flogto_$(date +\\%Y\\%m\\%d).sql.gz\n```\n\nFor automated, deduplicated, encrypted backups to S3 or Backblaze B2, mount the `logto_db` volume to a Backrest instance available in the ServOrbit catalogue.",{"type":59,"title":81,"steps":82},"Logging in for the first time",[83,86,89,92],{"title":84,"body":85},"Open the SSH tunnel to the admin console","The admin console listens on port 3002, bound to localhost for security. From your local machine, open a tunnel:\n\n```bash\nssh -L 3002:127.0.0.1:3002 root@your-vps-ip\n```\n\nKeep this terminal open for the duration of your admin session.",{"title":87,"body":88},"Create the administrator account","Open `http:\u002F\u002Flocalhost:3002` in your browser. The first-run wizard appears — there are no default credentials. Enter an email address and a strong password, then click **Create account**. These credentials are yours for administering Logto; store them in a password manager.",{"title":90,"body":91},"Explore the dashboard","After creating the account, you land on the Logto dashboard. From here you can view the audit log, manage users, configure social connectors, and create **Applications** — the Logto entity that represents one of your projects.",{"title":93,"body":94},"Create your first Application","In the console: **Applications → Create application**. Choose the type that matches your project (Traditional Web, Single Page App, Native, or Machine-to-machine). Give it a name, then fill in the **Redirect URI** — the URL Logto redirects to after a successful login (for example `https:\u002F\u002Fmy-app.com\u002Fapi\u002Flogto\u002Fsign-in-callback` for a Next.js application). Logto then generates an `App ID` and `App Secret` that you will use in your SDK.",{"type":39,"title":96,"body":97},"Integrating Logto into a Next.js application","Install the SDK with `npm install @logto\u002Fnext`, then create a `logto.ts` that exports a `new LogtoClient({ … })` configured with `endpoint` (your Logto instance URL), `appId` and `appSecret` (from the Logto admin console), `baseUrl` (your application URL), `cookieSecret` and `cookieSecure`.\n\nTo protect a route, call `getLogtoContext({ getAccessToken: true })` imported from `@logto\u002Fnext\u002Fserver-component`: it returns `isAuthenticated` and the user's `claims`. If `isAuthenticated` is false, redirect to `\u002Fapi\u002Flogto\u002Fsign-in`; otherwise render the page from the claims you received.\n\nThat is the whole integration: fifteen lines of configuration, one import, one guard.",{"type":39,"title":99,"body":100},"Enabling Google social login","In the Google Cloud Console, create an OAuth 2.0 Client ID (Web application type). Set the authorised redirect URI to `https:\u002F\u002Fauth.your-domain.com\u002Fcallback\u002Fgoogle`. Copy the Client ID and Client Secret.\n\nIn the Logto admin console → Connectors → Social connectors → Google → Enable. Paste your Client ID and Secret, save. Google now appears as a sign-in option on your Logto sign-in page automatically — no code changes needed in your application.",{"type":102,"title":103,"intro":104,"columns":105,"rows":110,"note":130},"comparison","Logto, Authentik, Authelia, Keycloak — which one to choose?","Four open-source solutions for self-hosted authentication, with distinct use cases. The table below compares the three criteria that matter most at setup time.",[106,107,108,109],"Solution","Primary use case","Minimum RAM","SDK integration complexity",[111,116,120,125],[112,113,114,115],"**Logto**","Authentication for a product you are building (sign-up, JWTs, social connectors)","2 GB","Low — official SDK in 15 lines for React, Next.js, Python, Go, Flutter and 15+ more",[117,118,114,119],"**Authentik**","Centralised SSO for your self-hosted tools (Grafana, Gitea, Nextcloud, Proxmox)","Medium — configuration via Providers in the console, no application SDK",[121,122,123,124],"**Authelia**","MFA and login portal in front of existing apps, without modifying their code","256 MB","None — auth delegation via nginx header, no SDK integration",[126,127,128,129],"**Keycloak**","Enterprise SSO, LDAP\u002FAD federation, advanced multi-tenant scenarios","4 GB minimum","High — manual OIDC configuration, client libraries to set up per framework","For a SaaS product under development, Logto is the natural starting point. Keycloak suits organisations that already have an enterprise directory to integrate. Authelia and Authentik address infrastructure needs rather than application needs.",{"type":39,"title":132,"body":133},"Common troubleshooting","Here are the four most common issues during a first Logto VPS installation and how to resolve them.\n\n**Admin console inaccessible (port 3002)**\n\nPort 3002 is intentionally bound to `127.0.0.1` — it is not accessible directly from the internet. If `http:\u002F\u002Flocalhost:3002` does not respond, first verify your SSH tunnel is open (`ssh -L 3002:127.0.0.1:3002 root@\u003CIP>`). Then check that the Logto container is running: `docker compose ps`. If the container is in `Exit` state, inspect the logs: `docker compose logs logto --tail=50`.\n\n**OIDC discovery 502**\n\nLogto runs its database migrations on first start — this takes between 30 and 90 seconds depending on the VPS. If the discovery document `\u002F.well-known\u002Fopenid-configuration` returns 502, nginx is forwarding requests before Logto is ready. Wait 90 seconds and try again. If the error persists, check that PostgreSQL is healthy: `docker compose logs db --tail=20` — look for the line `database system is ready to accept connections`.\n\n**Redirect URI mismatch**\n\nLogto validates the redirect URI strictly: if the URI sent by your application does not match exactly what is declared in the Logto console (Application → Redirect URIs), the login fails with `redirect_uri_mismatch`. Verify you have registered the complete URL including the scheme (`https:\u002F\u002F`), the exact path, and the absence of a trailing slash if your SDK does not send one. Development URIs (`http:\u002F\u002Flocalhost:3000\u002F…`) must be added separately in the console.\n\n**Fatal: cannot connect to db**\n\nIf the Logto logs show `Fatal: cannot connect to db`, PostgreSQL was not yet ready when Logto tried to connect. The `depends_on` declaration in Docker Compose guarantees container startup order but not that PostgreSQL is accepting connections. Simply restart the Logto container: `docker compose restart logto`. It will reconnect as soon as PostgreSQL is ready.",{"type":39,"title":135,"body":136},"Backup strategy","Logto stores all its state in the `logto_db` PostgreSQL volume. Back it up with a `pg_dump` cron job or mount the volume to a Backrest instance (also in the ServOrbit marketplace) for automated, deduplicated, encrypted backups to S3, Backblaze B2 or SFTP. Losing the `logto_db` volume means losing all user accounts, application configurations, and audit logs — back it up before any VPS migration.","Your auth layer, on your own VPS","Deploy Logto on a ServOrbit VPS — own your users' authentication data, drop per-user billing, and integrate with SDKs for React, Next.js, Python, Go, Flutter and more.","Deploy Logto","\u002Fapplications\u002Fcybersecurity-bastion\u002Flogto",[142,166,188],{"id":143,"slug":144,"slugs":145,"title":149,"excerpt":150,"readTime":151,"views":151,"isPinned":19,"noindex":19,"publishedAt":152,"updatedAt":153,"category":154,"categories":160,"featuredImage":30,"bgImage":31,"posterImage":162,"relatedSolution":163},111,"centralizing-authentication-with-authentik-on-vps",{"fr":146,"en":144,"ar":147,"es":148},"sso-authentik-vps","مركزة-المصادقة-باستخدام-authentik-على-خادم-vps","centralizar-autenticacion-con-authentik-en-vps","Centralizing authentication with Authentik on VPS","Centralize the authentication of all your apps with self-hosted Authentik on a VPS: SSO, MFA and forward auth in Docker Compose.",9,"2026-03-01T00:00:00+00:00","2026-10-31T01:54:10+00:00",{"id":155,"name":156,"slug":157,"color":158,"icon":159},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[161],{"id":155,"name":156,"slug":157,"color":158,"icon":159},"\u002Fblog\u002Fcovers\u002Fsso-authentik-vps-poster.svg",{"categorySlug":164,"appSlug":165},"securite","authentik",{"id":167,"slug":168,"slugs":169,"title":173,"excerpt":174,"readTime":151,"views":18,"isPinned":19,"noindex":19,"publishedAt":175,"updatedAt":176,"category":177,"categories":183,"featuredImage":30,"bgImage":31,"posterImage":185,"relatedSolution":186},160,"how-to-self-host-infisical-on-a-vps",{"fr":170,"en":168,"ar":171,"es":172},"self-host-infisical-vps","كيفية-استضافة-infisical-ذاتيا-على-خادم-vps","como-autoalojar-infisical-en-un-vps","How to Self-Host Infisical on a VPS","Deploy Infisical on your VPS in under 20 min: RBAC, automatic rotation, GitHub Actions and GitLab CI integration, plus Redis and TLS troubleshooting.","2026-07-02T00:00:00+00:00","2026-10-16T01:57:38+00:00",{"id":178,"name":179,"slug":180,"color":181,"icon":182},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[184],{"id":178,"name":179,"slug":180,"color":181,"icon":182},"\u002Fblog\u002Fcovers\u002Fself-host-infisical-vps-poster.svg",{"categorySlug":34,"appSlug":187},"infisical",{"id":189,"slug":190,"slugs":191,"title":195,"excerpt":196,"readTime":197,"views":198,"isPinned":19,"noindex":19,"publishedAt":199,"updatedAt":200,"category":201,"categories":202,"featuredImage":30,"bgImage":31,"posterImage":204,"relatedSolution":205},131,"self-host-your-password-manager-deploy-vaultwarden-on-vps",{"fr":192,"en":190,"ar":193,"es":194},"deploy-vaultwarden-vps","استضف-مدير-كلمات-المرور-بنفسك-انشر-vaultwarden-على-vps","desplegar-vaultwarden-en-un-vps","Deploy Vaultwarden on a VPS: self-hosted password manager","Self-host Vaultwarden on a VPS: password management, Bitwarden compatibility, team vaults and TOTP, at a fixed monthly cost and under 50 MB of RAM.",15,3,"2026-06-24T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":155,"name":156,"slug":157,"color":158,"icon":159},[203],{"id":155,"name":156,"slug":157,"color":158,"icon":159},"\u002Fblog\u002Fcovers\u002Fdeploy-vaultwarden-vps-poster.svg",{"categorySlug":159,"appSlug":206},"vaultwarden",true,1794270489622]