Simple and effective site analytics

December 13, 2025 - 150 words - 1 mins #go #website #analytics in tools

I’d like to share a small but useful find in the category of simple and effective tools that handle a small yet important part of analytics work like collecting statistics for small to medium-sized websites without requiring extra effort for setup or ongoing maintenance.

Let me introduce GoatCounter — easy web analytics with no tracking of personal data. Its setup takes just a couple of minutes, and it doesn’t require large configuration files, complex databases, search engines, or ClickHouse. Just a single binary and SQLite — that’s all and its awesome.

GoatCounter

I just wanted to say thank you to Martin Tournoij and the many developers who helped build this, and I hope my humble publication will also help promote this wonderful tool.

And just in case you need a ready-made configuration. The simplest setup ever:

# docker-compose.yaml

services:
  nginx:
    image: nginx:1.26-bookworm
    container_name: nginx
    deploy:
      replicas: 1
      resources:
        limits:
          cpus: '1'
          memory: 512M
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/etc/nginx/certs
      - /var/www/html/blog/public:/usr/share/nginx/html
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - goatcounter
    networks:
      - backend

  goatcounter:
    image: arp242/goatcounter:latest
    container_name: goatcounter
    command: serve -automigrate
    restart: always
    volumes:
      - goatcounter-data:/home/goatcounter/goatcounter-data
    networks:
      - backend

volumes:
  goatcounter-data:

networks:
  backend:
    driver: bridge

And also Nginx configuration:

# nginx.conf

server {
    listen 443 ssl;
    server_name _;

    ssl_certificate /etc/nginx/certs/selfsigned.crt;
    ssl_certificate_key /etc/nginx/certs/selfsigned.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers off;

    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    location / {
        proxy_pass http://goatcounter:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

© 2025 Sergey Silaev. This blog is powered by Zola written in Rust ❤️ and hosted by Hetzner.