Production deployment with Docker Compose: what changes from the test stack
A Compose stack is a workable production target for a single host or a small team, but only when secrets, sizing, dependencies, TLS and upgrades are planned before users arrive. The default stack starts the api, worker, web, plugin daemon, PostgreSQL, Redis, Weaviate, Nginx, a code sandbox and an SSRF proxy on one machine. The documented minimum of 2 CPU cores, 4 GB of RAM and Docker Compose 2.24.0 or later is a floor for evaluation and does not replace a sizing exercise. Confirm host capacity against your document volume, workflow concurrency and user count, and record in writing that one host is one failure domain with no built-in high availability. The Dify deployment overview positions Kubernetes-based Enterprise deployment for high availability, SSO and multiple workspaces.
Start with SECRET_KEY in your .env file, since it signs session cookies and JWTs and encrypts OAuth credentials. Replace the default before the first login, because changing it after deployment logs out all users. Generate the value with a cryptographic random source, store it in your secrets manager, and back it up with the rest of your configuration so a restored host uses the same value. Keep .env out of version control, restrict its file permissions, and keep the SSRF_PROXY settings enabled so outbound requests from workflows and tools pass through a proxy that blocks internal and private IP ranges. Then decide which dependencies leave the host. The bundled PostgreSQL, Redis, Weaviate and file storage are the usual candidates, and each move changes who owns backups and failover, so plan those moves together with this deployment rather than afterward.
Plan upgrades before you need one. Dify minor releases arrive roughly monthly, with 1.16.0 on July 17, 2026, 1.17.0 on August 25, 2026 and 1.17.1 on September 10, 2026, so an unmaintained host falls behind quickly. For each upgrade, follow the guide for the target version on the GitHub releases page, take a backup first, and compare your .env with .env.example for new variables. Consider Enterprise on Kubernetes when the Community edition's single-workspace limit or the lack of SSO and high availability no longer fit. The Enterprise resources checklist requires Kubernetes 1.24 or later, Helm 3.14 or later, PostgreSQL 14 or later, Redis 6 or later, Qdrant and S3-compatible or cloud object storage. Enterprise pricing is custom, so request a written quote based on your workspace count, availability target and support needs.
Which core services and dependencies to move out of the Compose stack
This table compares each bundled container in the Compose stack with the supported alternatives named in the Dify environment reference. Read each row for the condition that justifies moving a component out and the operational cost of keeping it inside the same host.
| Component | Supported alternatives | When to move it out | Cost of keeping it bundled |
|---|---|---|---|
| PostgreSQL metadata database | External PostgreSQL (default engine), MySQL or OceanBase as the alternative engine | Move out when you need managed backups, point-in-time recovery, high availability or a database team that already runs PostgreSQL | Backups, upgrades and disk growth fall on the Compose host, and a host failure takes the metadata store with it |
| Redis | External Redis service with TLS and access controls | Move out when shared Redis is required, when you need replication, or when host restarts must not reset queues | A single container is a failure point for Celery queues and cache, and its persistence is tied to the host volume |
| Weaviate vector store | Qdrant, Milvus, pgvector, OpenSearch or Elasticsearch | Move out when knowledge base size, retrieval load or an existing vector platform makes the default store a poor fit | Index data, snapshots and version upgrades share the host with every other service, and the client must match the Dify version |
| File storage (local volume) | OpenDAL, S3-compatible storage, Azure Blob or Google Cloud Storage | Move out when uploads and dataset documents must survive host loss or sit in an approved storage account | Local volumes need separate backup and capacity monitoring, and restoring them alone can leave database and file state out of step |
| Nginx TLS entry point | Your corporate reverse proxy, load balancer or ingress | Move out when a central WAF, certificate process or proxy policy already governs public endpoints | Certificate renewal, header trust and upload limits are set in a container you must maintain alongside Dify |
| Code sandbox | Keep bundled in the Compose stack (no external alternative in the environment reference) | Keep it bundled unless your own isolation design for agent code execution has been reviewed and confirmed | It runs untrusted code paths, so host resource limits and network rules must be confirmed in your environment |
| SSRF proxy | Keep bundled in the Compose stack, with outbound rules confirmed for your network | Keep it bundled and confirm which internal and external endpoints it must reach for model providers and plugins | Blocked or misrouted outbound calls appear as model or plugin failures, so changes need testing against every provider |
Setup sequence: from secrets to a verified production host
This sequence takes a Dify Docker Compose stack from a default test install to a host with pinned images, unique secrets, sized resources, chosen dependencies moved out and a verified, backed-up baseline. Each step closes with a check you can run before moving on.
Pin the Dify release from GitHub
Choose the release you will run from the langgenius/dify releases page, and record the exact version tag in your change record. Read the upgrade guide for that version before you pull anything, because minor releases arrive roughly monthly and each one can change configuration. Check out the matching tag of the repository rather than tracking the main branch, so that the Compose files and the .env.example you edit come from the same release. Done when the tag, the image versions in docker-compose.yaml and the release notes you reviewed are all written down in the same record.
Generate and store a unique SECRET_KEY
Before the first start, generate a long random value for SECRET_KEY on a trusted workstation and write it to your secrets store, not to a shared document. Dify uses this key to sign session cookies and JWTs and to encrypt OAuth credentials, and changing it after deployment logs out all users, so it must be fixed for the life of the instance. Also replace the other default passwords in the stack, including the PostgreSQL and Redis credentials, with unique values. Done when no default value from the example file remains in the environment you will deploy, and the key is backed up in your secrets manager.
Copy and edit the env file from the example
Copy .env.example to .env in the Compose directory, then edit only the variables you have decided on: secrets, database and storage settings, and public URLs. Keep the file under change control and restrict its permissions so that only the deployment account and the Docker daemon can read it. Use the environment variable reference as the authority for each key, and record every change with a reason. Done when a diff against the release's .env.example shows only the intentional changes, and the file is stored outside the repository that holds public configuration.
Size the host against your expected load
The documented minimum is 2 CPU cores, 4 GB of RAM and Docker Compose 2.24.0 or later, which is enough for a test instance but leaves little headroom for knowledge indexing and concurrent workflows. Size above that minimum based on your expected users, indexing volume and workflow concurrency, and confirm the Compose version on the host with the version command. Plan disk for PostgreSQL, Weaviate and uploaded files as separate growth paths. Done when the host meets or exceeds your sizing target, Docker Compose reports 2.24.0 or later, and you have a written capacity note with the figures you chose and why.
Move chosen dependencies out of the bundled stack
Decide which bundled services stay inside the Compose stack and which move to infrastructure you already operate, typically the metadata database, Redis and object storage, and possibly the vector store. Update the connection variables in .env for each moved service, and disable or remove the corresponding containers from the Compose file only after the target service is reachable from the Dify host. Confirm that the external services are backed up and monitored by their owners before cutover. Done when each moved dependency answers a connection test from the Dify host, and the Compose file no longer starts containers for services you have replaced.
Configure SSRF_PROXY and public URL variables
Set the SSRF_PROXY settings so that outbound requests from Dify pass through the proxy, which blocks internal and private IP ranges, and confirm the proxy is listed in the Compose stack or reachable from it. Then set the URL variables that tell Dify its public address, using the exact external hostname and scheme that users will type into the browser. Mismatched URL values cause login, callback and file download failures that look like application bugs. Done when outbound calls to a private test address are refused through the proxy, and the public URL variables match the hostname your users will reach.
Start the stack and check each service
Start the stack with Docker Compose in detached mode, then review the status of every container, including api, worker, web, plugin daemon, PostgreSQL, Redis, the vector store, Nginx, the code sandbox and the SSRF proxy. Read the logs for the api and worker services and look for database migration errors, connection refusals and missing variables. Load the web console, sign in with the first administrator account, and confirm that the API responds on its health path. Done when every container reports a healthy or running state, the logs show no repeated errors after startup, and you can complete a sign-in from the browser.
Take and test the first backup
Once the stack runs cleanly, take a backup of the metadata database, the vector store data, the storage volume and the .env file, stored in a location separate from the host. Restore the backup into a separate test environment and confirm that you can sign in and see the apps, knowledge bases and workspace data you created. Record the backup procedure, the restore steps and the owner. The Dify docs advise a backup before every upgrade, so this procedure becomes the baseline for future changes. Done when a restore has been completed in a test environment and the restored instance matches the source.
How to lay out the env file so upgrades stay manageable
Treat .env.example as the reference for what Dify expects, and keep your production values in .env so the two files never blur together. The Dify Docker Compose docs advise checking .env.example for new variables after every upgrade, and minor releases arrive roughly monthly, so this check is a recurring task rather than a one-time setup step. Before each upgrade, diff the template for the target version against the one you deployed from, note any new keys, and decide whether each one needs a value in your .env before the new images start. Keep the .env file out of the template and out of any shared repository history where it could be copied, and back it up with the rest of your deployment state before every upgrade.
Record every override you have made to a default, with the reason and the date it was set. A short change log kept next to your deployment (for example, one line per key stating the value category, the owner and the reason for the change) lets the next operator tell a deliberate setting from a leftover experiment. Without this record, a future upgrade tends to either silently reset a setting you depended on or preserve a workaround that the new release no longer needs. Store the log separately from the secret values themselves, so reviewers can see what changed without reading credentials.
Handle SECRET_KEY as a secret that must not change after deployment. The environment reference says it signs session cookies and JWTs and encrypts OAuth credentials, and changing it after deployment logs out all users. Generate it once with a long random value, store it in your secrets management system, and confirm that your backup and restore process carries the same value, because a restored instance with a different key will break existing sessions and encrypted credentials. Make the key an explicit item in your upgrade checklist so that no one regenerates it while replacing the file.
Security controls to set before go-live
A Compose deployment inherits its security posture from a handful of settings, most of them in the env file and the published port list. The controls below cover secrets, network exposure, outbound requests, agent execution, encryption keys and backups, and each one needs a specific check before users arrive.
Replace default secrets and passwords
The .env file ships with placeholder values, including SECRET_KEY and the database and Redis passwords. Generate a new random SECRET_KEY before first login, because the environment reference says it signs session cookies and JWTs and encrypts OAuth credentials. Changing it after deployment logs out all users, so set it once and store it in your secrets manager. Verify that no default value remains in the running containers' environment.
Restrict published ports
Compose publishes several service ports to the host by default, so a host firewall and the port mappings in the Compose file decide what is reachable. Only the web entry point should be exposed to users, while database, Redis and vector store ports stay on the internal Docker network. Verify from a machine outside the host network with a port scan, and confirm that administrative endpoints are not reachable from user networks.
Confirm SSRF proxy blocks private ranges
Workflow HTTP nodes and tools can send requests from the API container, which makes internal services and cloud metadata endpoints reachable unless outbound traffic is filtered. The SSRF_PROXY settings route these requests through a proxy that blocks internal and private IP ranges. Verify that the proxy is in use, then test a workflow HTTP node pointed at an internal address and confirm the request fails.
Verify agent sandbox isolation
Dify 1.16.1 added agent sandbox network isolation through a Squid proxy, and the same release added sandboxed Jinja2 template rendering. Agent code runs in a sandbox, so upgrading to 1.16.1 or later is a precondition for this control. Confirm the sandbox container cannot reach your internal network or the database directly, and review which outbound destinations the proxy allows.
Enable token-based service authentication
The 1.16.1 release also added token-based API authentication between Dify services. Confirm that internal calls between the api, worker, plugin daemon and sandbox carry this authentication after you upgrade, and that the inter-service tokens are set from your secrets store rather than left at defaults. Check the service logs for rejected calls after the first test run.
Plan workspace encryption key storage
Workspace encryption keys protect stored model credentials and similar secrets, and the environment reference says they can be stored locally or in Azure Key Vault. Local storage keeps the key on the same host as the encrypted data, so a host compromise exposes both. Decide the storage location before the first model credential is saved, and confirm with your security team who holds the key material and how it is backed up.
Protect backups of the data stores
Backups hold the same secrets and user data as the live stack, and a backup of the database without the matching SECRET_KEY and encryption key material may not restore usable credentials. Store backups encrypted, restrict who can read them, and keep the key material in a separate system. Test a restore in a non-production environment and confirm the retention period with your data governance policy.
Questions teams ask before running Dify in production on Compose
Is self-hosted Dify free to run in production?
The Community edition is free to download and run, but it is limited to a single workspace. Per the Dify pricing page, the self-hosted Enterprise edition is custom priced and adds SSO, multiple workspaces, advanced security, a commercial license and professional support. The costs you carry on a Community deployment are infrastructure (compute, storage, backups, monitoring), model provider usage, and the staff time to operate the stack. Dify Cloud list prices, such as 590 US dollars per year for Professional, are subscription prices for the hosted service and are not a cost of running your own instance. Confirm your licensing position against the Dify pricing page and the license terms before you plan for more than one workspace.
What drives the cost of a production Dify deployment on Compose?
Cost follows the work in four areas: host capacity, managed or self-run dependencies, the engineering time to harden and back up the stack, and model usage. Host size depends on how many knowledge indexing jobs and workflow runs you expect at the same time. Dependencies such as external PostgreSQL, Redis, object storage and a vector database add either a managed service bill or internal operating effort. Model usage is billed by your model providers and often becomes the largest recurring line. One-time costs include the initial build, secret handling, TLS and the first restore test. Recurring costs include patching, monthly-ish upgrades, backup verification and on-call time. Ask any partner for a quote that lists each of these separately.
How long does it take to take Dify from test to production?
Duration depends on scope, not on a fixed template. The main variables are how many dependencies you move out of the bundled containers, whether you need TLS and identity integration at the edge, how many environments you run, and how much testing your security and compliance teams require. Each of those adds a decision and a verification step. Your internal change process and approval cycles often set the pace more than the technical work does. Engagements are normally fixed-scope, so the timeline is written into the agreed scope before work starts. Ask for a timeline that lists each milestone and what the client team must supply for it.
What does our team have to provide for a Compose deployment?
Plan on supplying a named technical owner, access to the target cloud account, data center or air-gapped network, and the DNS and certificate authority details. You also need decisions on the database, cache, object storage and vector store you will use, plus your model provider accounts and the secrets management system that will hold the environment values. Security and compliance staff should review the secret handling, outbound request policy and access model. A partner can build and document the stack, but your team still owns the operation after handover. Write these inputs into the scope so gaps are visible early.
Can our own team deploy and run Dify in production without a partner?
Yes, a capable platform team can deploy Dify with Docker Compose, provided it has Linux, Docker and PostgreSQL operations experience and time to test restores. The gaps usually appear in four places: replacing default secrets correctly (changing SECRET_KEY after deployment logs out all users), keeping the .env file in step with new variables, sizing the host for real indexing load, and designing backups that include both the database and file storage. Teams that lack one of these skills often bring in a partner for a fixed-scope review or build, then run the stack themselves. Be honest about how many people can cover on-call and upgrades.
How often does Dify release updates, and how should we plan upgrades?
Minor releases arrive roughly monthly. The GitHub releases page lists 1.16.0 on July 17, 2026, 1.17.0 on August 25, 2026 and 1.17.1 on September 10, 2026. Each upgrade should follow the guide for the target version, start with a backup, and check .env.example for new variables. Plan a staging run of every upgrade and a rollback path, since some major version jumps need more than new images. Set a cadence your team can keep, and treat security releases, such as the 1.16.1 agent sandbox and service authentication changes, as priority items.
When should we move Dify from Docker Compose to Kubernetes?
Move to Kubernetes when you need high availability across nodes, multiple workspaces under one control plane, SSO at enterprise scale, or operational patterns your platform team already runs. The Dify Enterprise resources checklist requires Kubernetes 1.24 or later, Helm 3.14 or later, PostgreSQL 14 or later, Redis 6 or later and a Qdrant vector database, and its production example uses six worker nodes with 8 CPUs and 32 GB of RAM each plus a three-node Qdrant cluster. Compose remains a reasonable choice for a single-workspace team with modest load and a clear backup plan. Confirm the Enterprise deployment path and its licensing with Dify before you commit to a design.
What should we confirm with Dify before going to production?
Confirm the supported deployment method for your target version, the edition and license terms that match your number of workspaces, and whether any feature you need, such as SSO, is available in your edition. Ask for the upgrade guide and any breaking changes for the versions you plan to run, and the list of environment variables that changed. Confirm how the metadata database, file storage and vector store options you choose are documented and supported. Keep these answers in writing so the design, the quote and the operating runbook refer to the same version and terms.
Limits to confirm in your environment
The Compose stack is a practical starting point, but several of its limits depend on your release, your traffic and your obligations. Each card below names one limit and the check that settles it before production sign-off.
Compose version against the target release
Dify's Docker Compose deployment requires Docker Compose 2.24.0 or later, and minor releases arrive roughly monthly. Confirm the Compose version on each host against the release you plan to run, then read the upgrade guide for that version. Check .env.example after every upgrade, because new variables are added between releases and a missing one can change behavior silently.
Host sizing for your concurrency
The documented minimum of 2 CPU cores and 4 GB of RAM is a test floor, not a production estimate. Knowledge indexing, workflow concurrency and the number of simultaneous chat users drive load on the api, worker and database containers. Measure peak CPU, memory and disk I/O during a representative indexing and chat test, and size the host from those numbers rather than the minimum.
Compose against your availability requirement
A single-host Compose stack has one host, one Redis container and one PostgreSQL container, so a host failure or container crash stops every workflow. Decide the recovery time and recovery point your business requires, then confirm that a restore from backup on a second host meets them. If you need high availability, the Dify deployment overview points to Dify Enterprise on Kubernetes, which is a separate quote and architecture.
Vector store and storage support in your version
The vector store defaults to Weaviate, and the metadata database and file storage have several supported options. Confirm in the environment variable reference which vector store, metadata database and storage type your target version supports, and whether it is the one you intend to operate. Ask the vendor or test on your version before choosing a backend, since support can differ between releases.
Community license against multi-tenant use
The Dify Open Source License prohibits operating the source code as a multi-tenant environment, where a tenant is one workspace, without written authorization. The Community edition is also limited to a single workspace. Confirm with your legal team whether your planned use, such as a shared platform serving several business units or customers, needs a commercial agreement before deployment.
Primary sources for the Compose deployment
Start with the official Docker Compose deployment guide, Deploy with Docker Compose, before you change anything in the stack. It is the document that defines the baseline your hardening work starts from: the minimum of 2 CPU cores and 4 GB of RAM, Docker Compose 2.24.0 or later, and the list of services the Compose file starts, including the api, worker, web, plugin daemon, PostgreSQL, Redis, Weaviate, Nginx, the code sandbox and the SSRF proxy. Read it against the Compose file version you actually pulled, because the service list is the checklist you will use to decide which containers stay bundled and which move to external services.
The environment variable reference is the second source to work from, at Dify environment variables. Every value you place in the .env file, including SECRET_KEY, the database and storage settings, the vector store choice and the SSRF_PROXY options, is defined there. Pay particular attention to the warning that changing SECRET_KEY after deployment logs out all users, because that affects when you can generate your real secret. Use the Dify deployment overview to confirm the scope of the community edition, and the Dify FAQs to check known installation and configuration problems before you open a support request.
The GitHub releases page at langgenius/dify releases is where version-specific upgrade guidance and security notes appear, such as the 1.16.1 notes on agent sandbox network isolation. Before you lock a version, read the release notes for every minor release between your current and target version, and confirm the upgrade guide for that target. The Compose documentation also asks you to back up before each upgrade and to compare your .env file with .env.example for new variables. Record the version you deployed, the date you checked these sources and any variables you changed, so the next upgrade starts from a documented state rather than memory.
How DeployOpen works on this
DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure. For Dify on Docker Compose, we start from a written scope covering secrets, sizing, service placement and the env file layout, then build and verify the production stack in your environment.
How we scope
- Confirm the target hosts, network zones, DNS names and TLS requirements before any configuration changes begin.
- Record which bundled services stay in Compose and which move to external PostgreSQL, Redis, object storage or a vector store.
- Agree the model endpoints, identity approach, backup targets and upgrade cadence that the written scope will cover.
How we build
- Replace every default secret, including SECRET_KEY, and store generated values in your approved secrets system.
- Structure the env file, compose overrides and host configuration so they can be versioned, reviewed and reproduced.
- Test the stack under representative workflow and knowledge indexing load, then record the sizing evidence behind the host profile.
How we hand over
- Deliver an operations runbook covering startup order, upgrade steps, environment variable changes and rollback.
- Document backup and restore procedures, including the database, file storage and secrets that must be captured together.
- Walk your operators through verification checks and the monitoring signals they should watch after go-live.
How we support
- Offer ongoing support, upgrade work and continuous testing as a retainer after the fixed-scope delivery ends.
- Plan each minor release against the upgrade guide and the .env.example changes, with a backup taken first.
- Review security advisories and release notes with your team so changes to sandboxing or authentication are tested before rollout.

