Self-Hosting Web Analytics with Docker and PostgreSQL
One of the biggest advantages of open-source analytics is complete data ownership. When you self-host your analytics, no third party ever sees your traffic data. In this guide, we walk through deploying Xine Analytics on your own infrastructure using Docker Compose and PostgreSQL.
Why Self-Host?
Before we dive into the technical setup, here is why self-hosting your analytics matters:
- Data sovereignty: Your analytics data stays on your server. No third-party processors, no data sharing agreements, no vendor lock-in.
- Privacy compliance: Since data never leaves your infrastructure, GDPR Article 28 (data processor requirements) does not apply. You are both the controller and processor.
- Cost efficiency: Xine is free and open-source. The only cost is your server, which can be as little as $5/month on a VPS.
- Performance: A self-hosted analytics endpoint on your own domain avoids ad-blocker interference and reduces DNS lookups.
Prerequisites
You will need:
- A Linux VPS (Ubuntu 22.04+ recommended) with at least 1GB RAM
- Docker and Docker Compose installed
- A domain name pointed to your server
- Basic familiarity with the command line
Step 1: Clone the Repository
git clone https://github.com/unisource/xine.git
cd xine
Step 2: Configure Environment Variables
Create a .env file from the example:
cp .env.example .env
Edit the .env file with your configuration:
DB_HOST=postgres
DB_PORT=5432
DB_USER=xine_user
DB_PASSWORD=your_secure_password_here
DB_NAME=analytics_db
DASHBOARD_PASSWORD=your_dashboard_password
The DASHBOARD_PASSWORD is used for the single-user login to your analytics dashboard. Choose something strong—this protects access to all your analytics data.
Step 3: Launch with Docker Compose
docker-compose up -d
This starts two containers:
- PostgreSQL 16 — your analytics database with persistent data volume
- Xine App — the Next.js application serving both the dashboard and the data collection API
The first startup will automatically create the database schema using Drizzle ORM migrations.
Step 4: Set Up a Reverse Proxy
For production, you should put Xine behind Nginx with SSL. Here is a minimal Nginx configuration:
server {
listen 443 ssl;
server_name analytics.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/analytics.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/analytics.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Use Certbot to obtain free SSL certificates from Let's Encrypt.
Step 5: Add the Tracking Script
On any website you want to track, add the Xine script tag:
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/t.js"></script>
That is it. The 8KB tracking script will automatically start tracking pageviews, sessions, referrers, and browser data—without setting a single cookie.
Step 6: Access the Dashboard
Navigate to https://analytics.yourdomain.com and log in with the password you set in the .env file. You will see the full Xine dashboard with:
- Realtime visitors — live view of active sessions
- Traffic analytics — pageviews, sessions, bounce rate, and session duration
- Acquisition sources — referrers, UTM campaigns, and search engines
- Performance metrics — Core Web Vitals (LCP, FCP, CLS, INP, TTFB)
- Session replays — visual recordings of user journeys
Database Maintenance
PostgreSQL handles analytical workloads extremely well, but for high-traffic sites (100K+ pageviews/month), consider:
- Partitioning the
pageviewstable by month for faster queries - Setting up automated backups with
pg_dumpin a cron job - Monitoring disk usage and setting up log rotation
Conclusion
Self-hosting your analytics gives you the ultimate combination of privacy, performance, and control. With Docker Compose, the entire setup takes under 15 minutes. Your data stays on your server, your visitors get a faster experience, and you maintain full GDPR compliance without a single cookie.
Ready to own your analytics? Get started with Xine →
Published by Melvin Prince at Unisource