Dify CORS and public URL configuration

Replace wildcard CORS defaults and align console, API, app and file URLs in self-hosted Dify so browsers, tokens and download links only work for the hosts you intend.

On this page

Why Dify CORS and public URL configuration matters before go-live

CORS and public URL settings decide which browser origins may call the Dify console and web APIs, and which hostnames Dify writes into the links and redirects it generates. Set them before go-live as soon as users reach the instance through a hostname behind a reverse proxy, which is the normal layout for the Docker Compose deployment, where an Nginx service sits in front of the web and api services. Leaving the defaults in place can mean the browser accepts calls from any origin, and the instance may generate links that point at an internal address that users cannot reach.

Dify exposes several surfaces on different addresses: the console used by builders, the web apps used by end users, the service API used by products and pipelines, and file URLs for uploads and downloads. Each has a public address that the browser or client actually sees, and the console, web app and API hosts must agree with the origins you allow. Session cookies and JWTs are signed with SECRET_KEY, but the host a token is issued for is a separate question, so a mismatch can send a user to the wrong host or break sign-in. Confirm the exact variable names for each surface in the Dify environment variable reference before you write them into .env.

Before go-live, list every hostname that serves Dify, record which origin each surface needs, and test sign-in, app use, file upload and an API call from a browser on a separate host. Include a check that generated links resolve to the public name. Because the Docker Compose upgrade guidance asks operators to compare .env.example after each upgrade, add these values to the change record so a new release does not silently reset them. Ask your security reviewer to confirm that no wildcard origin remains in the final configuration.

Which CORS and URL settings fit which deployment

This table compares four common ways to publish a self-hosted Dify console, web apps, API and files, along with the origin list each one needs. Read each row against your own traffic paths, then confirm exact keys in the Dify environment variable reference. The main takeaway: every public host you add widens the set of sites allowed to call console APIs, so keep the list to hosts you operate.

Deployment patternWhen it fitsOrigins and URLs to setWhat breaks if left wide
Single public hostnameOne team, one reverse proxy, no separate end-user app domainConsole, web app and file URLs on one host; origin list contains only that hostAny site a user visits could make authenticated console calls from their browser
Separate console and app hostnamesEnd users open apps on their own domain while staff use a console domainConsole origin and app origin listed separately; file URL reachable from bothAn app host could read responses or tokens meant for the console host
Internal-only console behind VPNAdministrators and automation reach the console only over a private networkInternal console host only; no public origin for the consolePublic exposure of administrative APIs that were meant to stay private
API behind a separate gatewayA gateway already handles TLS, routing and authentication ahead of DifyGateway hostname as the public API URL; origins limited to the gateway and approved front endsClients may call Dify directly, bypassing gateway authentication and rate limits

How to set explicit origins and public URLs step by step

