Open Project #4123
Replies: 6 comments 5 replies
-
|
I would be super grateful to have an OpenProject template. Has anyone got it working? |
Beta Was this translation helpful? Give feedback.
-
|
I managed to get it working, but I can't verify if this is safe and secure because it involves setting HSTS config to false. networks:
frontend: null
backend: null
volumes:
opdata: null
x-op-restart-policy:
restart: unless-stopped
x-op-image:
image: 'openproject/openproject:${TAG:-16-slim}'
x-op-app:
image: 'openproject/openproject:${TAG:-16-slim}'
restart: unless-stopped
environment:
OPENPROJECT_HTTPS: '${OPENPROJECT_HTTPS:-true}'
OPENPROJECT_HOST__NAME: '${OPENPROJECT_HOST__NAME:-localhost:8080}'
OPENPROJECT_HSTS: '${OPENPROJECT_HSTS:-true}'
RAILS_CACHE_STORE: memcache
OPENPROJECT_CACHE__MEMCACHE__SERVER: 'cache:11211'
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}'
DATABASE_URL: '${DATABASE_URL:-postgres://postgres:p4ssw0rd@db/openproject?pool=20&encoding=unicode&reconnect=true}'
RAILS_MIN_THREADS: '${RAILS_MIN_THREADS:-4}'
RAILS_MAX_THREADS: '${RAILS_MAX_THREADS:-16}'
IMAP_ENABLED: '${IMAP_ENABLED:-false}'
volumes:
- 'openproject:/var/openproject/assets'
services:
cache:
image: memcached
restart: unless-stopped
networks:
- backend
web:
image: 'openproject/openproject:${TAG:-16-slim}'
restart: unless-stopped
environment:
OPENPROJECT_HTTPS: '${OPENPROJECT_HTTPS:-true}'
OPENPROJECT_HOST__NAME: '${OPENPROJECT_HOST__NAME:-localhost:8080}'
OPENPROJECT_HSTS: '${OPENPROJECT_HSTS:-true}'
RAILS_CACHE_STORE: memcache
OPENPROJECT_CACHE__MEMCACHE__SERVER: 'cache:11211'
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}'
DATABASE_URL: '${DATABASE_URL:-postgres://postgres:p4ssw0rd@db/openproject?pool=20&encoding=unicode&reconnect=true}'
RAILS_MIN_THREADS: '${RAILS_MIN_THREADS:-4}'
RAILS_MAX_THREADS: '${RAILS_MAX_THREADS:-16}'
IMAP_ENABLED: '${IMAP_ENABLED:-false}'
volumes:
- 'openproject:/var/openproject/assets'
command: ./docker/prod/web
networks:
- frontend
- backend
depends_on:
- cache
- seeder
labels:
- autoheal=true
healthcheck:
test:
- CMD
- curl
- '-f'
- 'http://localhost:8080${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}/health_checks/default'
interval: 10s
timeout: 3s
retries: 3
start_period: 30s
autoheal:
image: 'willfarrell/autoheal:1.2.0'
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
environment:
AUTOHEAL_CONTAINER_LABEL: autoheal
AUTOHEAL_START_PERIOD: 600
AUTOHEAL_INTERVAL: 30
worker:
image: 'openproject/openproject:${TAG:-16-slim}'
restart: unless-stopped
environment:
OPENPROJECT_HTTPS: '${OPENPROJECT_HTTPS:-true}'
OPENPROJECT_HOST__NAME: '${OPENPROJECT_HOST__NAME:-localhost:8080}'
OPENPROJECT_HSTS: '${OPENPROJECT_HSTS:-true}'
RAILS_CACHE_STORE: memcache
OPENPROJECT_CACHE__MEMCACHE__SERVER: 'cache:11211'
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}'
DATABASE_URL: '${DATABASE_URL:-postgres://postgres:p4ssw0rd@db/openproject?pool=20&encoding=unicode&reconnect=true}'
RAILS_MIN_THREADS: '${RAILS_MIN_THREADS:-4}'
RAILS_MAX_THREADS: '${RAILS_MAX_THREADS:-16}'
IMAP_ENABLED: '${IMAP_ENABLED:-false}'
volumes:
- 'openproject:/var/openproject/assets'
command: ./docker/prod/worker
networks:
- backend
depends_on:
- cache
- seeder
cron:
image: 'openproject/openproject:${TAG:-16-slim}'
restart: unless-stopped
environment:
OPENPROJECT_HTTPS: '${OPENPROJECT_HTTPS:-true}'
OPENPROJECT_HOST__NAME: '${OPENPROJECT_HOST__NAME:-localhost:8080}'
OPENPROJECT_HSTS: '${OPENPROJECT_HSTS:-true}'
RAILS_CACHE_STORE: memcache
OPENPROJECT_CACHE__MEMCACHE__SERVER: 'cache:11211'
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}'
DATABASE_URL: '${DATABASE_URL:-postgres://postgres:p4ssw0rd@db/openproject?pool=20&encoding=unicode&reconnect=true}'
RAILS_MIN_THREADS: '${RAILS_MIN_THREADS:-4}'
RAILS_MAX_THREADS: '${RAILS_MAX_THREADS:-16}'
IMAP_ENABLED: '${IMAP_ENABLED:-false}'
volumes:
- 'openproject:/var/openproject/assets'
command: ./docker/prod/cron
networks:
- backend
depends_on:
- cache
- seeder
seeder:
image: 'openproject/openproject:${TAG:-16-slim}'
restart: on-failure
environment:
OPENPROJECT_HTTPS: '${OPENPROJECT_HTTPS:-true}'
OPENPROJECT_HOST__NAME: '${OPENPROJECT_HOST__NAME:-localhost:8080}'
OPENPROJECT_HSTS: '${OPENPROJECT_HSTS:-true}'
RAILS_CACHE_STORE: memcache
OPENPROJECT_CACHE__MEMCACHE__SERVER: 'cache:11211'
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}'
DATABASE_URL: '${DATABASE_URL:-postgres://postgres:p4ssw0rd@db/openproject?pool=20&encoding=unicode&reconnect=true}'
RAILS_MIN_THREADS: '${RAILS_MIN_THREADS:-4}'
RAILS_MAX_THREADS: '${RAILS_MAX_THREADS:-16}'
IMAP_ENABLED: '${IMAP_ENABLED:-false}'
volumes:
- 'openproject:/var/openproject/assets'
command: ./docker/prod/seeder
networks:
- backendI removed the DB because I wanted to use an external one, but you're free to leave it in if you prefer. For env vars I only used these, I configured the rest (SMTP) in the dashboard: |
Beta Was this translation helpful? Give feedback.
-
|
I've just wasted 3 hours trying to get Open Project to load as much as a login page... I'm so glad I decided to give Coolify a go before trying to run a single deployment that isn't in the recipe book (2 / 3 deployments I really should get working) |
Beta Was this translation helpful? Give feedback.
-
|
holy cow!! after 6 hours of engineering I could make it happen: Open Project is up and running in Coolify. here is how you can also achieve it: OpenProject Deployment on Coolify - Complete Guide
After spending considerable time troubleshooting OpenProject deployment on Coolify, I've documented a working configuration that addresses all the common pitfalls. This guide will help you deploy OpenProject successfully in under 30 minutes. Table of Contents
Prerequisites
Key Insights (Read First!)Before you start, understand these critical points that differ from standard Docker Compose deployments: 1. Do NOT Define NetworksCoolify automatically creates an isolated network for each service stack. Do not define
2. YAML Anchors Create Phantom ServicesThe official OpenProject docker-compose.yml uses YAML anchors ( 3. Domain Must Point to the "web" ServiceThe domain configuration must be set on the web service, not on any phantom service created by YAML anchors. 4. Disable "Connect To Predefined Network"In Coolify's Service Stack settings, keep "Connect To Predefined Network" disabled for isolated deployments. 5. The Seeder Service is Supposed to ExitThe 6. No Health Check for Memcached AlpineThe 7. Do NOT Hardcode SMTP/IMAP in Environment VariablesIf you define SMTP settings via environment variables, they become read-only in the OpenProject admin UI. Configure email via the UI instead for flexibility. Step-by-Step DeploymentStep 1: Create New Service Stack
Step 2: Configure Service Stack Settings
Step 3: Edit Compose FileClick "Edit Compose File" and paste the working configuration below. Important: Replace these placeholders with secure values:
Step 4: Save and Deploy
Step 5: Configure Domain on Web ServiceAfter deployment:
Step 6: Handle Phantom ServicesIf you see an "Open Project" service (from YAML anchors):
Do the same for the Seeder service (enable "Exclude from service status"). Step 7: Verify Deployment
Working Docker Compose Configuration
Post-Deployment ConfigurationEmail Configuration (SMTP)Do NOT configure SMTP via environment variables - it locks the settings in the UI and makes them read-only. Instead, configure via OpenProject Admin UI:
For Port 587 (STARTTLS) - Recommended
Incoming Email (IMAP) - OptionalTo create work packages via email, configure under Administration → Emails and notifications → Incoming emails. Troubleshooting"no available server" ErrorCause: Domain is assigned to a non-running service (usually the phantom "Open Project" from YAML anchors). Solution:
Container "cache" is UnhealthyCause: Health check uses Solution: Remove the health check from the cache service (as shown in the config above). Seeder Shows "Exited" StatusThis is normal! The seeder runs once to initialize the database, then exits. Solution: Enable "Exclude from service status" for the seeder service in Coolify. SSL/STARTTLS Email Errors ("wrong version number")Cause: Mismatched SSL/STARTTLS settings for the SMTP port. Solution:
SMTP Settings Are Grayed Out / Read-OnlyCause: SMTP is configured via environment variables in docker-compose.yml. Solution: Remove all Database Connection Errors After RestartCause: Services starting before database is ready. Solution: The configuration above uses Architecture OverviewCreditsThis guide was created after extensive troubleshooting and testing. Special thanks to the Coolify and OpenProject communities. If this guide helped you, please consider:
Author: Dimitri Rupp |
Beta Was this translation helpful? Give feedback.
-
|
@ruppdi75 Thanks man, Thank you all!! |
Beta Was this translation helpful? Give feedback.
-
|
I've updated the guide provided by the amazing @ruppdi75 for OpenProject 1.7 (with hocuspocus and live doc editing) There is also an optimized version for very small VPS Instance (like CX22 on hetzner who is half of the minimum requirements of OpenProject). OpenProject 17 on Coolify — Deployment Guide
What Changed from v16 to v17
Coolify Golden Rules (unchanged from v16)These pitfalls still apply exactly as Dimitri documented them:
Environment Variables ReferenceSet these in Coolify UI → Service Stack → Environment Variables. Required
Optional
Step-by-Step Deployment1. Create Service StackIn Coolify: Projects → your project → + New → Docker Compose → Empty Docker Compose 2. Configure Stack Settings
3. Set Environment VariablesIn Coolify UI, add at minimum:
4. Paste Docker ComposeClick "Edit Compose File" and paste the contents of 5. Save & DeployClick Save, then Deploy. Wait 2–3 minutes. 6. Configure Domain on Web ServiceAfter deployment:
7. Configure Domain on Hocuspocus ServiceHocuspocus needs its own subdomain. Path-based routing (
8. Handle Phantom / Seeder ServicesIf you see phantom services (from any residual YAML anchor parsing):
Do the same for the seeder service (it's supposed to show "Exited"). 9. Verify & Secure
Hocuspocus (Collaborative Editing)OpenProject 17 introduces real-time collaborative editing via Hocuspocus. The setup requires:
Why a Subdomain is Required on CoolifyThe official OpenProject docker-compose includes a proxy service that routes The solution is to give Hocuspocus its own subdomain (e.g.
Both get automatic SSL via Coolify, and WebSocket upgrades work out of the box. Checklist
Architecture (v17)TroubleshootingAll of Dimitri's original troubleshooting tips still apply. Additional v17 items: Collaborative Editing: "real-time text collaboration server is unreachable"Cause: Hocuspocus is not reachable from the browser. This is almost always a routing issue. Solution: Hocuspocus needs its own subdomain in Coolify (see Hocuspocus section above). Path-based routing (
Seeder Exits with Code 2 (No Logs)Cause: Usually a malformed Solution: Use hex-only passwords: Server Hangs at 100% CPU During SeedingCause: The first-time seeder runs database migrations + data seeding + asset tasks. On a 2 vCPU server this can saturate both cores for 5–15 minutes, making the entire server (including other Coolify apps) unresponsive. Solution: Wait 15 minutes. If still stuck, reboot the server. The seeder will re-run on next deploy. For small servers (2 vCPU / 4GB), consider deploying during low-traffic hours. Collaborative Editing Not SyncingSymptoms: Editor opens but changes don't appear for other users, or cursors don't show. Check:
PostgreSQL Migration from 13 to 17If upgrading an existing v16 installation that used Postgres 13:
Docker Compose File (standard file)Docker Compose Optimized for very small VPS Instance (Like CX22 on hetzner who is half the minimum requirements of OpenProject.) |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
It would be great to have a service deployment for Open Project! https://www.openproject.org/
Beta Was this translation helpful? Give feedback.
All reactions