Self-Hosting EspoCRM with Docker Compose

What Is EspoCRM?

EspoCRM is a mature open-source CRM that handles contacts, accounts, leads, opportunities, email integration, calendar, and workflow automation. It’s been around since 2014 and has a significantly more polished UI than most open-source CRM alternatives. Think of it as a practical Salesforce replacement for small to mid-size teams — it does 80% of what Salesforce does at 0% of the cost.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 1 GB of free RAM (2 GB recommended for 5+ concurrent users)
  • 5 GB of free disk space
  • A domain name (required for email integration and WebSocket)

Docker Compose Configuration

EspoCRM needs four services: the main app, a background job daemon, a WebSocket server (optional but recommended), and MariaDB. All three EspoCRM services share the same Docker image with different entrypoints.

Create a docker-compose.yml:

services:
  espocrm:
    image: espocrm/espocrm:9.3.3
    container_name: espocrm
    depends_on:
      espocrm-db:
        condition: service_healthy
    environment:
      ESPOCRM_DATABASE_PLATFORM: Mysql
      ESPOCRM_DATABASE_HOST: espocrm-db
      ESPOCRM_DATABASE_USER: espocrm
      ESPOCRM_DATABASE_PASSWORD: changeme_strong_password  # CHANGE — must match DB
      ESPOCRM_ADMIN_USERNAME: admin
      ESPOCRM_ADMIN_PASSWORD: changeme_admin_password      # CHANGE
      ESPOCRM_SITE_URL: "http://localhost:8080"            # CHANGE to your public URL
    volumes:
      - espocrm-data:/var/www/html    # App files, config, uploads
    ports:
      - "8080:80"                     # Web UI
    restart: unless-stopped

  espocrm-daemon:
    image: espocrm/espocrm:9.3.3
    container_name: espocrm-daemon
    entrypoint: docker-daemon.sh
    volumes:
      - espocrm-data:/var/www/html    # Must share volume with main app
    restart: unless-stopped

  espocrm-websocket:
    image: espocrm/espocrm:9.3.3
    container_name: espocrm-websocket
    entrypoint: docker-websocket.sh
    environment:
      ESPOCRM_CONFIG_USE_WEB_SOCKET: "true"
      ESPOCRM_CONFIG_WEB_SOCKET_URL: "ws://localhost:8081"
      ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN: "tcp://*:7777"
      ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN: "tcp://espocrm-websocket:7777"
    volumes:
      - espocrm-data:/var/www/html    # Must share volume with main app
    ports:
      - "8081:8080"                   # WebSocket for real-time updates
    restart: unless-stopped

  espocrm-db:
    image: mariadb:11.7
    container_name: espocrm-db
    environment:
      MARIADB_ROOT_PASSWORD: changeme_root_password      # CHANGE
      MARIADB_DATABASE: espocrm
      MARIADB_USER: espocrm
      MARIADB_PASSWORD: changeme_strong_password         # CHANGE — must match app
    volumes:
      - espocrm-db-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 20s
      start_period: 10s
      timeout: 10s
      retries: 3
    restart: unless-stopped

volumes:
  espocrm-data:
  espocrm-db-data:

Before starting: Change all changeme passwords. Update ESPOCRM_SITE_URL to your actual access URL — this is critical for email links, calendar invites, and API responses.

docker compose up -d

Initial Setup

  1. Open http://your-server-ip:8080 in your browser
  2. Log in with the admin credentials you set (admin / your password)
  3. Complete the setup wizard — configure your company name, timezone, and date format
  4. Navigate to Administration → Integrations to connect email (IMAP/SMTP)

First Steps

StepWhereWhat to Do
1Administration → Outbound EmailsConfigure SMTP for sending emails
2Administration → Personal Email AccountsConnect IMAP for email tracking
3Leads or ContactsImport existing contacts from CSV
4Administration → RolesSet up user roles and permissions
5Administration → WorkflowsCreate automation rules

Key Features

EspoCRM ships with a comprehensive feature set out of the box:

ModuleWhat It Does
Contacts & AccountsPeople and organizations with custom fields, relationships, activity history
LeadsLead capture, scoring, and conversion to contacts/opportunities
OpportunitiesSales pipeline with stages, probability, and revenue forecasting
CalendarShared calendars, meeting scheduling, reminders
EmailFull email integration (IMAP/SMTP), email-to-lead conversion, mass email
Calls & MeetingsLog calls, schedule meetings, track outcomes
WorkflowsTrigger-based automation (e.g., send email when deal stage changes)
ReportsVisual reports and dashboards with charts
Knowledge BaseInternal documentation and FAQ system
StreamActivity feed showing all interactions per record

Configuration

Email Integration

