How to Install an Open Source CRM with Docker
Docker containers package the CRM application, its web server, database, and supporting services into isolated, portable units. Docker Compose orchestrates these containers so they start together, communicate on a private network, and persist data to volumes that survive container restarts. The result is a deployment that is reproducible, easy to upgrade, and consistent across development, staging, and production environments.
Step 1: Prepare the Server
Start with a Linux server running Ubuntu 22.04 LTS or Debian 12. A VPS with 2 CPU cores, 4 GB RAM, and 40 GB SSD storage is sufficient for a CRM serving up to 20 concurrent users. For larger teams, scale to 4 cores and 8 GB RAM. SSD storage is important because CRM database queries benefit significantly from fast disk I/O.
Install Docker Engine using the official repository method. On Ubuntu, this involves adding the Docker GPG key, configuring the apt repository, and running apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin. The docker-compose-plugin package provides the docker compose command (v2 syntax) as a Docker CLI plugin. Verify the installation by running docker --version and docker compose version. Both commands should return version numbers confirming successful installation.
Add your non-root user to the docker group with usermod -aG docker your-username, then log out and back in for the group membership to take effect. This allows you to run Docker commands without sudo, which simplifies the workflow and avoids file permission issues with mounted volumes.
Create a dedicated directory for your CRM deployment. A common convention is /opt/crm/ or /srv/crm/. All Docker Compose files, environment configuration, and data volumes will live under this directory, keeping the deployment organized and easy to manage.
Step 2: Create the Docker Compose Configuration
Each CRM platform requires a docker-compose.yml file that defines the application services, database, networking, and persistent storage. The configuration details differ by platform.
For SuiteCRM: The Bitnami SuiteCRM image is the most commonly used Docker image. The compose file defines two services: a SuiteCRM application container (bitnami/suitecrm) and a MariaDB database container (bitnami/mariadb). Key environment variables include SUITECRM_DATABASE_HOST, SUITECRM_DATABASE_USER, SUITECRM_DATABASE_PASSWORD, SUITECRM_DATABASE_NAME, SUITECRM_USERNAME (admin login), and SUITECRM_PASSWORD. Mount two named volumes: one for MariaDB data persistence and one for SuiteCRM application data. Map the application container's port 8080 to a host port (or leave it internal if using a reverse proxy). The Bitnami image handles Apache, PHP, and SuiteCRM configuration internally.
For EspoCRM: The official EspoCRM Docker image (espocrm/espocrm) works alongside a MySQL container. The compose file defines three services: the EspoCRM application, a MySQL database, and an EspoCRM daemon container that handles scheduled jobs (cron tasks). Environment variables configure ESPOCRM_DATABASE_HOST, ESPOCRM_DATABASE_USER, ESPOCRM_DATABASE_PASSWORD, and ESPOCRM_ADMIN_USERNAME/PASSWORD. Mount volumes for MySQL data and the EspoCRM data directory (which holds configuration, custom modules, and uploaded files). The daemon container shares the same data volume as the application container and runs background jobs like workflow execution, email fetching, and cleanup tasks.
For Twenty: The official Twenty docker-compose.yml from their GitHub repository defines the application server (twentycrm/twenty), a PostgreSQL database (postgres), and a Redis cache (redis). Environment variables include SERVER_URL (your CRM domain), PG_DATABASE_URL (PostgreSQL connection string), REDIS_URL, ACCESS_TOKEN_SECRET, LOGIN_TOKEN_SECRET, and STORAGE_TYPE. Twenty generates cryptographic secrets on first startup if not provided. Mount volumes for PostgreSQL data and Twenty's local storage directory. Twenty listens on port 3000 by default.
For all platforms, use an .env file alongside docker-compose.yml to store sensitive values like database passwords and secrets. Reference these in the compose file with variable substitution syntax. Never commit the .env file to version control.
Step 3: Launch the Containers
From the directory containing your docker-compose.yml, run docker compose up -d. Docker pulls the required images from the container registry (this takes a few minutes on first run depending on internet speed), creates the network, starts the containers, and detaches to run in the background.
Monitor the startup with docker compose logs -f to watch the initialization process in real time. The database container initializes first, creating the database and user account. The application container waits for the database to become available, then runs its own initialization: creating tables, loading default data, and starting the web server. First startup takes longer than subsequent starts because of this initialization.
Verify all containers are running with docker compose ps. You should see all defined services with a status of "Up" and healthy health checks where applicable. If any container fails to start, check its logs with docker compose logs service-name for diagnostic information.
At this point, the CRM is accessible on the configured port. If you are installing locally or on a server without a domain yet, access it via http://server-ip:port to verify the application loads correctly before proceeding with domain and TLS configuration.
Step 4: Complete Initial Setup
Each platform has a slightly different initial configuration process after the containers are running.
SuiteCRM with the Bitnami image completes most setup automatically using the environment variables you provided. The admin account is created with the username and password from the compose configuration. Log in and verify that modules are loading correctly, the admin panel is accessible, and the system check page shows no critical warnings.
EspoCRM presents a web-based installation wizard on first access. The wizard confirms database connectivity (using the environment variables), creates the database schema, sets up the admin account, and configures system settings like date format, time zone, and language. Complete each step and verify that the dashboard loads after finishing the wizard.
Twenty displays a setup screen on first access where you create the initial workspace and admin account. Enter your name, email address, and password. Twenty then initializes the workspace, creates the default data schema, and drops you into the main application. Configure your workspace settings including company name, logo, and default currency.
For all platforms, immediately after initial setup: change any default passwords that were set through environment variables, verify that email sending works (configure SMTP and send a test message), and confirm that scheduled jobs or cron tasks are executing (check the CRM's scheduled job log or admin health page).
Step 5: Configure Reverse Proxy and TLS
For production use, place an Nginx reverse proxy in front of the Docker containers. Install Nginx directly on the host (apt install nginx) rather than in a Docker container, as this simplifies TLS certificate management with Certbot.
Create an Nginx server block for your CRM domain. The configuration should listen on port 80, define the server_name matching your domain, and proxy all requests to the CRM container's internal port (8080 for SuiteCRM, 8080 for EspoCRM, 3000 for Twenty) on localhost. Include standard proxy headers: proxy_set_header Host, X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto. Set proxy_read_timeout to at least 300 seconds to accommodate long-running CRM operations like bulk imports.
Install Certbot with the Nginx plugin (apt install certbot python3-certbot-nginx). Run certbot --nginx -d crm.yourdomain.com. Certbot obtains a certificate from Let's Encrypt, modifies the Nginx configuration to enable HTTPS, sets up HTTP-to-HTTPS redirection, and configures automatic renewal via a systemd timer. Verify the certificate by accessing your CRM at the HTTPS URL.
After TLS is configured, update the CRM's site URL in its configuration to use the HTTPS domain. For SuiteCRM, edit the config.php file (or the environment variable). For EspoCRM, update the Site URL in Administration > Settings. For Twenty, update the SERVER_URL environment variable and restart the container.
Step 6: Set Up Backups and Cron Jobs
Automated backups are essential for any production CRM deployment. Create a backup script that performs both a database dump and a file system backup of the CRM data volume.
For MySQL/MariaDB (SuiteCRM and EspoCRM), the backup command executes mysqldump inside the database container using docker compose exec. For PostgreSQL (Twenty), use pg_dump inside the postgres container. The script should compress the dump file with gzip, name it with a timestamp, and copy it to a remote location using rsync, scp, or an S3-compatible upload tool like rclone.
Schedule the backup script with a cron job running daily during off-hours. A typical crontab entry runs the script at 2:00 AM server time. Set a retention policy that keeps 14 daily backups, 8 weekly backups, and 12 monthly backups. Write a simple cleanup function in the backup script that removes backups older than the retention period.
For SuiteCRM, verify that the built-in scheduler is running. SuiteCRM uses a cron job that calls the CRM scheduler endpoint every minute to process workflow actions, email campaigns, and system maintenance tasks. Add this to the host's crontab or configure it as a separate Docker container. EspoCRM handles this through the daemon container defined in the compose file. Twenty handles background jobs internally within the application container.
Test the entire backup and restore process at least once before considering the deployment production-ready. Spin up a temporary set of containers, load the backup, and verify that the CRM application works correctly with the restored data. Document the restore procedure so that any team member can execute it in an emergency.
Upgrading Your Docker CRM
One of Docker's greatest advantages for CRM deployment is clean upgrades. The general process for all three platforms follows the same pattern: stop the containers, back up the database and data volumes, pull the new container images, and start the containers. The application detects the version change and runs any necessary database migrations automatically.
Before upgrading production, test the upgrade on a copy. Duplicate your data volumes, create a separate compose file pointing to the copies, and run the upgrade process against the test instance. Verify that the CRM functions correctly with the new version before applying the upgrade to production. This practice catches breaking changes, deprecated configurations, and migration issues in a safe environment.
Subscribe to the release channels for your chosen CRM: SuiteCRM's GitHub releases page, EspoCRM's changelog, or Twenty's release blog. Security patches should be applied promptly. Feature releases can be evaluated and scheduled for planned maintenance windows.
Docker Compose reduces CRM installation from a multi-hour process to a matter of minutes. The key to a production-grade deployment is what you do after the containers are running: TLS certificates, automated backups, monitoring, and a tested upgrade procedure. Do those four things and your self-hosted CRM will be as reliable as any SaaS platform.