How to Install, Update, and Monitor MaxMind’s GeoLite2 City Database on a Self-Hosted Server
Managing a GeoIP database efficiently is critical for enhancing your server logs, analytics, and user experience. In this post, I’ll walk you through the complete, professional-grade setup to:
- Install the free MaxMind GeoLite2-City database
- Create an auto-update script that downloads new database files monthly
- Set up a cron wrapper script to email you if an update fails or succeeds
This guide assumes you’re running a Debian/Ubuntu-based Linux server and have SSH access.
Let’s dive in!
Prerequisites
Before we start, ensure you have:
wget
,tar
, andbash
installed (default on most servers)- Basic knowledge of SSH and cron jobs
msmtp
or another minimal SMTP relay for sending email notifications
If you haven’t installed msmtp
, you can do so with:
sudo apt update
sudo apt install msmtp msmtp-mta
This provides a lightweight email sending capability without needing a full SMTP server.
Step 1: Get Your MaxMind License Key
MaxMind requires a license key to download GeoLite2 databases.
- Go to MaxMind’s GeoLite2 Signup Page
- Create an account and generate a License Key
- Save your license key securely
We’ll use this key to automate downloads.
Step 2: Create the Auto-Update Script
Let’s build a script that:
- Downloads the latest GeoLite2-City database
- Extracts it
- Moves it to the correct server folder
- Cleans up temporary files
- Sends a success or failure email notification
Create the script:
sudo nano /usr/local/bin/update-geoip-db.sh
Paste the following into the file:
#!/bin/bash
# Variables
LICENSE_KEY="YOUR_LICENSE_KEY" # Replace with your MaxMind license key
DOWNLOAD_DIR="/usr/share/GeoIP"
TMP_DIR="/tmp/geoip_update"
EMAIL="your@email.com" # Replace with your email
# Create temp directory
mkdir -p "$TMP_DIR"
cd "$TMP_DIR" || { echo "GeoIP Update: Failed to cd to $TMP_DIR" | mailx -s "GeoIP Update FAILED on $(hostname)" "$EMAIL"; exit 1; }
# Download latest GeoLite2-City database
wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=${LICENSE_KEY}&suffix=tar.gz" -O GeoLite2-City.tar.gz
if [ $? -ne 0 ]; then
echo "GeoIP Update: Failed to download GeoLite2-City.tar.gz" | mailx -s "GeoIP Update FAILED on $(hostname)" "$EMAIL"
exit 1
fi
# Extract
tar -xvzf GeoLite2-City.tar.gz
if [ $? -ne 0 ]; then
echo "GeoIP Update: Failed to extract GeoLite2-City.tar.gz" | mailx -s "GeoIP Update FAILED on $(hostname)" "$EMAIL"
exit 1
fi
# Move .mmdb file
find . -name "*.mmdb" -exec mv -f {} "${DOWNLOAD_DIR}/GeoLite2-City.mmdb" \;
if [ $? -ne 0 ]; then
echo "GeoIP Update: Failed to move GeoLite2-City.mmdb" | mailx -s "GeoIP Update FAILED on $(hostname)" "$EMAIL"
exit 1
fi
# Clean up temp files
rm -rf "$TMP_DIR"
# Success Notification
echo "GeoIP Update: Successfully updated at $(date)" | mailx -s "GeoIP Update SUCCESSFUL on $(hostname)" "$EMAIL"
exit 0
Make the script executable:
sudo chmod +x /usr/local/bin/update-geoip-db.sh
✅ Done! You now have a script that updates the database and notifies you on success or failure.
Step 3: Create a Cron Wrapper Script
We want an additional layer of monitoring for any critical cron jobs.
This wrapper will:
- Run any script
- Monitor its exit status
- Email you the output if it fails
- (Optional) Email you even on success
Create the wrapper:
sudo nano /usr/local/bin/cron_email_on_failure.sh
Paste the following:
#!/bin/bash
# Arguments
SCRIPT="$1"
LOGFILE="$2"
EMAIL="your@email.com" # Replace with your email
# Run the script
/bin/bash "$SCRIPT" >> "$LOGFILE" 2>&1
EXIT_CODE=$?
# Tail log content
BODY=$(tail -n 50 "$LOGFILE")
# Email based on result
if [ $EXIT_CODE -ne 0 ]; then
SUBJECT="CRON JOB FAILED: $(basename "$SCRIPT") on $(hostname)"
echo "$BODY" | mailx -s "$SUBJECT" "$EMAIL"
else
SUBJECT="CRON JOB SUCCESS: $(basename "$SCRIPT") on $(hostname)"
echo "$BODY" | mailx -s "$SUBJECT" "$EMAIL"
fi
exit 0
Make it executable:
sudo chmod +x /usr/local/bin/cron_email_on_failure.sh
✅ This wrapper gives you full, monitored control over any important script.
Step 4: Set Up Crontab
Now, let’s schedule our database updates automatically.
Edit your crontab:
crontab -e
Add the following lines:
MAILTO=""
# GeoIP Database Update (runs at 3:00 AM on the 1st of each month)
0 3 1 * * /usr/local/bin/cron_email_on_failure.sh /usr/local/bin/update-geoip-db.sh /var/log/update-geoip-db.log
✅ This ensures:
- No noisy default emails
- You get professional failure/success notifications
- Last 50 lines of the script log are included in the email
Additional Recommendations
- Log Rotation:
- You may want to rotate your
/var/log/update-geoip-db.log
once every few months to prevent it from growing indefinitely.
- You may want to rotate your
- Database Backup:
- Optionally, archive the previous month’s
.mmdb
file before overwriting it.
- Optionally, archive the previous month’s
- System Monitoring:
- Combine this setup with broader monitoring tools like Monit or Zabbix for full server oversight.
Conclusion
Congratulations! You now have a:
- Fully automated
- Email-monitored
- Failure-resilient
- Production-grade
GeoLite2-City database update system running on your server.
This setup not only keeps your GeoIP data current but also ensures you are immediately notified if anything breaks — keeping your operations clean, professional, and low-maintenance.
If you found this guide helpful, feel free to bookmark it for future reference, or leave a comment below if you have questions!