This sequence replaces wildcard cross-origin defaults with an explicit allowlist and aligns the console, app, API and file URLs so that sign-in, embedded apps and generated links point at the hosts you intend. Each step closes with a check you can repeat after every change.

  1. Inventory every hostname, scheme and origin

    The platform team lists every address that reaches the deployment: the console, the published web apps, the service API, the file endpoints, any MCP endpoints, and every site that embeds a Dify app. For each entry, record the scheme, host, and port exactly as a browser sends them, because a trailing slash, a missing port or an http address will fail an exact match later. Confirm the list with the teams that own the embedding sites. Build and test this first in a non-production instance, so that wrong entries surface before any production configuration changes. The step is done when every browser-facing origin has one row in a shared document and an owner has signed off on it.

  2. Set the console and app public URLs

    The operator sets the public addresses that Dify uses to build links for the console, the web apps and the API in the environment file, which is typically .env next to the Docker Compose file. The variables to confirm against your version include CONSOLE_WEB_URL, CONSOLE_API_URL, APP_WEB_URL and SERVICE_API_URL. Use the full https address that users actually type, and avoid internal container names, which will leak into links. The Dify environment variable reference lists the current names and defaults, so check it against the .env.example file that ships with your release. The step is done when each variable matches a row from the inventory and no value points at localhost or an internal name.

  3. Define the explicit origin allowlist

    The operator replaces any wildcard value in the cross-origin settings with a comma-separated list of exact origins, such as CONSOLE_CORS_ALLOW_ORIGINS for the console API and WEB_API_CORS_ALLOW_ORIGINS for the web app and embedded API. Each entry includes the scheme, host and port, and no path. Keep the console and web app lists separate, so that an embedding site gets access only to the web API and not to console endpoints. Confirm the exact variable names in the environment reference for your version. The step is done when a review of the final values shows no asterisk, no path segments, and no origin that is absent from the inventory.

  4. Align file and reverse proxy URLs

    The platform team sets the file URL variables, such as FILES_URL, so that uploaded files and their download links resolve through the public host instead of an internal address. If a reverse proxy or load balancer sits in front of the Nginx service, confirm that it forwards the original host and the forwarded protocol headers, and that the Dify services are configured to trust them. Document which addresses are internal for service-to-service traffic and which are public for users, so that nobody later swaps them. The step is done when an uploaded test file produces a download link on the intended public host, and a request through the proxy returns the same host name in the response.

  5. Restart the services and check preflight responses

    After saving the environment file, the operator restarts the affected containers using the restart method described in the Docker Compose deployment guide for your version, so that the new values load. Then the tester sends preflight OPTIONS requests with an Origin header for an allowed site and for a site that is not on the list. The allowed origin should receive a matching Access-Control-Allow-Origin header, and the disallowed origin should receive none. Repeat the check for the console API and the web API. The step is done when both allowed and denied results match the allowlist in a written test log.

  6. Verify generated links and keep the upgrade path clear

    The tester signs in through the public console address, opens a published web app, generates the embed code, and copies an API endpoint from the app page. Each of these must resolve to the intended host, and sign-in must return to the same host without a redirect to an internal address. Record the results against the inventory, then add a standing item to the change record: when the Dify version changes, the operator reviews the upgrade guide for the target release in the GitHub Releases notes and compares .env.example for new or renamed variables before repeating this sequence. The step is done when every link in the test log resolves to an inventory entry and the change record names the owner of the next review.

Security risks when CORS and public URLs are left at defaults

Dify's browser-facing console, web app and file endpoints each depend on the origin and host they are served from. When CORS and public URL settings are left unchanged, or drift after a hostname change, browsers may accept calls they should refuse, and links and tokens may point at hosts users cannot reach or should not trust. The cards below pair each risk with the control that addresses it.

Wildcard origins expose authenticated APIs

A wildcard origin lets any website ask a user's browser to call Dify's console and API endpoints. Where a signed-in user has a session, a page on an unrelated domain can read responses it should never see. Set explicit origins for the console and web API paths, using the CORS allowlist variables in .env. Check the active values in the running containers, not only in the file, and confirm each listed origin is one you own and operate.

Tokens issued for an internal hostname

Dify builds some links and redirects from its configured public addresses. If those addresses still point at an internal name such as a container or private DNS record, users may be sent to a host they cannot resolve, or a link may be shared outside the network with an address that only works inside it. Review the console, app and API base URL settings, and test a login and an app share link from a device outside your network.

File URLs served on the wrong host

Uploaded documents and generated files are retrieved through URLs that Dify builds from its file address setting. If that setting names a different host than the one users reach, downloads can fail, or files can be fetched from an address that bypasses the proxy and access path you intended. Confirm the file URL setting matches the public host behind your reverse proxy, then upload and download a test file as an ordinary user.

Embedding sites missing from the allowlist

Web apps embedded in partner portals, intranets or product pages make cross-origin requests to Dify. Each embedding site must appear in the allowlist for the web API, or its users see failed requests with no clear error. Keep a written register of every site that embeds a Dify app, with its owner, and review the list when a new embedding is requested so that no origin is added only because a request failed.

Configuration drift after a hostname change

A new domain, certificate or load balancer changes the public host, but CORS origins, console URLs and file URLs are often updated in some places and not others. The result is a mix of working and broken paths, and sometimes a path that still accepts an old origin. Treat a hostname change as a planned change: list every public address setting, update them together, restart the services, and retest login, uploads, embeds and API calls before retiring the old name.

SECRET_KEY and session settings out of step

SECRET_KEY signs session cookies and JWTs, and changing it after deployment logs out all users. Changing public URLs or moving to a new host can also change how cookies are scoped and sent, so a hostname change can look like a login failure. Keep SECRET_KEY unchanged during URL work, record its value in your secrets store, and schedule any rotation as a planned window with users warned in advance.

Questions teams ask about Dify CORS and public URL setup

How much effort does it take to replace wildcard CORS and align Dify's public URLs?

The effort is usually modest in the configuration itself but depends heavily on how many hosts you serve. The main drivers are how many public hostnames exist (console, web app, API, file access), whether they sit behind one reverse proxy or several, how many embedding sites call the APIs from browsers, and whether any integration relies on the current permissive behavior. Each additional origin needs an explicit entry, a test, and an owner who approves it. Ask any partner to price the work from a written list of hostnames and calling applications, not from a headcount guess.

Can our own team configure CORS and public URLs without outside help?

Yes, if your engineers are comfortable with Docker Compose, environment files and reverse proxy configuration, and if someone owns the decision about which origins are trusted. The configuration keys live in the environment reference and the Compose setup, so the technical steps are not secret. Outside help tends to add value when many embedding sites or internal tools call the APIs, when browser behavior has to be verified across several clients, or when the team lacks time to test upgrades. Confirm the exact keys for your release in the environment variable reference before you change anything.

What does our team need to provide for this work?

Plan for four inputs: DNS records for each public hostname, valid TLS certificates that match those hostnames, access to the reverse proxy or load balancer that fronts Dify, and a few test users who can sign in from each allowed origin. Your team also needs to list every application that calls the API from a browser, because those origins must be approved explicitly. If you use a separate file or object storage endpoint, its public address must be known too. Missing any of these usually shows up as failed logins or broken file links during testing, not during the configuration step.

How long does validation take once the origins and URLs are set?

Validation time depends on the number of hostnames and the number of browser clients, not on the configuration edit itself. A reasonable test covers sign-in from the console, opening a published web app, calling the API from each approved origin, confirming that an unapproved origin is refused, and checking that uploaded file links and redirects point at the correct host. Each test needs a named tester and a recorded result. Agree on the test cases and sign-off criteria in writing before the work starts so that the duration is set by a defined checklist.

What changes when we upgrade Dify, and do our CORS settings survive?

Upgrades can change how environment variables are named, defaulted or documented, so your CORS and URL settings should be checked after every upgrade, not assumed to carry over. The Docker Compose guidance says to back up before each upgrade, follow the upgrade guide for the target release, and check the example environment file for new variables. Minor releases arrive about monthly, so a repeatable post-upgrade test of login, API calls and file links is worth keeping. Keep your origin list in version control so a change is reviewed and can be reapplied.

Does this work differ between the Community and Enterprise editions?

The CORS and public URL settings apply to the self-hosted deployment in both editions, because they are configured on the platform itself. The pricing page describes the Community edition as free and limited to a single workspace, while the Enterprise edition is custom priced and adds SSO, multiple workspaces, advanced security, a commercial license and professional support. If you plan to use Enterprise, confirm with the vendor how its features, such as SSO, interact with your public hostnames and login redirects. Licensing terms also matter for multi-tenant use, which the Dify Open Source License restricts without written authorization.

Keeping URL and origin settings correct through upgrades and host changes

Origin and URL settings drift over time, and upgrades are the most common moment they break. Minor Dify releases arrive roughly monthly according to the releases page on GitHub, with 1.16.0 on July 17, 2026 and 1.17.0 on August 25, 2026 as recent examples, so a team on a self-hosted instance will face this check many times a year. Treat each upgrade as a planned change: follow the upgrade guide for the target version, take a backup before you start, and then compare your .env file against .env.example in the new release. New variables that govern console, API, app and file URLs or CORS behavior can appear in a release, and an older value you copied forward may no longer match what the new version expects.

