A beautiful domain expiration monitoring service for Homepage dashboard that tracks your domain renewals and alerts you before they expire.
π Want a standalone web dashboard? Check out domain-expiry-web for a beautiful interface with light/dark themes, color-coded status, and live countdown timer.
- π΄ Visual Alerts - Red indicator when domains are approaching expiration
- π Expiration Tracking - Shows days remaining for each domain
- π Auto-Refresh - Configurable cache (default 6 hours)
- π All TLDs - 3-tier fallback system supports 7,500+ TLDs worldwide
- π³ Docker Ready - Available on GitHub Container Registry & Docker Hub
- β‘ Fast & Lightweight - Python FastAPI backend
- π¨ Homepage Native - Uses built-in customapi widget
- Docker & Docker Compose installed
- Running Homepage instance
- Domains you want to monitor
Step 1: Create Container Directory
mkdir -p /path/to/containers/domain-expiry
cd /path/to/containers/domain-expiryStep 2: Download compose.yml
Download the compose.yml file:
wget https://raw.githubusercontent.com/Hackpig1974/domain-expiry/main/domain-expiry/compose.yml
# or
curl -O https://raw.githubusercontent.com/Hackpig1974/domain-expiry/main/domain-expiry/compose.ymlStep 3: Pull the Docker Image
docker compose pullStep 4: Create Configuration File
Download the example and rename it:
wget https://raw.githubusercontent.com/Hackpig1974/domain-expiry/main/domain-expiry/.env.example -O .envOr create .env manually:
nano .envAdd your configuration:
DOMAINS=example.com,google.com,github.com
RDAP_BASE=https://rdap.org/domain
WHOIS_FALLBACK_ENABLED=false
WHOISXML_API_KEY=YOUR_API_KEY
ALERT_DAYS=183
REFRESH_MINUTES=360
TZ=America/DenverStep 5: Start the Container
docker compose up -dStep 6: Verify it's Running
# Check container status
docker ps | grep domain-expiry
# Health check
curl http://localhost:8088/healthz
# Get domain status
curl http://localhost:8088/statusStep 1: Create Container Directory
mkdir -p /path/to/containers/domain-expiry
cd /path/to/containers/domain-expiryStep 2: Pull the Docker Image
Choose either registry:
# Option 1: Docker Hub (Recommended)
docker pull damon1974/domain-expiry:latest
# Option 2: GitHub Container Registry
docker pull ghcr.io/hackpig1974/domain-expiry:latestStep 3: Create Configuration File
Download the example:
wget https://raw.githubusercontent.com/Hackpig1974/domain-expiry/main/domain-expiry/.env.example -O .envEdit with your settings:
nano .envStep 4: Run the Container
docker run -d \
--name domain-expiry \
--env-file .env \
-p 8088:8000 \
--restart unless-stopped \
ghcr.io/hackpig1974/domain-expiry:latestStep 5: Verify it's Running
# Check container status
docker ps | grep domain-expiry
# View logs
docker logs domain-expiry
# Health check
curl http://localhost:8088/healthz
# Get domain status
curl http://localhost:8088/statusDocker Compose:
cd /path/to/containers/domain-expiry
docker compose pull
docker compose up -dDocker CLI:
docker pull ghcr.io/hackpig1974/domain-expiry:latest
docker stop domain-expiry
docker rm domain-expiry
# Re-run the docker run command from Step 4 aboveContainer won't start:
# Check logs
docker logs domain-expiry
# Common issues:
# - Missing required .env variables (DOMAINS, RDAP_BASE, ALERT_DAYS)
# - Port 8088 already in use (change to different port)
# - Invalid domain format in DOMAINS variableCan't access the API:
# Verify container is running
docker ps | grep domain-expiry
# Check if port is accessible
curl http://localhost:8088/healthz
# If using a different host, replace localhost with server IP
curl http://YOUR_SERVER_IP:8088/healthzDomains showing "n/a":
# Check logs for specific errors
docker logs domain-expiry -f
# Force refresh cache
curl "http://localhost:8088/status?force=true"
# See Configuration section for fallback optionsOnce the container is running, add it to your Homepage dashboard:
Step 1: Edit Homepage services.yaml
# Location depends on your Homepage setup
nano /path/to/homepage/config/services.yamlStep 2: Add Domain Expiry Widget
- Domain Tools:
- Domain Expirations:
icon: mdi-web
widget:
type: customapi
url: http://YOUR_SERVER_IP:8088/status
display: dynamic-list
refreshInterval: 900000 # 15 minutes (in milliseconds)
mappings:
items: domains
name: domain
label: labelImportant: Replace YOUR_SERVER_IP with:
- Docker host IP address (e.g.,
192.168.1.100) if Homepage is in a different container localhostor127.0.0.1if Homepage is on the same host- Container name
domain-expiryif on the same Docker network
Step 3: Restart Homepage
# If using Docker Compose
docker compose restart homepage
# If using Docker CLI
docker restart homepageStep 4: Verify Widget Appears
The widget should now show:
- List of domains being monitored
- Expiration dates in MM/DD/YYYY format
- Days remaining in parentheses
- π΄ Red alert emoji for domains expiring soon (within ALERT_DAYS threshold)
Example Widget Display:
Domain Expirations
ββ example.com β Exp: π΄ 01/15/2026 (23d)
ββ google.com β Exp: 09/14/2028 (997d)
ββ github.com β Exp: 10/09/2025 (291d)
If you prefer a simpler list format:
- Domain Tools:
- Domain Expirations:
icon: mdi-web
widget:
type: customapi
url: http://YOUR_SERVER_IP:8088/flat
display: list
refreshInterval: 900000
mappings:
- field: line1
- field: line2
- field: line3
# Add more lines as needed for each domainThis displays domains in a cleaner line-by-line format without JSON parsing.
| Variable | Required | Default | Description |
|---|---|---|---|
DOMAINS |
β Yes | - | Comma-separated list of domains to monitor |
RDAP_BASE |
β Yes | - | RDAP server URL (use https://rdap.org/domain) |
ALERT_DAYS |
β Yes | - | Show alert when days remaining β€ this value |
REFRESH_MINUTES |
No | 360 | Cache duration in minutes (6 hours) |
ALERT_EMOJI |
No | π΄ | Emoji to show for expiring domains |
TZ |
No | UTC | Timezone (e.g., America/New_York) |
WHOIS_FALLBACK_ENABLED |
No | false | Enable python-whois fallback (works for .uk/.ca/.fr/.io/.ai) |
WHOISXML_API_KEY |
No | - | WhoisXML API key for ALL TLDs including .bz (500 free/month) |
The service uses intelligent fallback to maximize domain coverage:
Tier 1: RDAP (Default)
- β Fast, free, no API key needed
- β Works for most major TLDs (.com, .net, .org, .io, etc.)
- β Best option for common domains
Tier 2: python-whois (Optional)
- β‘ Free, no API key needed
- β‘ Enable with
WHOIS_FALLBACK_ENABLED=true - β‘ Works for: .uk, .ca, .fr, .io, .ai
- β‘ Limited TLD support (~41%)
Tier 3: WhoisXML API (Optional)
- π Works for ALL 7,500+ TLDs including .bz, .ai, .de, .au, .nz
- π 500 free requests/month (plenty for homelab use)
- π Requires free API key from WhoisXML API
- π― Solves ccTLD problems that RDAP doesn't support yet
How It Works:
- Try RDAP (Tier 1) first
- If RDAP fails and
WHOIS_FALLBACK_ENABLED=true, try python-whois (Tier 2) - If python-whois fails and
WHOISXML_API_KEYis set, try WhoisXML API (Tier 3) - If all fail: show "n/a"
Example Configuration for Maximum Coverage:
DOMAINS=example.com,gov.bz,mysite.uk
RDAP_BASE=https://rdap.org/domain
WHOIS_FALLBACK_ENABLED=true # Enable Tier 2
WHOISXML_API_KEY=your-api-key-here # Enable Tier 3
ALERT_DAYS=183With this setup:
- Common domains (.com, .org) use fast RDAP
- .uk domains fall back to python-whois (fast, free)
- .bz domains fall back to WhoisXML API (works but counts against free quota)
Get WhoisXML API Key:
- Sign up at https://whoisxmlapi.com (free account)
- Get 500 free requests/month automatically
- Copy your API key from dashboard
- Add to
.envfile:WHOISXML_API_KEY=your-key-here
High-Security Setup (check more frequently):
DOMAINS=banking.com,payment.com
ALERT_DAYS=90
REFRESH_MINUTES=60 # 1 hourPersonal Domains (longer cache):
DOMAINS=myblog.com,portfolio.io,family.name
ALERT_DAYS=183
REFRESH_MINUTES=720 # 12 hours-
Check Container Logs
docker logs domain-expiry
-
Verify API is Accessible
curl http://YOUR_IP:8088/status
-
Test Individual Domain
curl "https://rdap.org/domain/example.com"
- Force Refresh:
curl "http://YOUR_IP:8088/status?force=true" - Reduce Cache: Lower
REFRESH_MINUTESin.env - Restart Container:
docker compose restart
Some domains/TLDs don't provide expiration data via RDAP. The 3-tier fallback system can help!
Quick Fix for ccTLDs (like .bz, .nz, .au):
-
Get a free WhoisXML API key:
- Sign up at https://whoisxmlapi.com
- 500 free requests/month (plenty for homelab)
- Copy your API key
-
Add to
.env:WHOISXML_API_KEY=your-key-here
-
Restart:
docker compose restart
-
Verify logs:
docker logs domain-expiry # Should see: "WhoisXML API lookup successful for domain.bz"
Alternative for some TLDs (.uk, .ca, .fr, .io, .ai):
WHOIS_FALLBACK_ENABLED=trueThis works without an API key but has limited TLD support.
TLD Support Summary:
- β Most TLDs: RDAP (Tier 1, no key needed)
- β .uk, .ca, .fr, .io, .ai: python-whois (Tier 2, no key needed)
- β .bz, .nz, .au, .de, .jp and 7,500+ others: WhoisXML API (Tier 3, free key)
-
Use Host IP, Not localhost
- β
http://localhost:8088 - β
http://192.168.1.100:8088
- β
-
Check Docker Network
docker network inspect bridge
-
Verify Port is Open
netstat -tulpn | grep 8088
- π Don't expose port 8088 to the internet
- π‘οΈ Run behind reverse proxy with auth if needed
- π No sensitive data is stored
- π RDAP queries don't require authentication
- π Monitor 10-20 domains max per instance
- β±οΈ Keep cache at 6+ hours to respect RDAP servers
- π Use CDN RDAP (
rdap.org) for best performance - πΎ Container uses minimal resources (~50MB RAM)
- π Update container regularly:
docker compose pull && docker compose up -d - π Review alert threshold quarterly
- π§Ή Check logs occasionally:
docker logs domain-expiry --tail 100
Q: Can I monitor subdomains?
A: No - expiration is tracked at the domain level only. Subdomains inherit the parent domain's expiration.
Q: What about private/internal domains?
A: RDAP only works for publicly registered domains. Internal domains won't work.
Q: Can I use multiple RDAP providers?
A: Currently no, but you could run multiple instances with different providers.
Q: Why 6 hour cache?
A: Domain expiry dates change rarely. Shorter cache = unnecessary load on RDAP servers.
Q: Can I get notifications?
A: Not yet - see roadmap below. For now, Homepage is your notification.
Q: Does this work with Homepage v0.8.x?
A: Yes! The customapi widget has been available for a long time.
Q: How many domains can I monitor?
A: Tested up to 50. More than that, consider multiple instances or longer cache times.
Contributions welcome! Ideas:
- Report Issues - Found a bug? Open an issue
- Feature Requests - Have an idea? Start a discussion
- Code - PRs welcome for features or fixes
- Documentation - Improve README, add examples
- Testing - Test with different TLDs and report back
- Homepage - The dashboard this integrates with
- RDAP - Domain registration data protocol
- WhoisXML API - Universal WHOIS data provider
GPL-3.0 License - see LICENSE file
- Homepage team for excellent dashboard & customapi widget
- RDAP.org for free RDAP meta-service
- WhoisXML API for solving ccTLD coverage
- FastAPI for the awesome Python framework
- π Open an Issue
- π¬ Discussions
- β Star this repo if you find it useful!
Made with β€οΈ for the homelab community