EspoCRM’s email features are one of its strongest selling points. To enable them:

  1. Outbound (SMTP): Administration → Outbound Emails → add your SMTP server
  2. Personal inbox: Click your avatar → Personal Email Accounts → add IMAP
  3. Group inbox: Administration → Group Email Accounts → add a shared inbox (e.g., [email protected])

Emails automatically link to contacts based on email address matching.

Custom Fields and Entities

EspoCRM’s entity manager lets you create custom record types and fields without writing code:

  1. Administration → Entity Manager
  2. Create a new entity or extend an existing one
  3. Add custom fields (text, number, enum, multi-enum, date, currency, and more)
  4. Define relationships between entities

Workflow Automation

Navigate to Administration → Workflows to create automation rules:

  • Trigger types: After record created, after record updated, scheduled, sequential
  • Actions: Send email, create record, update record, notify users, execute formula
  • Conditions: Filter which records trigger the workflow

Example: automatically send a follow-up email 3 days after a deal enters “Proposal Sent” stage.

Reverse Proxy

For production with HTTPS, update your compose and reverse proxy configuration.

Update ESPOCRM_SITE_URL to your HTTPS domain:

ESPOCRM_SITE_URL: "https://crm.example.com"

For the WebSocket URL:

ESPOCRM_CONFIG_WEB_SOCKET_URL: "wss://crm.example.com/ws"

Caddy example (handling both HTTP and WebSocket):

crm.example.com {
    reverse_proxy localhost:8080

    handle /ws {
        reverse_proxy localhost:8081
    }
}

See our Reverse Proxy Guide for Nginx Proxy Manager and Traefik configurations.

Backup

Back up the database and application volume:

# Database dump
docker exec espocrm-db mariadb-dump -u root -p'your_root_password' espocrm > espocrm-backup-$(date +%Y%m%d).sql

# Application data (config, uploads, extensions)
docker run --rm -v espocrm-data:/data -v $(pwd):/backup \
  alpine tar czf /backup/espocrm-data-$(date +%Y%m%d).tar.gz /data

Restore:

cat espocrm-backup-20260224.sql | docker exec -i espocrm-db mariadb -u root -p'your_root_password' espocrm

See our Backup Strategy Guide for automated approaches.

Troubleshooting

Scheduled Jobs Not Running

Symptom: Emails not being fetched, workflows not triggering, notifications not sent.

Fix: The espocrm-daemon service must be running. It handles all background jobs:

docker ps | grep espocrm-daemon
docker logs espocrm-daemon

The daemon must share the same volume as the main app (espocrm-data:/var/www/html). If the volume isn’t shared, the daemon can’t access the application code.

WebSocket Connection Failed

Symptom: Browser console shows WebSocket connection errors. UI doesn’t update in real-time.

Fix: Check that:

  1. espocrm-websocket is running
  2. ESPOCRM_CONFIG_WEB_SOCKET_URL matches how users access the WebSocket (including ws:// vs wss:// for HTTPS)
  3. ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN uses the container name (tcp://espocrm-websocket:7777)
  4. Port 8081 is accessible (or routed through your reverse proxy)

Email Sending Fails

Symptom: Outbound emails stuck in queue, no delivery.

Fix: Check SMTP settings in Administration → Outbound Emails. Test with the “Send Test Email” button. Common issues:

  • Wrong port (use 587 for STARTTLS, 465 for SSL)
  • Authentication required but not configured
  • Firewall blocking outbound SMTP

ESPOCRM_SITE_URL Mismatch

Symptom: Login redirects loop, links in emails point to the wrong URL, API calls fail.

Fix: ESPOCRM_SITE_URL must exactly match the URL users type in their browser. If behind a reverse proxy with HTTPS, it must be https://your-domain.com — not http://localhost:8080. After changing, restart the container.

Resource Requirements

MetricValue
RAM (idle)~300 MB (app) + ~100 MB (daemon) + ~80 MB (websocket) + ~150 MB (MariaDB)
RAM (active, 5+ users)800 MB - 1.5 GB
CPULow-Medium
Disk~500 MB for application + database growth

Verdict

EspoCRM is the most mature and feature-complete self-hosted CRM you can deploy today. The email integration is genuinely useful (not a checkbox feature), workflow automation covers real business processes, and the entity manager means you can customize it without touching code. It’s been actively developed since 2014 — the kind of stability that matters when you’re putting customer data into a system.

The main drawback is that the UI, while functional, isn’t as modern as newer alternatives like Twenty CRM. If you care more about a polished developer experience and GraphQL APIs, Twenty is worth looking at. But for raw CRM capability — lead management, email tracking, workflow automation, reporting — EspoCRM has years of refinement that newer tools haven’t matched yet.

Comments