After any upgrade, and before users or integrations depend on it, confirm that the console loads and logs in, that a published web app opens from its own address, that a service API call from an allowed browser origin succeeds, and that a disallowed origin is refused. Check that file download and preview links point at the public host rather than an internal container name. Then repeat the same checks after a hostname change, a certificate renewal or replacement, or any edit to the Nginx or other reverse proxy in front of Dify, since each of these can alter the host header, the scheme or the forwarded address that the application reads. Record the results so the next upgrade has a baseline to compare against.

Confirm with your own team which values in your environment are tied to the public host, including any SSO redirect URIs and webhook or callback addresses configured in other systems, because these are not covered by a Dify upgrade guide. Ask whether the target release changes any of these variables before you schedule the window, and plan the rollback path around the backup you took, not around reverting a single setting.

How DeployOpen scopes this work

A CORS and public URL change touches every browser, embed and integration that talks to your Dify instance, so scope starts with an inventory rather than a config file. The cards below list what DeployOpen asks for before writing a fixed-scope proposal, and what the written deliverable contains.

Hostname and URL inventory

List every public and internal hostname that serves the console, the web apps, the service API and uploaded files, along with the scheme and port each one uses. Include staging and any preview hosts. Mismatches between the console domain and the API or file domain are the most common reason tokens and links point at the wrong host, so this list is the first input DeployOpen reviews. Confirm which hostnames your reverse proxy and load balancer actually terminate.

Embedding and integration list

Record each website, portal or internal application that calls Dify from a browser or embeds a web app, and each server-side client that calls the API without a browser. Browser callers need explicit origins in the allowlist, while server-side callers do not depend on CORS at all. Knowing which group each caller belongs to keeps the origin list short and avoids opening access for tools that never needed it.

Proxy and certificate ownership

Name the team that owns the reverse proxy configuration, the TLS certificates, DNS records and any CDN in front of Dify. Header rewrites, forwarded host and scheme settings, and the public URL variables all depend on what that layer does. DeployOpen needs written confirmation of who changes each layer and who approves a change, because CORS and URL fixes usually fail at the proxy rather than in the application.

Test plan and acceptance criteria

Agree the browser and API tests that prove the change works before any setting is changed. Typical checks include a preflight request from an allowed origin, a refused request from an unlisted origin, sign-in and token refresh on each hostname, and a file link opened from a generated answer. The acceptance criteria are written with your team so that a passing result has a clear meaning for both sides.

Written fixed-scope deliverable

Most engagements are fixed-scope, so the output is a written statement of the hostnames covered, the configuration changes, the tests run, the rollback steps and the items left out. Scope boundaries matter here, for example whether SSO redirect URIs or plugin endpoints are included. Ask for the deliverable list in writing before work starts, and confirm how changes after the agreed scope are priced and approved.

How DeployOpen works on this

DeployOpen plans and implements self-hosted Dify inside your own infrastructure, including the origin and URL settings that decide which hosts can call the console and API and which hosts receive tokens and file links. Engagements are fixed-scope, with the written scope agreed before work starts.

How we scope

  • Inventory every public hostname for the console, web apps, service API, file access and any embedded pages
  • Record the current CORS and public URL values and which clients depend on them
  • Agree in writing which origins, hostnames and reverse proxy paths are in and out of scope

How we build

  • Set explicit allowed origins in place of wildcard defaults and test each intended browser client
  • Align the console, API, web app and file URLs so generated links resolve to the correct host
  • Verify preflight responses and token issuance against each hostname in a staging copy before production

How we hand over

  • Deliver a written record of each origin, URL variable, proxy rule and the reason it exists
  • Document the test cases used to confirm rejected origins and correct link generation
  • Provide a change procedure that covers hostname changes, certificate renewals and upgrade checks

How we support

  • Recheck origin and URL settings after each Dify upgrade, since new variables may appear in the example env file
  • Ongoing support and upgrades are available as a retainer, scoped in writing
  • Quotes follow from the written scope, so ask for each item and its recurring cost separately

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.