AI Deployment (Hetzner)
Deploying a Secure RAG Chatbot with Dify.ai on Coolify (Hetzner Cloud) for Ghost CMS
This guide provides step-by-step instructions to build and self-host a Retrieval-Augmented Generation (RAG) chatbot using Dify.ai on the Coolify PaaS, hosted on a Hetzner Cloud VPS. The chatbot will utilize models via OpenRouter AI and be securely embedded into a Ghost CMS website, ensuring it only functions on your specified domain.
Why Coolify & Hetzner for this Scenario? Coolify simplifies the deployment and management of Dockerized applications on your own server, offering a PaaS-like experience. Hetzner Cloud provides powerful and cost-effective VPS options. This combination allows for a self-hosted, budget-friendly Dify setup. Dify.ai itself is chosen for its robust built-in security features (domain whitelisting, CORS) critical for secure embedding.
Assumed Chatbot Purpose: Knowledge Base Q&A for a technical product.
Recommended Hetzner Cloud VPS Plan: For a production Dify setup including its databases and potentially a vector store, a Hetzner Cloud CPX31 (4 vCPU, 8 GB RAM, 160 GB NVMe) is a good starting point. This provides enough resources for Dify's API, Web, Worker services, PostgreSQL, Redis, and potentially a self-hosted Weaviate instance. Coolify itself will consume some resources. If your knowledge base is very large or you anticipate high traffic, consider the CPX41 (8 vCPU, 16 GB RAM). For initial testing or very small setups, a CPX21 (3 vCPU, 4GB RAM) might suffice, but monitor resources closely.
Prerequisites
Before you begin, ensure you have:
- Hetzner Cloud Account: An account with Hetzner Cloud.
- Domain Name: A domain name you own (e.g.,
your-coolify-server.com
) that you can point to your Hetzner VPS for Coolify and Dify services. You'll likely use subdomains for Dify (e.g.,dify-console.your-coolify-server.com
). - Ghost CMS Website: An operational Ghost CMS website (e.g.,
your-ghost-domain.com
). - OpenRouter AI Account: An account with OpenRouter AI and an API key.
- Basic Linux & Docker Knowledge: Familiarity with basic Linux commands (for Coolify setup) and Docker concepts is helpful.
Part 1: Setting up Hetzner Cloud VPS & Coolify
1.1. Create a Hetzner Cloud Server
- Log in to your Hetzner Cloud Console.
- Click
Add Server
. - Choose a location.
- Select Ubuntu 22.04 (or a newer LTS version Coolify supports) as the image.
- Select a type (e.g., CPX31 as recommended above).
- Add your SSH key for access.
- Give your server a name (e.g.,
coolify-dify-server
). - Click
Create & Buy now
. - Once the server is running, note down its Public IP Address.
1.2. Point Your Domain to the Server
Go to your DNS provider and create an A record for your chosen domain (e.g., your-coolify-server.com
) and wildcard CNAME/A records for subdomains (e.g., *.your-coolify-server.com
) pointing to the Hetzner server's Public IP Address. This allows Coolify to manage subdomains for its services.
1.3. Install Coolify
-
SSH into your newly created Hetzner server:
ssh root@YOUR_SERVER_IP
-
Install Coolify using the official installation script (check coolify.io for the latest command):
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
-
Follow the on-screen prompts. Coolify will install Docker and its own components.
-
Once installation is complete, access the Coolify dashboard by navigating to your server's IP address or
http://your-coolify-server.com:3000
(or the port it indicates). You'll be prompted to create an admin account.
1.4. Configure Coolify Server
- Log in to Coolify.
- Navigate to
Servers
in the sidebar. You should see your local server (the one Coolify is installed on). - Click on your server, go to the
Configuration
tab. - Set the
FQDN (Domain)
to your primary domain for Coolify services (e.g.,your-coolify-server.com
). Coolify will use this to generate URLs for applications. Coolify will automatically try to obtain SSL certificates using Let's Encrypt.
1.5. Provision Databases via Coolify
Dify requires PostgreSQL and Redis. Coolify can manage these for you.
- In Coolify, go to
Databases
->Create New
. - PostgreSQL:
- Select
PostgreSQL
. - Give it a name (e.g.,
dify-postgres
). - Choose the server (your Hetzner VPS).
- Deploy.
- Once deployed, click on the
dify-postgres
service. Note down the Connection URL or individual connection parameters (Host will be the service name, e.g.,dify-postgres
).
- Select
- Redis:
- Select
Redis
. - Give it a name (e.g.,
dify-redis
). - Choose the server.
- Deploy.
- Once deployed, click on
dify-redis
. Note down the Connection URL or parameters. The host will bedify-redis
.
- Select
Part 2: Configuring Dify.ai Environment Variables
Dify.ai is configured via environment variables. Gather these before setting them up in Coolify for each Dify service.
Reference: Dify Self-Hosted Environment Variables
2.1. Core Dify Configuration
EDITION
:SELF_HOSTED
CONSOLE_URL
:https://dify-console.your-coolify-server.com
(Replace with the FQDN Coolify will assign to your Dify Web service).APP_URL
:https://dify-app.your-coolify-server.com
(Replace with the FQDN for Dify's app/API endpoint).API_URL
:https://dify-app.your-coolify-server.com/v1
(TypicallyAPP_URL
+/v1
).
2.2. Database & Redis Connection (from Coolify in Part 1.5)
DB_USERNAME
: (from Coolify PostgreSQL service, oftenpostgres
)DB_PASSWORD
: (from Coolify PostgreSQL service)DB_HOST
:dify-postgres
(The Coolify service name for PostgreSQL)DB_PORT
:5432
DB_DATABASE
: (from Coolify PostgreSQL service, oftenpostgres
ordefault
)REDIS_HOST
:dify-redis
(The Coolify service name for Redis)REDIS_PORT
:6379
REDIS_PASSWORD
: (from Coolify Redis service, might be empty if not set)REDIS_DB
:0
2.3. File Storage
For simplicity, we'll use local storage managed by Coolify's persistent volumes.
FILES_STORAGE_TYPE
:local
- Important: Coolify will handle creating persistent volumes for the Dify API service. The default storage path within the container is
/app/storage
. You'll map a Coolify volume to this path in Part 3.1.
- Important: Coolify will handle creating persistent volumes for the Dify API service. The default storage path within the container is
- If using S3: Set to
s3
and configureS3_ENDPOINT
,S3_BUCKET_NAME
,S3_ACCESS_KEY
,S3_SECRET_KEY
,S3_REGION
.
2.4. Vector Store
We'll deploy Weaviate as a separate service via Coolify.
VECTOR_STORE
:weaviate
WEAVIATE_ENDPOINT
:http://dify-weaviate:8080
(Assuming your Weaviate service in Coolify is nameddify-weaviate
and listens on port 8080. Coolify uses internal Docker networking).WEAVIATE_API_KEY
: (If Weaviate authentication is enabled and you've configured one)
2.5. Critical Security Configuration (CORS & Allowed Domains)
CONSOLE_CORS_ALLOW_ORIGINS
:https://dify-console.your-coolify-server.com
(Allows your Dify admin console to talk to the Dify API).WEB_API_CORS_ALLOW_ORIGINS
:https://your-ghost-domain.com
(Crucial! Restricts API access to your Ghost domain for the embedded chatbot).
2.6. OpenRouter AI Integration
OPENAI_API_KEY
:YOUR_OPENROUTER_API_KEY
OPENAI_API_BASE
:https://openrouter.ai/api/v1
2.7. Encryption & Secret Keys
Generate strong random strings (e.g., using openssl rand -hex 32
on a terminal).
ENCRYPTION_KEY
: (e.g., a 64-character hex string)SECRET_KEY
: (e.g., a 64-character hex string)
Part 3: Deploying Dify.ai Services on Coolify
Deploy Dify's API, Web, Worker, and Weaviate services. Use specific version tags for Dify images for stability.
Reference Docker Images: (Check Dify's Docker Hub for latest stable tags, e.g., :0.6.1
. Replace <specific_version>
with the actual tag.)
- API:
langgenius/dify-api:<specific_version>
- Web:
langgenius/dify-web:<specific_version>
- Worker:
langgenius/dify-worker:<specific_version>
- Weaviate:
semitechnologies/weaviate:<specific_version>
(e.g.,1.23.7
)
For each service:
- In Coolify, go to
Applications
->Create New
. - Choose
Public Docker Image
. - Select your Hetzner server as the
Destination
.
3.1. Deploy Dify API Service
- Name:
dify-api
- Image:
langgenius/dify-api:0.6.1
(replace with desired stable version) - Configuration Tab:
- FQDN(s): Set your
APP_URL
domain (e.g.,https://dify-app.your-coolify-server.com
). Coolify will manage SSL. - Port(s):
5001
(Dify API's default port).
- FQDN(s): Set your
- Environment Variables Tab: Add all relevant variables from Part 2.
- Storage Tab (Crucial for
FILES_STORAGE_TYPE: local
):- Add a new persistent volume mapping.
- Path in Container:
/app/storage
(Dify's default local storage path) - Path on Host: Coolify will auto-generate a path (e.g.,
/data/coolify/storages/dify-api-app-storage
).
- Health Check: Path:
/healthz
, Port:5001
. - Deploy.
3.2. Deploy Dify Web (Console) Service
- Name:
dify-web
- Image:
langgenius/dify-web:0.6.1
(replace with desired stable version) - Configuration Tab:
- FQDN(s): Set your
CONSOLE_URL
domain (e.g.,https://dify-console.your-coolify-server.com
). - Port(s):
3000
(Dify Web's default port).
- FQDN(s): Set your
- Environment Variables Tab: Add all relevant variables from Part 2. Ensure
API_URL
andCONSOLE_URL
are correct. - Health Check: Path:
/
, Port:3000
. - Deploy.
3.3. Deploy Dify Worker Service
- Name:
dify-worker
- Image:
langgenius/dify-worker:0.6.1
(replace with desired stable version) - Configuration Tab:
- FQDN(s): Not required. This service doesn't need public exposure.
- Port(s): Not required for public exposure.
- Environment Variables Tab: Add all relevant variables from Part 2.
- Deploy. (Health check typically not HTTP based for workers; monitor logs).
3.4. Deploy Weaviate Service (Vector Database)
- Name:
dify-weaviate
- Image:
semitechnologies/weaviate:1.23.7
(or latest stable Weaviate version) - Configuration Tab:
- FQDN(s): Not required for public exposure if only Dify accesses it internally.
- Port(s):
8080
(Weaviate's default HTTP port).
- Environment Variables Tab:
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED
:true
(For simplicity. For production, consider disabling anonymous access and configuring API key authentication if Weaviate and Dify support it in your desired setup.)PERSISTENCE_DATA_PATH
:/var/lib/weaviate
(Default, will be mapped to a volume)DEFAULT_VECTORIZER_MODULE
:none
(Dify handles embeddings, so Weaviate shouldn't vectorize by default)ENABLE_MODULES
:'text2vec-transformers'
(This is often a safe default module to enable for general compatibility. If Dify manages all embeddings externally and you encounter issues or want minimal Weaviate modules, consult Dify/Weaviate documentation. For some setups, this can be empty ifDEFAULT_VECTORIZER_MODULE
isnone
.)CLUSTER_HOSTNAME
:node1
(Default)
- Storage Tab:
- Add a persistent volume mapping for Weaviate data.
- Path in Container:
/var/lib/weaviate
- Deploy. Ensure your Dify API service's environment variable
WEAVIATE_ENDPOINT
is set tohttp://dify-weaviate:8080
.
Part 4: Initial Dify.ai Setup & LLM Configuration
4.1. Accessing Dify Console & Initial Setup
- Wait for all Coolify services (Dify API, Dify Web, Dify Worker, Weaviate, PostgreSQL, Redis) to deploy successfully. Check their logs in Coolify to ensure they are running without errors.
- Open your Dify Web (Console) URL (the
CONSOLE_URL
you configured, e.g.,https://dify-console.your-coolify-server.com
) in your browser. - You should see the Dify setup screen. Create your administrator account by providing an email, username, and password.
4.2. Configuring OpenRouter as LLM Provider
- Log in to your Dify console using the administrator account you just created.
- Navigate to
Settings
(usually represented by a gear icon, often found in the bottom-left or top-right of the Dify interface). - In the Settings menu, find and click on the
Model Providers
section. - Dify should attempt to automatically detect and configure an "OpenAI" provider using the
OPENAI_API_KEY
andOPENAI_API_BASE
environment variables you set for OpenRouter during the Dify API service deployment. - Verify this configuration. If it's not present, or if you prefer a specifically named provider for OpenRouter:
- Click
Add Provider
(or a similar button like+ Create Provider
). - Provider Name: Enter a descriptive name, e.g.,
OpenRouterAI
. - Model Type: Select
Text Generation
orChat
(orLLM
), depending on the models you intend to use from OpenRouter.Chat
is common. - Provider: From the dropdown list of provider types, choose
OpenAI
(as OpenRouter exposes an OpenAI-compatible API). - API Key: Enter your
YOUR_OPENROUTER_API_KEY
. If the environment variables were correctly picked up by Dify, this might already be pre-filled or inherited. - API Base URL: Enter
https://openrouter.ai/api/v1
. This might also be pre-filled if env vars are detected.
- Click
- Test the connection if Dify offers a "Test" or "Validate" button for the provider settings.
- Once saved, you can select specific models hosted on OpenRouter (e.g.,
openai/gpt-4-turbo-preview
,mistralai/mistral-7b-instruct
) when building your Dify applications. You might need to add these models to your "System-Level Model List" or "Available Models" within Dify's model provider settings if they are not automatically populated after setting up the provider.
Part 5: Building Your RAG Chatbot in Dify.ai
5.1. Creating the Chatbot Application
- In the Dify console, navigate to the
Studio
section (this is typically where you create and manage your AI applications). - Click
Create App
(or a similar button like+ New App
). - Choose an application type. For a RAG Q&A bot, the
Chatbot
type is suitable. Other options might include "Agent" or "Workflow," butChatbot
is standard for this use case. - Give your application a distinctive name (e.g., "Product Documentation Bot"), a brief description, and optionally, choose an icon. Click
Create
.
5.2. Setting up the Knowledge Base (RAG)
- After creating the app, or from the Dify main navigation, navigate to the
Knowledge
section (sometimes called "Datasets" or "Knowledge Bases"). - Click
Create Knowledge
(or+ New Knowledge Base
). - Name your knowledge base (e.g., "Product Docs KB").
- Upload Documents:
- Click
Upload Documents
or drag and drop your source files (e.g., PDFs, TXT, Markdown files containing your technical product information). - Dify will upload these files (using the Dify API service and its configured storage) and prepare them for processing.
- If using
FILES_STORAGE_TYPE: local
, ensure the Dify API service on Coolify has the/app/storage
volume correctly mapped and persistent (as configured in Part 3.1).
- Click
- Configure Indexing & Chunking:
- After uploading, you'll typically configure how Dify processes these documents.
- Set the
Indexing mode
(e.g.,High Quality
for better retrieval accuracy but slower processing, orEconomic
for faster processing). - Adjust the
Chunking strategy
(e.g., "by sentence," "fixed-size"). - Set
Segment length
(max characters/tokens per chunk) andSegment Overlap
(characters/tokens shared between adjacent chunks) as appropriate for your content type and density.
- Start the processing/indexing. Dify will then chunk the documents, generate embeddings (using a model configured in Dify or a default one), and store them in your vector database (Weaviate). This may take some time depending on the size of your documents. Monitor the progress in the Dify UI.
- Once the knowledge base is successfully processed and indexed ("Available" or "Ready" status), navigate back to your Chatbot App settings in the
Studio
section. - In your app's configuration, find a section like
Contexts
,Retrieval Configuration
, orKnowledge Integration
. - Select and add your newly created Knowledge Base ("Product Docs KB") to this application. This links the RAG data source to your chatbot, enabling it to retrieve relevant information.
5.3. Prompt Engineering & Model Selection
-
Within your Chatbot App settings in Dify's
Studio
, navigate to thePrompt Eng.
(Prompt Engineering),Instructions
, orOrchestration
section. -
System Prompt: Refine the system prompt (or instructions) that guides the LLM's behavior. This is crucial for RAG. Example:
You are an AI assistant for [Your Product Name]. Your primary goal is to answer user questions based SOLELY on the provided context documents.
If the answer is found in the context, provide it clearly and concisely.
If the answer is not in the provided context, you MUST state: "I do not have enough information from the provided documents to answer that question."
Do not use any external knowledge or make assumptions beyond the context.
Be polite and helpful. -
Model and Parameters:
- Find the section for
Model and Parameters
orLLM Configuration
. - Select the LLM you want to use. This should list models available through your configured OpenRouter provider (e.g.,
openai/gpt-4-turbo-preview
,mistralai/mistral-7b-instruct
). - Adjust parameters like
temperature
(e.g., 0.2 for factual Q&A, higher for more creative responses) andmax_tokens
(maximum length of the generated response) as needed.
- Find the section for
-
Test: Use Dify's built-in preview, debug, or test chat interface to interact with your chatbot. Ask questions that should be answerable from your knowledge base and some that should not, to verify its behavior according to your prompt. Iterate on the prompt and model settings for optimal performance.
Part 6: Embedding the Chatbot in Ghost CMS with Security
6.1. Configuring Embed Security in Dify
- In your Chatbot App settings in Dify's
Studio
, navigate to thePublish
orEmbed
section. - Look for a setting labeled "Allowed Domains," "Permitted Domains," or similar that controls where the embedded chatbot (widget or iframe) can be initialized and communicate from.
- Add your Ghost CMS domain here:
https://your-ghost-domain.com
. Addhttp://localhost:port
if you test Ghost locally.- This is Dify's application-level security control. It works in conjunction with the
WEB_API_CORS_ALLOW_ORIGINS
environment variable (server-level CORS) you set for the Dify API service. Both are important for security.
- This is Dify's application-level security control. It works in conjunction with the
6.2. Getting the Embed Code
Dify will provide an embed code snippet in the Publish
or Embed
section. This is typically an <iframe>
tag or a <script>
tag. Copy this code.
Example iframe (the URL will be based on your APP_URL
):
<iframe
src="https://dify-app.your-coolify-server.com/chatbot/YOUR_APP_ID"
style="width: 100%; height: 100%; min-height: 700px; border: none;"
frameborder="0"
allow="microphone">
</iframe>
Example script tag (the src
URL and data-app-id
will be based on your APP_URL
and specific App ID):
<script
src="https://dify-app.your-coolify-server.com/embed.min.js"
id="YOUR_DIFY_APP_ID_FROM_EMBED_SETTINGS"
data-app-id="YOUR_DIFY_APP_ID_FROM_EMBED_SETTINGS">
</script>
(Replace YOUR_APP_ID_FROM_EMBED_SETTINGS
, YOUR_DIFY_APP_ID_FROM_EMBED_SETTINGS
, and domains with the actual values provided by Dify in its embed section.)
6.3. Adding the Chatbot to Ghost CMS
- Log in to your Ghost Admin panel (e.g.,
https://your-ghost-domain.com/ghost
). - Go to
Posts
orPages
and open the editor for the specific post or page where you want to embed the chatbot. - In the Ghost editor, click the
+
button on a new line to add a new card. - Select the
HTML
card from the list of available cards. - Paste the embed code (iframe or script) copied from Dify into the HTML card.
- Save or Publish/Update your Ghost post or page.
6.4. (Recommended) Implementing Content Security Policy (CSP) in Ghost
For an additional layer of security, configure Content Security Policy (CSP) headers on your Ghost site to restrict where iframes or scripts can be loaded from, and what external connections they can make. This is a browser-level security measure.
- How to set CSP in Ghost: This depends heavily on your Ghost hosting setup:
- Reverse Proxy: If Ghost is behind a reverse proxy you manage (e.g., Nginx, Caddy, or even if you have access to Coolify's Traefik configuration for your Ghost site if hosted there), configure the CSP header in the proxy's site configuration. This is the most robust method.
- Ghost Code Injection: Ghost Admin has a
Settings
->Code Injection
section. You can add CSP via a<meta http-equiv="Content-Security-Policy" content="...">
tag in the "Site Header" section. While less secure than HTTP headers (as meta tags can be overridden more easily), it's better than no CSP. - Theme Modification: You could edit your Ghost theme's
default.hbs
file to include the meta tag if code injection isn't sufficient. - Hosting Provider: Some specific Ghost hosting providers might offer dedicated interfaces for adding custom HTTP headers.
- CSP Directives:
- For iframe embeds:
frame-src
- For script embeds:
script-src
- You will likely also need
connect-src
to allow the embedded Dify script/iframe to communicate with your Dify API (https://dify-app.your-coolify-server.com
). - Example CSP (adjust for your Dify App URL from
APP_URL
):Content-Security-Policy: frame-src 'self' https://dify-app.your-coolify-server.com; script-src 'self' 'unsafe-inline' https://dify-app.your-coolify-server.com; connect-src 'self' https://dify-app.your-coolify-server.com wss://dify-app.your-coolify-server.com;
(Note:'unsafe-inline'
might be needed forscript-src
if Dify's embed script uses inline styles/scripts, which is common for widgets. Try to avoid it if possible by using nonce or hash-based CSP if Dify's embed supports it.wss://
for WebSocket connections if Dify uses them. Always test CSP policies thoroughly, as overly restrictive policies can break your site or the chatbot.) (Adjust'self'
and other sources like CDNs for fonts/styles your Ghost site uses. Start with a less restrictive policy and tighten it.)
- For iframe embeds:
Part 7: Verification and Testing
7.1. Test on Allowed Domain (Ghost Site)
- Open the Ghost page where you embedded the chatbot in a web browser.
- Expected: The Dify chatbot should load correctly within the iframe or as a widget. You should be able to interact with it, ask questions, and receive responses based on your knowledge base.
7.2. Test on Disallowed Domain
-
Create a simple local HTML file (e.g.,
test_disallowed.html
) on your computer:<!DOCTYPE html>
<html>
<head><title>Test Embed - Disallowed</title></head>
<body>
<h1>Chatbot Test (Disallowed Domain)</h1>
<!-- Paste the SAME Dify embed code from Part 6.2 here -->
</body>
</html> -
Open this
test_disallowed.html
file directly in your browser (it will be served from afile://
URL, which is a different origin than your whitelisted Ghost domain). -
Alternatively, use an online HTML sandbox tool (like JSFiddle, CodePen, or Glitch) and paste the embed code. Ensure the sandbox domain is not whitelisted in Dify's settings.
-
Expected:
- The chatbot should not load or function correctly.
- You might see a blank iframe, an error message from Dify within the iframe, or the widget might fail to initialize.
- This test confirms that Dify's "Allowed Domains" feature and your
WEB_API_CORS_ALLOW_ORIGINS
server-side setting are working to prevent unauthorized embedding and API usage.
7.3. Check Browser Console & Network Requests
- On both the allowed (Ghost site) and disallowed test pages, open your browser's Developer Tools (usually by pressing F12 or right-clicking and selecting "Inspect").
- Console Tab:
- On the allowed domain (Ghost site), check for any errors. Ideally, there should be none related to the chatbot.
- On the disallowed domain, you should expect to see errors. These might include:
- CORS (Cross-Origin Resource Sharing) errors if the browser blocks requests to the Dify API.
- JavaScript errors from the Dify embed script if it detects it's on an unauthorized domain.
- Messages from Dify indicating the domain is not permitted.
- Network Tab:
- Filter requests to see those made by the iframe/script to your Dify API domain (e.g.,
dify-app.your-coolify-server.com
). - On the allowed domain, these requests should complete successfully (e.g., HTTP status 200 OK).
- On the disallowed domain, requests might be blocked by the browser due to CORS (showing as errors in the Network tab), or the Dify API might return an error status (e.g., 403 Forbidden) if Dify's server-side checks also deny the request based on the
Origin
header.
- Filter requests to see those made by the iframe/script to your Dify API domain (e.g.,
Part 8: Maintenance and Operations (Coolify/Hetzner Context)
8.1. Updating Dify.ai
- Periodically check the Dify GitHub repository or Docker Hub (hub.docker.com/u/langgenius) for new image versions/tags. It's best to use specific version tags, not
:latest
, for production. - Read Dify's release notes carefully for any breaking changes, migration steps, or updates to environment variables before updating.
- In Coolify, for each Dify service (API, Web, Worker):
- Navigate to the service in your Coolify dashboard.
- Go to its
Configuration
tab (or where the Docker image is specified). - Update the
Image
field with the new specific version tag (e.g.,langgenius/dify-api:0.6.2
). - Click
Deploy
(orSave & Deploy
). Coolify will pull the new image and restart the service. - Monitor logs during and after deployment.
8.2. Backups
- Coolify Managed Databases (PostgreSQL, Redis):
- Coolify has built-in backup capabilities for services it manages.
- Go to your
dify-postgres
anddify-redis
database services in Coolify. - Navigate to their
Backups
tab. - Configure scheduled backups. Coolify often supports various destinations like local storage (on the server), S3-compatible services, etc. Choose a reliable off-server backup location if possible.
- Dify Application Configuration: This is stored in the PostgreSQL database, so it's covered by your PostgreSQL backups.
- Uploaded Files (Knowledge Base - if
FILES_STORAGE_TYPE: local
):- The
/app/storage
volume for the Dify API service is managed by Coolify, which creates it on the Hetzner server's filesystem (typically under/data/coolify/storages/...
or a similar path). - Check if Coolify offers direct backup options for application persistent volumes.
- If not directly in Coolify, you are responsible for backing up this host path. This can be done via:
- Hetzner Server Snapshots: Configure regular snapshots of your entire Hetzner VPS. This is a good disaster recovery option but might not be ideal for granular file recovery.
- Manual/Scripted Backups: Create scripts (e.g., using
rsync
ortar
) to copy the volume's host path to another location (e.g., another server, S3 bucket).
- Using
FILES_STORAGE_TYPE: s3
(as mentioned in Part 2.3) offloads file storage to S3, which has its own robust backup and versioning features, simplifying this aspect.
- The
- Coolify Configuration: Back up Coolify's own configuration data if possible (refer to Coolify documentation for how to do this).
8.3. Monitoring Resources
- Coolify Dashboard: Coolify typically provides basic resource monitoring (CPU, memory, disk usage) for your deployed applications and the server itself.
- Hetzner Cloud Console: The Hetzner dashboard shows graphs for CPU, Network traffic, and Disk I/O for your VPS.
- Server-level Monitoring: For more detailed insights, SSH into your Hetzner VPS and use tools like:
htop
ortop
(real-time process monitoring)df -h
(disk space)free -m
(memory usage)- Consider installing more advanced monitoring tools like
netdata
(real-time performance monitoring with a web UI) or setting up a Prometheus/Grafana stack if you need comprehensive long-term monitoring and alerting.
- Service Logs: Regularly check the logs for all Dify services (API, Web, Worker), Weaviate, PostgreSQL, and Redis within the Coolify interface for errors or performance warnings.
Troubleshooting & Further Considerations (Coolify/Hetzner)
- CORS Issues: Meticulously double-check your
CONSOLE_CORS_ALLOW_ORIGINS
(for Dify console access to API) andWEB_API_CORS_ALLOW_ORIGINS
(for Ghost site access to API) environment variables in the Dify API service settings within Coolify. Ensure no typos, correct schemes (https://
), and exact domain names. - Chatbot Not Loading/Functioning:
- Check Logs: Examine logs for all relevant services in Coolify: Dify API, Dify Web, Dify Worker, Weaviate, PostgreSQL, Redis. Look for startup errors, connection issues, or runtime exceptions.
- Coolify Proxy Logs: Coolify uses a reverse proxy (often Traefik). If you suspect SSL or domain routing issues, check the logs for the proxy container (usually named something like
coolify-proxy
or accessible via Coolify's server logs). - FQDNs & DNS: Verify that the FQDNs set in Coolify for Dify API and Web services are correct and that DNS records for these domains have propagated and point to your Hetzner server's IP.
- Internal Networking: Ensure Dify services can reach PostgreSQL, Redis, and Weaviate using their Coolify service names (e.g.,
dify-postgres
,dify-weaviate
). Docker's internal networking managed by Coolify should handle this.
- File Upload Issues / Data Loss (Local Storage): If
FILES_STORAGE_TYPE: local
is used, ensure the persistent volume mapping for/app/storage
on the Dify API service is correctly configured in Coolify, is writable by the Dify container user, and is indeed persistent across deployments/restarts. - Resource Limits: If Dify is slow, unresponsive, or services are crashing (e.g., OOMKilled), you might be hitting resource limits. Check CPU, memory, and disk usage in both Hetzner Console and Coolify. Consider upgrading your Hetzner VPS plan if necessary.
- Hetzner Firewall: If you have configured a Hetzner Cloud Firewall for your server, ensure it allows inbound traffic on necessary ports:
- Port
80
(HTTP, for Let's Encrypt SSL renewal and HTTP-to-HTTPS redirects) - Port
443
(HTTPS, for all Coolify-managed web services like Dify Console and Dify App) - Your SSH port.
- Port
- Coolify Updates: Keep your Coolify instance itself updated to the latest stable version for new features, bug fixes, and security patches. Follow Coolify's official update procedure.
- Dify Versioning: As emphasized, stick to specific, stable versions of Dify images rather than
:latest
to avoid unexpected breaking changes from auto-updates. - External Vector Database: For larger-scale deployments, increased reliability, or to simplify management, consider using a managed external vector database service (e.g., Pinecone, Weaviate Cloud Service, Qdrant Cloud) instead of self-hosting Weaviate on the same VPS. You would then configure Dify's
WEAVIATE_ENDPOINT
and any necessary API keys to point to the managed service. - Custom Domains & SSL: Coolify should handle SSL certificates (e.g., via Let's Encrypt) for the FQDNs you configure for your Dify services. Ensure this is working correctly.
Conclusion
By following this comprehensive guide, you should have a self-hosted Dify.ai RAG chatbot running securely on your own Hetzner Cloud VPS, with deployment and service management streamlined by Coolify. This setup provides significant control, potential cost savings for long-term hosting, and leverages Dify's security features for safe embedding on your specified Ghost CMS domain. Always prioritize security best practices and keep your software components updated.
References and Further Reading
- Dify.ai Documentation: docs.dify.ai
- Self-Hosting: Dify Self-Hosted Installation
- Environment Variables: Environment Variables & CORS
- Embedding: Embedding in Websites
- Coolify Documentation: coolify.io/docs
- Hetzner Cloud Documentation: docs.hetzner.com
- OpenRouter AI: openrouter.ai
- Ghost CMS: ghost.org
- Weaviate Documentation: weaviate.io/developers/weaviate
- Content Security Policy (CSP): MDN Web Docs - CSP