How to Self-Host Countly with Docker Compose

What Is Countly?

Countly is an open-source product analytics platform that tracks web, mobile, and desktop application usage. Unlike simple pageview analytics like Plausible or Umami, Countly focuses on product metrics — user sessions, custom events, crash reporting, push notifications, and user flows. The Community Edition (AGPL-3.0) covers core analytics, while the Enterprise edition adds advanced features like funnels, cohorts, and A/B testing.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 4 GB of free RAM (MongoDB + Node.js workers)
  • 10 GB of free disk space
  • A domain name (recommended for production)

Docker Compose Configuration

Create a docker-compose.yml file:

services:
  countly-api:
    image: countly/api:25.03
    container_name: countly-api
    environment:
      COUNTLY_PLUGINS: "mobile,web,desktop,plugins,density,locale,browser,sources,views,logger,systemlogs,populator,reports,crashes,push,star-rating,slipping-away-users,compare,server-stats,dbviewer,times-of-day,compliance-hub,alerts,onboarding,consolidate,remote-config,hooks,dashboards,sdk,data-manager"
      COUNTLY_CONFIG__MONGODB_HOST: mongodb
      COUNTLY_CONFIG_API_API_WORKERS: "4"
      COUNTLY_CONFIG__FILESTORAGE: "gridfs"
      NODE_OPTIONS: "--max-old-space-size=2048"
    depends_on:
      mongodb:
        condition: service_healthy
    networks:
      - countly
    restart: unless-stopped

  countly-frontend:
    image: countly/frontend:25.03
    container_name: countly-frontend
    environment:
      COUNTLY_PLUGINS: "mobile,web,desktop,plugins,density,locale,browser,sources,views,logger,systemlogs,populator,reports,crashes,push,star-rating,slipping-away-users,compare,server-stats,dbviewer,times-of-day,compliance-hub,alerts,onboarding,consolidate,remote-config,hooks,dashboards,sdk,data-manager"
      COUNTLY_CONFIG__MONGODB_HOST: mongodb
      NODE_OPTIONS: "--max-old-space-size=2048"
    deploy:
      resources:
        limits:
          cpus: "0.5"
    depends_on:
      mongodb:
        condition: service_healthy
    networks:
      - countly
    restart: unless-stopped

  mongodb:
    image: bitnami/mongodb:7.0
    container_name: countly-mongodb
    volumes:
      - mongodb_data:/bitnami
    networks:
      - countly
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 5s
      retries: 5

  countly-nginx:
    image: nginx:1.27-alpine
    container_name: countly-nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - countly-api
      - countly-frontend
    networks:
      - countly
    restart: unless-stopped

networks:
  countly:

volumes:
  mongodb_data:

Create nginx.conf for the reverse proxy:

upstream countly-api {
    server countly-api:3001;
}

upstream countly-frontend {
    server countly-frontend:6001;
}

server {
    listen 80;
    server_name _;

    location = /i {
        proxy_pass http://countly-api;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location ^~ /i/ {
        proxy_pass http://countly-api;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location = /o {
        proxy_pass http://countly-api;
    }

    location ^~ /o/ {
        proxy_pass http://countly-api;
    }

    location / {
        proxy_pass http://countly-frontend;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Start the stack:

docker compose up -d

Initial Setup

  1. Wait 1-2 minutes for MongoDB to initialize and Countly to start
  2. Open http://your-server-ip:8080 in your browser
  3. Complete the setup wizard:
    • Create an admin account (email and password)
    • Enter your application name
    • Select the platform (web, mobile, desktop)
  4. You’ll receive an app key and SDK endpoint URL

Configuration

API Workers

Set COUNTLY_CONFIG_API_API_WORKERS to match your CPU core count. More workers handle more concurrent requests:

CPU CoresRecommended Workers
1-22
44
8+6-8

Memory Allocation

NODE_OPTIONS: "--max-old-space-size=2048" sets Node.js heap to 2 GB. Adjust based on available RAM:

Server RAMRecommended Setting
4 GB1024
8 GB2048
16 GB+4096

Plugins

The COUNTLY_PLUGINS environment variable controls which plugins load. The list in the Docker Compose above includes all Community Edition plugins. Remove plugins you don’t need to reduce memory usage.

Web SDK Integration

Add the Countly Web SDK to your site:

<script type="text/javascript">
var Countly = Countly || {};
Countly.q = Countly.q || [];
Countly.app_key = "YOUR_APP_KEY";
Countly.url = "https://your-countly-server.example.com";
Countly.q.push(["track_sessions"]);
Countly.q.push(["track_pageview"]);
Countly.q.push(["track_errors"]);
</script>
<script async src="https://your-countly-server.example.com/sdk/web/countly.min.js"></script>

Replace YOUR_APP_KEY and the URL with your actual values from the dashboard.

Reverse Proxy

For production with SSL, put the Nginx container behind your main reverse proxy:

  • Scheme: http
  • Forward Hostname: countly-nginx (or host IP)
  • Forward Port: 8080

See Reverse Proxy Setup for details.

Backup

MongoDB stores all analytics data. Back it up with:

docker exec countly-mongodb mongodump --archive=/bitnami/backup-$(date +%Y%m%d).gz --gzip
docker cp countly-mongodb:/bitnami/backup-$(date +%Y%m%d).gz ./

See Backup Strategy for a comprehensive backup approach.

Troubleshooting

Dashboard Loads But Shows No Data

Symptom: You can log in but no events or sessions appear. Fix: Verify the app key in your SDK matches the key shown in Management → Applications. Check that the SDK URL points to your Countly server’s public address, not localhost. Check browser console for CORS errors.

MongoDB Connection Errors on Startup

Symptom: API and frontend containers restart repeatedly with connection errors. Fix: MongoDB takes 30-60 seconds to initialize on first run. The depends_on with health check handles this. If it persists, check MongoDB logs: docker logs countly-mongodb.

High Memory Usage

Symptom: Server runs out of RAM after a few days. Fix: Reduce NODE_OPTIONS max-old-space-size. Remove unused plugins from COUNTLY_PLUGINS. Consider running only essential plugins: mobile,web,plugins,views,logger,systemlogs,crashes,dashboards,sdk.

Plugins Not Loading

Symptom: Dashboard shows fewer features than expected. Fix: Ensure the COUNTLY_PLUGINS environment variable is identical in both countly-api and countly-frontend services. Mismatched plugin lists cause features to appear broken.

Resource Requirements

  • RAM: ~1.5 GB idle (MongoDB + API + Frontend + Nginx), ~3-4 GB under load
  • CPU: Moderate — scales with API workers
  • Disk: ~500 MB for the application, plus MongoDB growth (~1 MB per 10,000 events)

Verdict

Countly is the right choice when you need more than pageview analytics. If you’re tracking mobile app usage, custom events, crash reports, or user flows, Countly’s product analytics capabilities far exceed what Plausible or Umami offer. The trade-off is complexity — 4 containers, higher memory usage, and more configuration. For simple website analytics, Plausible or Umami are easier. For full product analytics that rivals Mixpanel or Amplitude, Countly delivers.

Comments