Fixing the OpenPanel Signup Issue on Dokploy

· updated · post dokploy openpanel traefik

When deploying OpenPanel on Dokploy, many users encounter a puzzling issue after the first spin-up:

The dashboard loads fine — but signup (and sometimes login) simply doesn’t work.

The browser console reports errors like:

Laden von gemischten aktiven Inhalten "http://monitor-openpanel-…/trpc/auth.signUpEmail" wurde blockiert.

and later, after partial fixes:

Cross-Origin-Anfrage blockiert: Die Gleiche-Quelle-Regel verbietet das Lesen der externen Ressource...

At first, it looks like a frontend or network bug — but the actual problem lies in how Dokploy’s Traefik reverse proxy, HTTPS setup, and OpenPanel’s environment variables interact.

Let’s break down what’s happening and how to fix it properly.

🔍 The Problem: Mixed Content, CORS, and Misaligned URLs

OpenPanel is a modern analytics stack composed of multiple services:

Dokploy automatically provisions and exposes these services behind Traefik, which manages routing, HTTPS certificates, and load balancing.

When OpenPanel is first deployed through Dokploy, it is usually assigned temporary Traefik test URLs, for example:

https://monitor-openpanel-XXXX.traefik.me

Later, you might configure manual redirects or custom domains (e.g. dashboard.example.com for the dashboard and api.example.com for the API). This is done in the settings pannel of the service directly in Dokploy.

This domain change introduces the real problem:

As a result:

⚙️ Step 1 — Correcting Base URLs in the Environment Configuration

The most critical fix is to ensure every service knows the correct public URLs for the dashboard and API.

OpenPanel uses Next.js, which reads these variables at build and runtime to form absolute URLs.

In the .env file, define the URLs explicitly for your final domains:

# Domains
DASHBOARD_HOST=dashboard.example.com
API_HOST=api.example.com

# Public origins
NEXT_PUBLIC_DASHBOARD_URL=https://${DASHBOARD_HOST}
NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_DASHBOARD_URL}
NEXT_PUBLIC_API_URL=https://${API_HOST}

# NextAuth (if used)
NEXTAUTH_URL=${NEXT_PUBLIC_DASHBOARD_URL}
AUTH_TRUST_HOST=true

Why this matters:

🧱 Step 2 — Configuring Traefik to Handle HTTPS and CORS

Dokploy already ships with a working Traefik setup. However, for multi-domain OpenPanel deployments, we need to make it explicitly enforce HTTPS and allow cross-origin requests from the dashboard to the API.

✅ Static Traefik configuration (/etc/dokploy/traefik/traefik.yml)

This is Dokploy’s default configuration, which we keep intact. It ensures Traefik listens on both ports 80 (HTTP) and 443 (HTTPS), with automatic Let’s Encrypt certificate provisioning.

entryPoints:
    web:
        address: :80
    websecure:
        address: :443
        http3:
            advertisedPort: 443
        http:
            tls:
                certResolver: letsencrypt

✅ Dynamic middlewares (/etc/dokploy/traefik/dynamic/middlewares.yml)

We add two key middlewares:

  1. redirect-to-https — Redirects all HTTP requests to HTTPS.
  2. openpanel-cors — Allows the dashboard origin to access the API safely.
http:
    middlewares:
        redirect-to-https:
            redirectScheme:
                scheme: https
                permanent: true

        openpanel-cors:
            headers:
                accessControlAllowOriginList:
                    - 'https://dashboard.example.com'
                accessControlAllowMethods:
                    - GET
                    - POST
                    - PUT
                    - PATCH
                    - DELETE
                    - OPTIONS
                accessControlAllowHeaders:
                    - '*'
                accessControlAllowCredentials: true
                addVaryHeader: true

Explanation:

✅ Traefik labels in the Docker configuration

We attach these middlewares to the respective services via labels.

API service (op-api)

labels:
    - 'traefik.enable=true'
    - 'traefik.http.routers.openpanel-api.rule=Host(`${API_HOST}`)'
    - 'traefik.http.routers.openpanel-api.entrypoints=websecure'
    - 'traefik.http.routers.openpanel-api.tls=true'
    - 'traefik.http.routers.openpanel-api.middlewares=openpanel-cors@file'
    - 'traefik.http.services.openpanel-api.loadbalancer.server.port=3000'

    # HTTP → HTTPS redirect
    - 'traefik.http.routers.openpanel-api-http.rule=Host(`${API_HOST}`)'
    - 'traefik.http.routers.openpanel-api-http.entrypoints=web'
    - 'traefik.http.routers.openpanel-api-http.middlewares=redirect-to-https@file'

Dashboard service (op-dashboard)

labels:
    - 'traefik.enable=true'
    - 'traefik.http.routers.openpanel-dash.rule=Host(`${DASHBOARD_HOST}`)'
    - 'traefik.http.routers.openpanel-dash.entrypoints=websecure'
    - 'traefik.http.routers.openpanel-dash.tls=true'
    - 'traefik.http.services.openpanel-dash.loadbalancer.server.port=3000'

    # HTTP → HTTPS redirect
    - 'traefik.http.routers.openpanel-dash-http.rule=Host(`${DASHBOARD_HOST}`)'
    - 'traefik.http.routers.openpanel-dash-http.entrypoints=web'
    - 'traefik.http.routers.openpanel-dash-http.middlewares=redirect-to-https@file'

Why this works:

🩺 Step 3 — Fixing the “Unhealthy Container” Problem

After HTTPS and CORS were fixed, Dokploy still sometimes failed the deployment with:

dependency failed to start: container op-api-1 is unhealthy

This happens because Dokploy checks container health via the HEALTHCHECK directive in Docker Compose. OpenPanel’s API runs database migrations on first start, which can delay the healthcheck response.

The solution is to simplify the healthcheck to a TCP-level check and give it more time.

healthcheck:
    test: ['CMD-SHELL', 'nc -z localhost 3000']
    interval: 10s
    timeout: 5s
    retries: 60
    start_period: 180s

Additionally, other services (op-dashboard, op-worker) should not wait for a “healthy” API, just for it to be “started”:

depends_on:
    op-api:
        condition: service_started

Why this works:

✅ The Final Result

After applying these fixes:

🚀 Lessons Learned

  1. Dokploy’s automation is powerful, but explicit configuration is key when you introduce custom domains.
  2. Next.js apps require correct public URLs (NEXT_PUBLIC_API_URL, NEXT_PUBLIC_DASHBOARD_URL) — otherwise, the frontend calls the wrong endpoint.
  3. Traefik handles HTTPS and CORS elegantly, but only if you tell it exactly what to allow.
  4. Healthchecks should reflect startup behavior — migrations and initialization often take longer on first boot.
  5. Centralizing domains in .env keeps your stack maintainable across staging and production.