Skip to content

Custom domain setup fails with "Not authorized" on self-hosted instances #2045

Description

@scorpion7slayer

Custom domain setup fails with "Not authorized" on self-hosted instances

Description

When trying to set up a custom domain for an organization on a self-hosted Cap instance, the operation fails with a 500 Internal Server Error and the message "Not authorized".

The custom domain dialog works fine (UI loads, input is enabled, the "Next" button is clickable), but clicking "Next" triggers a Server Action (POST /dashboard/settings/organization) that returns a 500 error.

Steps to reproduce

  1. Deploy Cap using the official docker-compose.coolify.yml or docker-compose.yml with the pre-built image ghcr.io/capsoftware/cap-web:latest
  2. Log in and go to Organization Settings
  3. Click Setup on the Custom Domain section
  4. Enter a valid domain (e.g. share.example.com)
  5. Click Next

Expected behavior

The domain should be saved and the setup should proceed to the verification step.

Actual behavior

The request fails with:

POST https://cap.example.com/dashboard/settings/organization 500 (Internal Server Error)

Server logs show:

⨯ Error: Not authorized

Root cause analysis

After investigating the source code, the issue appears to be related to two things:

  1. NEXT_PUBLIC_IS_CAP is not set in the pre-built Docker image. The proxy middleware in apps/web/proxy.ts activates restrictive logic when buildEnv.NEXT_PUBLIC_IS_CAP !== "true". While /dashboard is in the allowlist, the Server Action context may still be affected by the middleware behavior on self-hosted builds.

  2. The getCurrentUser() call in apps/web/actions/organization/update-domain.ts returns null for the Server Action, even though the same session works fine for page rendering. This suggests the session is not being properly passed or validated in the Server Action context on self-hosted builds.

Environment

  • Cap version: ghcr.io/capsoftware/cap-web:latest (as of July 2026)
  • Deployment: Docker Compose on VPS (Dokploy)
  • NEXT_PUBLIC_IS_CAP: not set (default in pre-built image)
  • WEB_URL and NEXTAUTH_URL: correctly configured with production domain
  • NEXTAUTH_SECRET: properly generated with openssl rand -hex 32

Suggested fix

Either:

  • Set NEXT_PUBLIC_IS_CAP=true in the pre-built Docker image so self-hosted instances behave like cap.so
  • Or ensure Server Actions properly pass the session on self-hosted builds where NEXT_PUBLIC_IS_CAP is unset
  • Or document that custom domains require building from source with NEXT_PUBLIC_IS_CAP=true

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions