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
- Wait 1-2 minutes for MongoDB to initialize and Countly to start
- Open
http://your-server-ip:8080in your browser - Complete the setup wizard:
- Create an admin account (email and password)
- Enter your application name
- Select the platform (web, mobile, desktop)
- 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 Cores | Recommended Workers |
|---|---|
| 1-2 | 2 |
| 4 | 4 |
| 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 RAM | Recommended Setting |
|---|---|
| 4 GB | 1024 |
| 8 GB | 2048 |
| 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.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments