Mastering Changedetection.io: A Practical Guide to Self-Hosted Website Change Monitoring and Alerts
This guide offers a comprehensive, Ubuntu- and cloud-agnostic approach to self-hosted website change monitoring with Changedetection.io. Unlike guides tied to specific platforms, this tutorial provides precise prerequisites, clear Docker Compose installation steps, end-to-end alert configuration (Email, Slack, Webhook), and robust troubleshooting, upgrade, and security advice. It aims to empower users with instant alerts from over 100 monitoring locations, supporting over 10,000 customers.
Why This Guide Beats Provider-Centric Guides
- Ubuntu- and Cloud-Agnostic: Runs on any Linux host; no vendor lock-in.
- Precise Prerequisites: Includes exact versions and commands to avoid missteps.
- Clear Docker Compose Installation: Features explicit port mappings.
- End-to-End Post-Install Alerts: Supports Email, Slack, and Webhook with built-in testing.
- Comprehensive Support: Covers troubleshooting, upgrade paths, and security/backup best practices.
- Credible Data: Leverages 100+ monitoring locations, instant alerts, 10,000+ customers, and a 30-day free trial for the cloud edition.
Related Video Guide
(Link to related video guide would go here)
Prerequisites and Environment Setup
System Checks
Prepare your server for modern deployments with a quick triage. In just a few commands, you’ll confirm you’re on a supported Ubuntu release, that there’s enough memory and disk headroom, and that the time zone is correctly set.
System Checks at a Glance
| Aspect | What to Verify | Recommended Thresholds | Commands |
|---|---|---|---|
| OS Version | Ubuntu version should be 22.04 LTS or 24.04 LTS | 22.04 LTS or 24.04 LTS | lsb_release -a or cat /etc/os-release |
| Memory & Disk Space | Free memory and available disk space | Minimum 2 GB RAM, 20 GB disk headroom; swap disabled recommended | free -h and df -h |
| Time Zone | Server time zone should be UTC or your region | UTC is a safe default; set to your region as needed | timedatectl set-timezone UTC or timedatectl set-timezone <Region>/<City>; date to verify |
Quick Follow-ups
- OS version mismatch: Upgrade to 22.04 LTS or 24.04 LTS using your upgrade path or image.
- Insufficient RAM or disk space: Add memory or expand the disk headroom.
- Time zone incorrect: Set the appropriate zone with
timedatectl set-timezoneand verify withdate.
Install Docker Engine and Docker Compose (Ubuntu)
Ready to run containers on Ubuntu with the latest Compose experience? Here’s a fast, reliable path to install the Docker Engine and the Docker Compose v2 workflow, with commands you can copy-paste.
Install Prerequisites
Update the package index and install the basics needed to fetch Docker’s packages:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
Add Docker’s Official GPG Key and Repository
Set up Docker’s repository so you can install the official packages:
# Add the official GPG key and repository
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
Enable and Start Docker
Make sure Docker starts on boot and is currently running:
sudo systemctl enable docker
sudo systemctl start docker
Install Docker Compose Plugin or Use the docker compose (v2) Workflow
Choose your preferred path for Compose integration:
Option A: Install the Compose Plugin (v2)
sudo apt-get update
sudo apt-get install -y docker-compose-plugin
Option B: Use the docker compose (v2) Workflow (no separate binary)
# Verify the v2 compose integration
docker compose version
# Example usage
docker compose up -d
Verify Installations
Confirm both Docker and Compose are available and report their versions:
docker --version
docker compose version
Create a Non-Root User and Basic Firewall Rules
Skip root-heavy setups. Create a dedicated non-root user and a lean firewall to lock down your workstation, then get back to building. Copy-paste this fast guide.
1) Create a Dedicated User
sudo adduser changedetect
- To grant sudo privileges (optional):
sudo usermod -aG sudo changedetect - To allow Docker commands without sudo:
sudo usermod -aG docker changedetect
Note: Log out and back in (or run newgrp) for group changes to take effect.
2) Firewall Setup
sudo ufw allow OpenSSH
sudo ufw allow 5000
sudo ufw enable
sudo ufw status
Tip: If you’re running services on other ports, add corresponding UFW rules. Regularly review sudo access and keep the system updated.
Prepare Host Networking and Time Synchronization
Your server’s clock is the backbone of automation. If time drifts, cron jobs can run late, alerts misfire, and logs become hard to correlate. Start with solid, accurate time on the host, then plan for a TLS-terminating reverse proxy later to simplify certificate management and external access.
1) Get the Host Time Right (NTP/chrony)
- Check Current Time and Clock Status: Use commands like
timedatectl statusto see if the system clock is synchronized and what the time zone is. - Install a Time Synchronization Service: On modern Debian/Ubuntu systems,
chronyis common; on others, you may seentpdin use. If you’re unsure, chrony is a good default choice for fast convergence and low resource use. - Configure Time Servers: Point the service at reliable NTP pools (e.g.,
pool.ntp.orgor regional pools) to keep the clock accurate across network hiccups. - Start and Enable the Service: Ensure time stays in sync across reboots (e.g.,
sudo systemctl enable --now chronydor the equivalent service name for your distro). - Verify Synchronization: Run
chronyc tracking(orntpq -pif using ntpd) and re-check withtimedatectl statusto confirm “System clock synchronized: yes.” - Set a Consistent Time Zone: If you need UTC across your fleet (recommended for servers), use
timedatectl set-timezone UTC.
Why this matters: Cron jobs, alerting rules, and log timestamps all rely on a reliable system time. A solid NTP/chrony setup prevents drift that can cause missed jobs or late alerts.
2) Plan for a Reverse Proxy with TLS Termination (Nginx or Traefik) Later
Why consider TLS termination at a reverse proxy later? A dedicated proxy centralizes certificate management, simplifies upgrades, and cleanly handles TLS for multiple services from one entry point.
Start with a simple plan and choose a tool that fits your workflow:
- Nginx: Mature, predictable, well-documented, excellent for stable routes and straightforward TLS setup with Certbot.
- Traefik: Dynamic configuration, built-in ACME/Let’s Encrypt support, and great for container-driven environments.
Key Steps When Ready to Enable TLS Termination
- Deploy the reverse proxy in front of your services and define routing rules to each backend (by hostname or path).
- Obtain and renew certificates (Let’s Encrypt is common). Traefik can automate this; Nginx with Certbot requires a small setup to renew automatically.
- Update DNS to point your domain to the proxy’s address and ensure backend services are accessible behind the proxy (usually via HTTP, with TLS only at the proxy).
- Test end-to-end: verify TLS with your domain, ensure clean redirects, and monitor for certificate expiry alerts.
| Aspect | Nginx | Traefik |
|---|---|---|
| TL;DR | Solid, stable TLS termination with lots of community examples | Dynamic, auto-ACME and container-friendly |
| Certificate Management | Certbot integration for Let’s Encrypt | Automatic ACME via built-in integration |
| Configuration Model | Static server blocks; straightforward for simple setups | Dynamic routing rules; great for rotating services |
| Best Use Case | Stability, traditional deployments | Containerized apps and rapid service changes |
Step-by-Step Installation (Docker Compose) for Changedetection.io on Ubuntu
Fetch the Changedetection.io Setup and Create docker-compose.yml
Get Changedetection.io up and running with Docker in a clean, repeatable way. Create a working directory, pull the repository, and drop in a compact docker-compose.yml that exposes the app on port 5000 and stores config data locally.
- Create a working directory:
sudo mkdir -p /opt/changedetection.io - Clone the repository or download the official docker-compose example:
git clone https://github.com/dgtlmoon/changedetection.io.git /opt/changedetection.io - Create a
docker-compose.yml:
Use the following content. Place it at/opt/changedetection.io/docker-compose.yml.
version: '3.8'
services:
changedetection:
image: ghcr.io/dgtlmoon/changedetection.io:latest
ports:
- '5000:5000'
volumes:
- './config:/config'
environment:
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
restart: unless-stopped
Prepare Configuration Directory and Environment
Get your configuration ready in one go. Create the config folder, optionally pin the UID/GID and timezone, and ensure the right ownership so the app can read and write without friction.
- Make config directory:
sudo mkdir -p /opt/changedetection.io/config - Optionally create a
.envfile: Create/opt/changedetection.io/config/.envcontaining:PUID=1000 PGID=1000 TZ=UTC - Set proper permissions:
sudo chown -R 1000:1000 /opt/changedetection.io
Note: If your host uses different user/group IDs, replace 1000:1000 with the appropriate values to avoid permission issues.
Launch and Verify the Container
One command brings your Changedetection.io container to life. These steps are a fast, reliable way to launch the stack and confirm it’s healthy and reachable.
Summary of Steps
| Step | Command(s) | Description |
|---|---|---|
| Navigate | cd /opt/changedetection.io |
Move into the project directory |
| Start | docker compose up -d (or docker-compose up -d) |
Launch the stack in detached mode |
| Check Status | docker ps; docker compose logs -f changedetection (or docker-compose logs -f changedetection) |
Verify containers are running and view runtime logs |
| Initial Access | http://your-server:5000 |
Open the web UI and complete first-run prompts if shown |
Create a Basic Monitor and Test Alerts
Instantly set up a lightweight URL monitor with configurable change detection and a testable alert channel. Follow these steps to get alerts flowing in minutes.
Add the URL to Monitor
In the UI, choose “Add URL to monitor” and enter the target URL you want to track.
Configure Change-Detection Options
- Interval: How often we fetch the URL (examples: 30s, 1m, 5m).
- Sensitivity: How aggressively we detect changes (Low, Medium, High).
- Ignore Patterns: Patterns to exclude from triggering alerts (e.g.,
/status,/health, dynamic query parameters).
Quick Reference
| Option | What it Controls | Examples |
|---|---|---|
| Interval | How often we poll the URL | 30s, 1m, 5m |
| Sensitivity | What counts as a change | Low, Medium, High |
| Ignore Patterns | Exclude specific paths or content | /status, /version |
Set Up at Least One Alert Channel
- Email: Specify recipient addresses or a distribution list.
- Slack: Configure a Slack app or paste a webhook URL and target channel.
- Webhook: Add a custom endpoint for downstream tooling (e.g., PagerDuty, Discord, or your own service).
Trigger a Test Alert
After saving your channel(s), click “Test alert” to send a sample notification. Verify delivery: check your email, Slack channel, or your webhook listener. If it doesn’t arrive, double-check credentials and network access, then try again.
Post-Install Configuration: Alerts, Monitoring, and Testing
Configure Alert Channels: Email, Slack, Discord, Telegram
Alerts should land where your team already communicates. Here’s a quick, practical guide to configuring four popular channels: Slack, Email, Discord, and Telegram. Each path shows the exact steps and what to paste into Changedetection.io.
Slack
- In Slack, create an Incoming Webhook: Go to Slack API, create or select an app, enable Incoming Webhooks, and choose the channel where alerts should appear.
- Copy the webhook URL that Slack provides.
- In Changedetection.io, open the alert you want to notify, choose Slack as the channel, and paste the webhook URL into the field. Save the alert.
Tip: After saving, send a test alert to verify delivery and formatting in Slack.
To send alerts by email, provide the SMTP details and ensure the server can reach the SMTP host.
| Setting | Example / Guidance |
|---|---|
| SMTP Host | smtp.yourprovider.com |
| Port | 587 (STARTTLS) or 465 (SMTPS) |
| TLS/Encryption | Enabled |
| Username | your-smtp-username |
| Password | your-smtp-password |
Note: Ensure outbound SMTP is allowed by your firewall and networking rules.
In Changedetection.io, configure Email as the alert channel and fill in these fields. Tip: After saving, send a test email to confirm delivery.
Discord
Webhook Approach: In Discord, create a Webhook for the target channel (Server > Channel Settings > Integrations > Webhooks > New Webhook). Copy the Webhook URL. In Changedetection.io, select Discord as the alert channel and paste the Webhook URL. Save.
Alternative: Bot-based alerts can be used by creating a Discord Bot in the Developer Portal, inviting it to your server, and using the bot token and the target chat_id in Changedetection.io.
Tip: Bots offer more control (filters, richer embeds) but require a bit more setup.
Telegram
- In Telegram, create a bot using BotFather and copy the bot token.
- Identify the target
chat_id(the chat or channel you want alerts posted to). - In Changedetection.io, enter the bot token and the
chat_id, then save the alert.
Note: For Telegram, a bot is the typical method; webhooks can also be configured if your setup requires server-side handling.
Tip: After saving, test the Telegram alert to confirm delivery to the intended chat.
With these channels configured, your alerts will land in Slack, email, Discord, and Telegram exactly where your team collaborates. If you run into issues, double-check the tokens/URLs and run a quick test to verify delivery and formatting.
Test Alerts and Validate Delivery
Test alerts are your signal that the delivery pipeline actually works. Use a quick UI test to confirm it lands in Slack, Email, or Discord, then validate end-to-end by triggering a lightweight content change in a monitor.
Send a Test Alert from the UI
- Open the Alerts panel and choose the option to “Send test alert” (or the equivalent action in your UI).
- Provide a minimal payload: a clear title, a short message, and the target channel or recipient if prompted.
- Submit and note the UI’s confirmation. If available, capture the generated alert ID for reference.
Verify Receipt
- Check the designated destination for the new alert entry.
- Confirm the content matches what you sent (title, message, environment, severity).
- Record the arrival time to ensure it landed within your expected window.
Create a Quick Monitor and Force a Content Change
Set up or reuse a lightweight monitor that watches a simple piece of content (a page, post, or API response). Make a safe, reversible content change that will trigger an alert (toggle a flag, publish a new version, etc.). Trigger the change and observe the alert flow: does Slack/Email/Discord receive the alert, and does the message reflect the update? Optionally repeat with a second change to confirm consistent delivery across channels.
| Channel | What to Verify | Notes |
|---|---|---|
| Slack | Message appears in the correct channel and reflects the content | Check for the right environment/tags |
| Subject and body include the alert title, message, and key fields | Verify sender address | |
| Discord | Embed or message fields match the alert content | Check timestamp and channel |
With these quick checks, you gain confidence that alerts reach the right people reliably—before a real incident demands it.
Security and Performance Hardening
Security and performance go hand in hand. The fastest, most reliable apps start at the edge with a strong entry point, tight access control, and disciplined secrets management. Here’s a practical, no-nonsense guide you can apply today.
Set Up a Reverse Proxy with TLS and Let’s Encrypt
A reverse proxy in front of your app not only routes traffic efficiently but also terminates TLS at the edge, offloading work from your services.
- Choose Nginx or Traefik as the entry point.
- Configure TLS with certificates from Let’s Encrypt to automate renewal.
- Redirect HTTP to HTTPS and enable security headers (HSTS, Content-Security-Policy).
- Keep TLS updated: disable weak ciphers, use modern TLS (1.2+), and enable HTTP/2 or QUIC when supported.
- Leverage built-in ACME support (Traefik) or certbot (Nginx) to automate certificate provisioning and renewal.
Hardening: Enable UFW and Limit SSH Exposure
A minimal firewall blocks misconfigurations and brute force attempts before they reach your services.
- Enable UFW with a default deny policy, then allow only the necessary ports (e.g., 80/443 for the proxy, and SSH access from trusted networks).
- Limit SSH exposure to a jump host, VPN, or implement port-knocking if you want extra obscurity.
- Use SSH keys instead of passwords, disable root login, and consider enabling two-factor authentication on critical access points. Consider fail2ban to block repeated failures.
Regularly Review Container Logs and Rotate Credentials
Visibility into what’s happening inside containers and how secrets are used is essential for quick incident response and long-term security.
- Collect and centralize container logs (e.g., via a logging driver or a centralized ELK/EFK stack, cloud log service). Implement log rotation and retention to prevent disk pressure.
- Regularly scan logs for anomalies: repeated failed logins, unusual 5xx spikes, or unexpected traffic patterns.
- Rotate credentials and secrets routinely: use Docker secrets, Vault, or your platform’s secret manager. Automate rotation for keys, tokens, and certificates to minimize downtime.
Maintenance, Upgrades, and Backups
Pros
- Full control over data retention, privacy, and integration with your monitoring stack.
- No per-monitor licensing; predictable hosting costs if you operate your own server.
Upgrade Path: docker compose pull && docker compose up -d; document version compatibility.
Cons
- Ongoing maintenance, updates, and security patching required.
- Requires backups of
/opt/changedetection.io/configand any custom scripts.
Comparison: Self-hosted vs. Cloud
| Aspect | Self-hosted (Docker Compose on Ubuntu) | Cloud |
|---|---|---|
| Deployment Flexibility / Vendor Lock-in | Works on any compatible Linux server; no vendor lock-in; complete control of data. | Cloud plans may price per monitor or per location. |
| Alerts and Scaling | Self-hosted allows configuration of 100+ location alerts and custom destinations with your own alerting stack. | N/A (Specific provider details not provided) |
| Cost Model | Self-hosted has upfront hardware/cloud costs but no ongoing per-monitor fees. | Ongoing subscription plus optional 30-day free trial. |

Leave a Reply