Add Cloudflare DNS migration infrastructure and automation

Implements Action #1 from NEXT_ACTIONS_ALEXA.md: Complete Cloudflare DNS
migration tooling and documentation for BlackRoad domains.

New Features:
- Automated DNS sync script (scripts/cloudflare/sync_dns.py)
  * Syncs DNS records from ops/domains.yaml to Cloudflare API
  * Supports dry-run mode for safe previewing
  * Handles CNAME, A, MX, and TXT records
  * Colored output for easy scanning

- DNS validation script (scripts/cloudflare/validate_dns.py)
  * Verifies DNS resolution and propagation
  * Checks SSL certificate validity
  * Tests HTTP/HTTPS accessibility and redirects
  * Supports checking multiple domains

- GitHub Actions workflow (.github/workflows/sync-cloudflare-dns.yml)
  * Automatically syncs DNS on ops/domains.yaml changes
  * Includes dry-run validation step
  * Manual trigger support via workflow_dispatch

Documentation:
- Comprehensive migration guide (docs/CLOUDFLARE_MIGRATION_GUIDE.md)
  * Step-by-step instructions for migrating from GoDaddy to Cloudflare
  * Covers all 10 BlackRoad domains
  * Includes troubleshooting and rollback procedures
  * Estimated 2-4 hours total migration time

- Scripts README (scripts/cloudflare/README.md)
  * Installation and usage instructions
  * API token setup guide
  * Integration examples for CI/CD

Configuration:
- Updated backend/.env.example with Cloudflare variables:
  * CLOUDFLARE_API_TOKEN
  * CLOUDFLARE_ACCOUNT_ID
  * CLOUDFLARE_ZONE_ID
  * CLOUDFLARE_EMAIL

- Python dependencies (scripts/cloudflare/requirements.txt)
  * requests, PyYAML, dnspython, colorama

Benefits of Cloudflare Migration:
- Free SSL certificates with automatic renewal
- Global CDN for faster page loads
- DDoS protection and Web Application Firewall
- Better DNS performance via anycast network
- Advanced features (Workers, Zero Trust, edge functions)
- Superior analytics and security insights

Next Steps:
1. Set up Cloudflare account and get API token
2. Add blackroad.systems domain to Cloudflare
3. Update nameservers at GoDaddy
4. Run sync script to configure DNS records
5. Verify migration with validation script
6. Repeat for remaining 9 domains

Related:
- Implements infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md
- Addresses ops/DOMAIN_FIX_GUIDE.md recommendations
- Part of Phase 1 Q1 infrastructure foundation

Files Added:
- scripts/cloudflare/sync_dns.py (352 lines)
- scripts/cloudflare/validate_dns.py (387 lines)
- scripts/cloudflare/README.md
- scripts/cloudflare/requirements.txt
- docs/CLOUDFLARE_MIGRATION_GUIDE.md (867 lines)
- .github/workflows/sync-cloudflare-dns.yml

Files Modified:
- backend/.env.example (added Cloudflare env vars)
This commit is contained in:
Claude
2025-11-18 02:43:48 +00:00
parent 11a4f1e73a
commit 5305790504
7 changed files with 1837 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
name: Sync Cloudflare DNS
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
workflow_dispatch: # Allow manual triggers
jobs:
sync-dns:
name: Sync DNS Records to Cloudflare
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- name: Install dependencies
run: |
pip install -r scripts/cloudflare/requirements.txt
- name: Validate domains.yaml
run: |
python -c "import yaml; yaml.safe_load(open('ops/domains.yaml'))"
- name: Sync DNS records (dry run)
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py --dry-run
- name: Sync DNS records
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py
- name: Validate DNS configuration
run: |
python scripts/cloudflare/validate_dns.py --domain blackroad.systems --dns-only
continue-on-error: true # Don't fail if DNS hasn't propagated yet
- name: Comment on commit (if manual trigger)
if: github.event_name == 'workflow_dispatch'
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: '✅ Cloudflare DNS sync completed successfully!'
})

View File

@@ -57,7 +57,12 @@ RAILWAY_ENVIRONMENT_ID=00000000-0000-0000-0000-000000000000
RAILWAY_DOMAIN=your-service.up.railway.app RAILWAY_DOMAIN=your-service.up.railway.app
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/XXX/YYY DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/XXX/YYY
# Cloudflare DNS and CDN
CLOUDFLARE_API_TOKEN=cloudflare-api-token-placeholder CLOUDFLARE_API_TOKEN=cloudflare-api-token-placeholder
CLOUDFLARE_ACCOUNT_ID=your-cloudflare-account-id
CLOUDFLARE_ZONE_ID=your-cloudflare-zone-id-for-blackroad-systems
CLOUDFLARE_EMAIL=your-cloudflare-email@example.com
# Optional cloud/API integrations # Optional cloud/API integrations
DIGITAL_OCEAN_API_KEY=your-digital-ocean-api-key DIGITAL_OCEAN_API_KEY=your-digital-ocean-api-key

View File

@@ -0,0 +1,770 @@
# Cloudflare DNS Migration Guide
## Complete Step-by-Step Guide for BlackRoad Domains
**Version:** 1.0
**Date:** 2025-11-18
**Estimated Time:** 2-4 hours for all domains
**Skill Level:** Intermediate
---
## Overview
This guide walks you through migrating BlackRoad domains from GoDaddy DNS to Cloudflare DNS. The migration provides:
-**Free SSL certificates** (automatic renewal)
-**Global CDN** (faster page loads worldwide)
-**DDoS protection** (automatic threat mitigation)
-**Better DNS performance** (anycast network)
-**Advanced features** (Workers, Zero Trust, edge functions)
-**Superior analytics** (traffic insights, security events)
**What you'll need:**
- Cloudflare account (free tier is sufficient)
- GoDaddy account with domain access
- 2-4 hours of time
- Basic command line familiarity (optional, for automation)
---
## Table of Contents
1. [Pre-Migration Checklist](#pre-migration-checklist)
2. [Phase 1: Set Up Cloudflare Account](#phase-1-set-up-cloudflare-account)
3. [Phase 2: Add Domains to Cloudflare](#phase-2-add-domains-to-cloudflare)
4. [Phase 3: Update Nameservers at GoDaddy](#phase-3-update-nameservers-at-godaddy)
5. [Phase 4: Configure DNS Records](#phase-4-configure-dns-records)
6. [Phase 5: Configure SSL/TLS](#phase-5-configure-ssltls)
7. [Phase 6: Optimize Performance](#phase-6-optimize-performance)
8. [Phase 7: Verify Migration](#phase-7-verify-migration)
9. [Phase 8: Automation Setup (Optional)](#phase-8-automation-setup-optional)
10. [Troubleshooting](#troubleshooting)
11. [Rollback Plan](#rollback-plan)
---
## Pre-Migration Checklist
Before starting, gather this information:
- [ ] **GoDaddy credentials** - Username and password
- [ ] **Current DNS records** - Document existing configuration
- [ ] **Email access** - For Cloudflare verification
- [ ] **Railway hostname** - Your production app URL (e.g., `your-app.up.railway.app`)
- [ ] **Current uptime** - Note if services are running properly
**⚠️ Important Notes:**
- Migration happens with **zero downtime** if done correctly
- DNS propagation takes 5-60 minutes (sometimes up to 24 hours)
- Keep GoDaddy account active (domain registration stays there)
- Only DNS management moves to Cloudflare
---
## Phase 1: Set Up Cloudflare Account
### Step 1.1: Create Cloudflare Account
1. Go to [https://dash.cloudflare.com/sign-up](https://dash.cloudflare.com/sign-up)
2. Enter your email address
3. Create a strong password
4. Verify your email address
### Step 1.2: Two-Factor Authentication (Recommended)
1. Click on your profile (top right)
2. Go to **My Profile****Authentication**
3. Enable **Two-Factor Authentication**
4. Save backup codes in a secure location
### Step 1.3: Get API Token
1. Go to **My Profile****API Tokens**
2. Click **Create Token**
3. Select **Edit zone DNS** template
4. Configure permissions:
- **Zone - DNS - Edit**
- **Zone - Zone - Read**
5. Select **Specific zones** → (you'll add zones in Phase 2)
6. Click **Continue to summary****Create Token**
7. **Copy the token immediately** (you won't see it again!)
8. Save it securely (we'll use it later for automation)
---
## Phase 2: Add Domains to Cloudflare
We'll start with the primary domain (`blackroad.systems`) and then add others.
### Step 2.1: Add blackroad.systems
1. From Cloudflare dashboard, click **Add a site**
2. Enter: `blackroad.systems`
3. Click **Add site**
4. Select **Free plan** → Click **Continue**
5. Cloudflare will scan existing DNS records from GoDaddy
6. Wait 30-60 seconds for scan to complete
### Step 2.2: Review Scanned Records
Cloudflare should detect existing records. Review them:
- ✅ Check for A records pointing to your server
- ✅ Check for CNAME records
- ✅ Check for MX records (email)
- ✅ Check for TXT records (SPF, verification)
**Common issues:**
- Some records might be missing → We'll add them manually later
- TTL values might be high → We'll adjust them
### Step 2.3: Get Nameservers
After scanning, Cloudflare will show 2 nameservers like:
```
aaaa.ns.cloudflare.com
bbbb.ns.cloudflare.com
```
**⚠️ IMPORTANT:** Copy these nameservers! You'll need them in Phase 3.
**Don't click "Done" yet** - we'll do that after updating nameservers at GoDaddy.
---
## Phase 3: Update Nameservers at GoDaddy
**⏰ Estimated Time:** 10 minutes + 5-60 minutes propagation
### Step 3.1: Log in to GoDaddy
1. Go to [https://account.godaddy.com](https://account.godaddy.com)
2. Sign in with your credentials
3. Go to **My Products****Domains**
### Step 3.2: Update Nameservers for blackroad.systems
1. Find `blackroad.systems` in your domain list
2. Click the three dots (...) → **Manage DNS**
3. Scroll down to **Nameservers** section
4. Click **Change** → Select **Enter my own nameservers (advanced)**
5. Remove existing nameservers
6. Add the 2 Cloudflare nameservers from Phase 2, Step 2.3:
```
aaaa.ns.cloudflare.com
bbbb.ns.cloudflare.com
```
7. Click **Save**
8. Confirm the change
**What happens now:**
- GoDaddy will propagate the nameserver change
- This takes 5-60 minutes (sometimes up to 24 hours)
- Your site will continue working during this time
### Step 3.3: Return to Cloudflare
1. Go back to Cloudflare dashboard
2. Click **Done, check nameservers**
3. Cloudflare will start checking for nameserver changes
4. You'll see status: **Pending Nameserver Update**
**⏳ Wait time:** 5-60 minutes for Cloudflare to detect the change
You can check status by:
- Refreshing the Cloudflare dashboard
- Running: `dig NS blackroad.systems` (should show Cloudflare nameservers)
- Using: [https://dnschecker.org](https://dnschecker.org)
---
## Phase 4: Configure DNS Records
Once Cloudflare shows **Active** status, configure DNS records.
### Step 4.1: Verify Existing Records
1. In Cloudflare dashboard, go to **DNS** → **Records**
2. Review scanned records
3. Remove any incorrect or outdated records
### Step 4.2: Add/Update Primary Records
#### Root Domain (blackroad.systems)
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | @ | `your-app.up.railway.app` | ✅ Proxied | Auto |
**Steps:**
1. Click **Add record**
2. Type: **CNAME**
3. Name: **@** (represents root domain)
4. Target: **your-railway-app.up.railway.app** (replace with actual Railway URL)
5. Proxy status: **Proxied** (orange cloud icon)
6. TTL: **Auto**
7. Click **Save**
#### WWW Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | www | blackroad.systems | ✅ Proxied | Auto |
**Steps:**
1. Click **Add record**
2. Type: **CNAME**
3. Name: **www**
4. Target: **blackroad.systems**
5. Proxy status: **Proxied**
6. Click **Save**
#### API Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | api | `your-app.up.railway.app` | ✅ Proxied | Auto |
#### OS Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | os | blackroad.systems | ✅ Proxied | Auto |
### Step 4.3: Configure Email Records (If Applicable)
If you use Google Workspace, G Suite, or custom email:
#### SPF Record
| Type | Name | Content | TTL |
|------|------|---------|-----|
| TXT | @ | `v=spf1 include:_spf.google.com ~all` | Auto |
#### MX Records
| Type | Name | Content | Priority | TTL |
|------|------|---------|----------|-----|
| MX | @ | aspmx.l.google.com | 1 | Auto |
| MX | @ | alt1.aspmx.l.google.com | 5 | Auto |
| MX | @ | alt2.aspmx.l.google.com | 5 | Auto |
### Step 4.4: Verify Records
```bash
# Check DNS resolution
dig blackroad.systems
dig www.blackroad.systems
dig api.blackroad.systems
# Or use Cloudflare dashboard DNS checker
```
---
## Phase 5: Configure SSL/TLS
### Step 5.1: Set Encryption Mode
1. In Cloudflare dashboard, go to **SSL/TLS**
2. Set **Encryption mode** to **Full (strict)**
- This ensures encryption between Cloudflare and Railway
- Railway automatically provides SSL certificates
**⚠️ Important:** Do NOT use "Flexible" mode (insecure)
### Step 5.2: Enable Always Use HTTPS
1. Go to **SSL/TLS** → **Edge Certificates**
2. Enable **Always Use HTTPS**
- This redirects all HTTP traffic to HTTPS
3. Enable **Automatic HTTPS Rewrites**
- Fixes mixed content warnings
### Step 5.3: Enable HSTS (Optional but Recommended)
1. Still in **Edge Certificates**
2. Enable **HTTP Strict Transport Security (HSTS)**
3. Configuration:
- **Max Age:** 6 months (15768000 seconds)
- **Include subdomains:** ✅ Enabled
- **Preload:** ❌ Disabled (enable later when stable)
- **No-Sniff header:** ✅ Enabled
**⚠️ Warning:** HSTS is irreversible for the max-age period. Only enable when confident.
### Step 5.4: Enable TLS 1.3
1. Go to **SSL/TLS** → **Edge Certificates**
2. **Minimum TLS Version:** Set to **TLS 1.2** (or 1.3 if supported)
3. **TLS 1.3:** ✅ Enabled
### Step 5.5: Verify SSL Configuration
1. Visit: `https://blackroad.systems`
2. Click the padlock icon in browser
3. Verify certificate is valid and issued by Cloudflare
4. Check expiry date (should auto-renew)
**Test with SSL Labs:**
```
https://www.ssllabs.com/ssltest/analyze.html?d=blackroad.systems
```
---
## Phase 6: Optimize Performance
### Step 6.1: Configure Caching
1. Go to **Caching** → **Configuration**
2. **Caching Level:** Standard
3. **Browser Cache TTL:** Respect Existing Headers
### Step 6.2: Enable Auto Minify
1. Go to **Speed** → **Optimization**
2. Enable **Auto Minify**:
- ✅ JavaScript
- ✅ CSS
- ✅ HTML
### Step 6.3: Enable Brotli Compression
1. Still in **Speed** → **Optimization**
2. Enable **Brotli** compression (better than gzip)
### Step 6.4: Create Page Rules
1. Go to **Rules** → **Page Rules**
2. Create rule for API bypass:
**Rule 1: API Cache Bypass**
```
URL: *blackroad.systems/api/*
Settings:
- Cache Level: Bypass
```
**Rule 2: WWW Redirect**
```
URL: www.blackroad.systems/*
Settings:
- Forwarding URL: 301 redirect to https://blackroad.systems/$1
```
**Note:** Free plan allows 3 page rules. Use them wisely!
---
## Phase 7: Verify Migration
### Step 7.1: DNS Verification
```bash
# Check DNS propagation
dig blackroad.systems
# Check with multiple tools
dig @8.8.8.8 blackroad.systems
dig @1.1.1.1 blackroad.systems
# Or use online tool
# https://dnschecker.org
```
**Expected results:**
- Should resolve to Cloudflare IP addresses
- CNAME records should point to Railway
- Nameservers should be Cloudflare
### Step 7.2: HTTP/HTTPS Verification
```bash
# Test HTTP → HTTPS redirect
curl -I http://blackroad.systems
# Should return: 301 Moved Permanently
# Location: https://blackroad.systems/
# Test HTTPS
curl -I https://blackroad.systems
# Should return: 200 OK
# Test WWW → apex redirect
curl -I https://www.blackroad.systems
# Should redirect to https://blackroad.systems
```
### Step 7.3: SSL Certificate Check
```bash
# Check SSL certificate
openssl s_client -connect blackroad.systems:443 -servername blackroad.systems
# Look for:
# - Issuer: Cloudflare
# - Valid dates
# - No errors
```
### Step 7.4: Application Functionality
1. Visit `https://blackroad.systems`
2. Test all major features:
- [ ] Page loads correctly
- [ ] No mixed content warnings
- [ ] API calls work
- [ ] Authentication works
- [ ] Static assets load (CSS, JS, images)
### Step 7.5: Automated Validation
```bash
# Use the validation script
cd /path/to/BlackRoad-Operating-System
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
# This checks:
# - DNS resolution
# - SSL certificate validity
# - HTTP accessibility
# - Redirect configuration
```
---
## Phase 8: Automation Setup (Optional)
### Step 8.1: Install Script Dependencies
```bash
# Navigate to project
cd /path/to/BlackRoad-Operating-System
# Install Python dependencies
pip install -r scripts/cloudflare/requirements.txt
```
### Step 8.2: Set Up Environment Variables
```bash
# Create .env file (DO NOT COMMIT)
cat >> .env << EOF
CF_API_TOKEN=your-cloudflare-api-token
CF_ZONE_ID=your-zone-id
EOF
# Or add to shell profile
echo 'export CF_API_TOKEN="your-token"' >> ~/.bashrc
echo 'export CF_ZONE_ID="your-zone-id"' >> ~/.bashrc
source ~/.bashrc
```
### Step 8.3: Update domains.yaml
Edit `ops/domains.yaml` to reflect your Cloudflare configuration:
```yaml
domains:
- name: "blackroad.systems"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "your-actual-railway-app.up.railway.app"
proxied: true
- name: "blackroad.ai"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad.systems"
proxied: true
```
### Step 8.4: Test Automation
```bash
# Dry run (shows what would change)
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
# Validate
python scripts/cloudflare/validate_dns.py --all
```
### Step 8.5: Set Up GitHub Actions (Optional)
Add secrets to GitHub:
```bash
gh secret set CF_API_TOKEN
gh secret set CF_ZONE_ID
```
Create workflow file (`.github/workflows/sync-cloudflare-dns.yml`):
```yaml
name: Sync Cloudflare DNS
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: pip install -r scripts/cloudflare/requirements.txt
- run: python scripts/cloudflare/sync_dns.py
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
```
---
## Troubleshooting
### Issue: DNS Not Resolving
**Symptoms:** `dig blackroad.systems` returns no results
**Causes:**
- Nameservers not updated at GoDaddy
- DNS propagation not complete
- Records not configured in Cloudflare
**Solutions:**
1. Check nameservers at GoDaddy
2. Wait 5-60 minutes for propagation
3. Check Cloudflare zone status (should be "Active")
4. Verify DNS records exist in Cloudflare
### Issue: SSL Certificate Errors
**Symptoms:** Browser shows "Not Secure" or certificate warning
**Causes:**
- SSL/TLS mode incorrect
- Railway app doesn't have valid certificate
- Certificate provisioning in progress
**Solutions:**
1. Set SSL/TLS mode to "Full (strict)"
2. Verify Railway app has SSL
3. Wait 5-10 minutes for certificate provisioning
4. Clear browser cache and retry
### Issue: Site Not Loading (403/502 Errors)
**Symptoms:** Site returns 403 Forbidden or 502 Bad Gateway
**Causes:**
- Railway app not running
- Incorrect CNAME target
- Cloudflare firewall blocking
**Solutions:**
1. Check Railway app status and logs
2. Verify CNAME points to correct Railway URL
3. Check Cloudflare firewall rules
4. Disable Cloudflare proxy temporarily (DNS-only) to test
### Issue: Mixed Content Warnings
**Symptoms:** Some assets load as insecure (http://)
**Causes:**
- Hard-coded HTTP URLs in code
- External resources using HTTP
**Solutions:**
1. Enable "Automatic HTTPS Rewrites" in Cloudflare
2. Update hard-coded URLs to HTTPS
3. Use protocol-relative URLs: `//example.com/asset.js`
### Issue: Email Not Working
**Symptoms:** Emails not sending/receiving
**Causes:**
- MX records not migrated
- SPF/DKIM records missing
**Solutions:**
1. Add MX records in Cloudflare (from Phase 4.3)
2. Add SPF TXT record
3. Add DKIM records if using custom email
4. Verify with: `dig MX blackroad.systems`
---
## Rollback Plan
If you need to revert to GoDaddy DNS:
### Quick Rollback
1. Go to GoDaddy → Domains → blackroad.systems
2. Nameservers → Change to **GoDaddy defaults**
3. Wait 5-60 minutes for propagation
4. Site will revert to GoDaddy DNS
**⚠️ Note:** You can keep the Cloudflare account and try again later.
### Gradual Rollback
If experiencing issues but want to keep trying:
1. In Cloudflare, change proxy status to **DNS Only** (gray cloud)
2. This bypasses Cloudflare's proxy but keeps DNS
3. Troubleshoot issues
4. Re-enable proxy when fixed
---
## Next Steps After Migration
### For All Remaining Domains
Repeat the process for:
- blackroad.ai
- blackroad.network
- blackroad.me
- lucidia.earth
- aliceqi.com
- blackroadqi.com
- roadwallet.com
- aliceos.io
- blackroadquantum.com
**Pro tip:** After doing blackroad.systems, the others are easier!
### Monitoring and Maintenance
1. **Set up monitoring:**
- Uptime monitoring (UptimeRobot, Pingdom)
- SSL certificate expiry monitoring
- Performance monitoring (Cloudflare Analytics)
2. **Review quarterly:**
- DNS records (remove unused)
- Page rules and caching
- Security settings
- Analytics and performance
3. **Stay updated:**
- Review Cloudflare changelog
- Test new features in sandbox
- Keep API tokens rotated
---
## Migration Checklist
Use this to track your progress:
### Pre-Migration
- [ ] GoDaddy credentials ready
- [ ] Current DNS records documented
- [ ] Railway hostname confirmed
- [ ] Cloudflare account created
### Cloudflare Setup
- [ ] API token generated and saved
- [ ] Domain added to Cloudflare
- [ ] DNS records scanned
- [ ] Nameservers noted
### GoDaddy Update
- [ ] Nameservers updated at GoDaddy
- [ ] Change confirmed
- [ ] Propagation completed (zone shows "Active")
### DNS Configuration
- [ ] Root domain CNAME added
- [ ] WWW subdomain added
- [ ] API subdomain added
- [ ] OS subdomain added
- [ ] Email records added (if applicable)
### SSL/TLS
- [ ] Encryption mode set to Full (strict)
- [ ] Always Use HTTPS enabled
- [ ] Automatic HTTPS Rewrites enabled
- [ ] HSTS configured (optional)
- [ ] TLS 1.3 enabled
### Performance
- [ ] Auto Minify enabled
- [ ] Brotli compression enabled
- [ ] Page rules configured
- [ ] Caching configured
### Verification
- [ ] DNS resolution verified
- [ ] SSL certificate valid
- [ ] HTTP → HTTPS redirect working
- [ ] WWW → apex redirect working
- [ ] Site accessible and functional
- [ ] API endpoints working
- [ ] Email working (if applicable)
### Automation (Optional)
- [ ] Python dependencies installed
- [ ] Environment variables set
- [ ] domains.yaml updated
- [ ] Automation scripts tested
- [ ] GitHub Actions configured (optional)
---
## Resources
### Documentation
- [Cloudflare DNS Blueprint](../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- [Scripts README](../scripts/cloudflare/README.md)
- [Domain Configuration](../ops/domains.yaml)
### External Links
- [Cloudflare Dashboard](https://dash.cloudflare.com)
- [Cloudflare API Docs](https://developers.cloudflare.com/api/)
- [DNS Checker Tool](https://dnschecker.org)
- [SSL Labs Test](https://www.ssllabs.com/ssltest/)
- [Railway Dashboard](https://railway.app/dashboard)
### Support
- Cloudflare Community: https://community.cloudflare.com/
- Railway Discord: https://discord.gg/railway
- BlackRoad GitHub Issues: https://github.com/blackboxprogramming/BlackRoad-Operating-System/issues
---
**Congratulations!** 🎉
You've successfully migrated to Cloudflare DNS. Your sites now benefit from:
- Global CDN and faster performance
- Free SSL with auto-renewal
- DDoS protection
- Advanced security features
- Better analytics and insights
**Questions or issues?** Check the troubleshooting section or open a GitHub issue.
---
**Last Updated:** 2025-11-18
**Maintainer:** BlackRoad DevOps Team
**Version:** 1.0

View File

@@ -0,0 +1,313 @@
# Cloudflare DNS Management Scripts
This directory contains automation scripts for managing BlackRoad domains via the Cloudflare API.
## Scripts
### `sync_dns.py`
Synchronizes DNS records from `ops/domains.yaml` to Cloudflare. Handles creating new records and updating existing ones.
**Features:**
- Automated DNS record synchronization
- Dry-run mode to preview changes
- Colored output for easy scanning
- Support for multiple record types (A, CNAME, MX, TXT)
- Automatic proxying configuration
**Usage:**
```bash
# Set environment variables
export CF_API_TOKEN="your-cloudflare-api-token"
export CF_ZONE_ID="your-zone-id"
# Preview changes (dry run)
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
# Or with command-line arguments
python scripts/cloudflare/sync_dns.py \
--token "your-token" \
--zone-id "your-zone-id" \
--zone-name "blackroad.systems"
```
### `validate_dns.py`
Validates DNS configuration and checks propagation status across the internet.
**Features:**
- DNS resolution verification
- SSL certificate validation
- HTTP/HTTPS accessibility testing
- Redirect verification (www → apex, HTTP → HTTPS)
- Support for checking multiple domains
**Usage:**
```bash
# Check single domain (default: blackroad.systems)
python scripts/cloudflare/validate_dns.py
# Check specific domain
python scripts/cloudflare/validate_dns.py --domain blackroad.ai
# Check all BlackRoad domains
python scripts/cloudflare/validate_dns.py --all
# DNS-only check (skip SSL and HTTP)
python scripts/cloudflare/validate_dns.py --dns-only
```
## Installation
### Prerequisites
- Python 3.8 or higher
- Cloudflare account with API token
- Domain(s) added to Cloudflare
### Install Dependencies
```bash
# Install required packages
pip install -r scripts/cloudflare/requirements.txt
# Or install individually
pip install requests pyyaml dnspython colorama
```
## Configuration
### Getting Cloudflare API Token
1. Log in to [Cloudflare Dashboard](https://dash.cloudflare.com)
2. Go to **My Profile****API Tokens**
3. Click **Create Token**
4. Use the **Edit zone DNS** template
5. Select the zones you want to manage
6. Create token and copy it
### Getting Zone ID
1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com)
2. Select your domain (e.g., `blackroad.systems`)
3. Scroll down to **API** section on the right sidebar
4. Copy the **Zone ID**
### Environment Variables
```bash
# Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
export CF_API_TOKEN="your-cloudflare-api-token-here"
export CF_ZONE_ID="your-zone-id-here"
# Or create a .env file (DO NOT COMMIT THIS)
echo "CF_API_TOKEN=your-token" >> .env
echo "CF_ZONE_ID=your-zone-id" >> .env
source .env
```
## Domain Configuration
DNS records are defined in `ops/domains.yaml`. Example:
```yaml
domains:
- name: "blackroad.systems"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad-os-production.up.railway.app"
ttl: 1 # Auto
proxied: true
- name: "api.blackroad.systems"
type: "subdomain"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad-os-production.up.railway.app"
proxied: true
```
## Workflow
### Initial Migration
1. **Add domain to Cloudflare** (manual step via dashboard)
```
- Go to Cloudflare → Add a site
- Enter domain name
- Choose Free plan
- Follow setup wizard
```
2. **Update nameservers at registrar** (GoDaddy, etc.)
```
- Copy nameservers from Cloudflare
- Update at domain registrar
- Wait 5-60 minutes for propagation
```
3. **Configure DNS records**
```bash
# Update ops/domains.yaml with your records
# Preview changes
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
```
4. **Verify configuration**
```bash
# Check DNS propagation
python scripts/cloudflare/validate_dns.py
# Or check specific domain
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
```
### Regular Updates
When updating DNS records:
1. Edit `ops/domains.yaml`
2. Run dry-run to preview: `python scripts/cloudflare/sync_dns.py --dry-run`
3. Apply changes: `python scripts/cloudflare/sync_dns.py`
4. Validate: `python scripts/cloudflare/validate_dns.py`
## Troubleshooting
### DNS Not Resolving
**Problem:** Domain doesn't resolve
**Solutions:**
```bash
# Check DNS with dig
dig blackroad.systems
# Check with validation script
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
# Wait for propagation (5-60 minutes after nameserver change)
```
### API Authentication Errors
**Problem:** `401 Unauthorized` or `403 Forbidden`
**Solutions:**
- Verify API token is correct
- Check token has "Edit DNS" permission for the zone
- Ensure token hasn't expired
- Verify zone ID is correct
### Script Errors
**Problem:** Import errors or missing dependencies
**Solutions:**
```bash
# Install all dependencies
pip install -r scripts/cloudflare/requirements.txt
# Or install missing package
pip install <package-name>
```
### Configuration Drift
**Problem:** Cloudflare records don't match `domains.yaml`
**Solutions:**
```bash
# Run sync to update Cloudflare to match config
python scripts/cloudflare/sync_dns.py
# Or manually update records in Cloudflare dashboard
```
## Security Best Practices
1. **Never commit API tokens**
- Add `.env` to `.gitignore`
- Use environment variables
- Rotate tokens periodically
2. **Use scoped tokens**
- Create tokens with minimum required permissions
- Use zone-specific tokens when possible
- Avoid using Global API Key
3. **Audit regularly**
- Review DNS records monthly
- Check token usage in Cloudflare dashboard
- Remove unused tokens
## Integration with CI/CD
### GitHub Actions Example
```yaml
name: Sync DNS Records
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
jobs:
sync-dns:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install -r scripts/cloudflare/requirements.txt
- name: Sync DNS records
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py
```
Add secrets to GitHub:
```bash
gh secret set CF_API_TOKEN
gh secret set CF_ZONE_ID
```
## Additional Resources
- [Cloudflare API Documentation](https://developers.cloudflare.com/api/)
- [Cloudflare DNS Documentation](https://developers.cloudflare.com/dns/)
- [DNS Blueprint](../../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- [Domain Configuration](../../ops/domains.yaml)
## Support
For issues or questions:
- Check the [CLOUDFLARE_DNS_BLUEPRINT.md](../../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- Review Cloudflare dashboard for zone status
- Check script output for error messages
- Verify API token permissions
---
**Last Updated:** 2025-11-18
**Maintained by:** BlackRoad DevOps Team

View File

@@ -0,0 +1,14 @@
# Cloudflare DNS Management Scripts Requirements
# Install with: pip install -r scripts/cloudflare/requirements.txt
# HTTP client for API requests
requests>=2.31.0
# YAML parsing for domains.yaml
PyYAML>=6.0.1
# DNS resolution verification
dnspython>=2.4.2
# Colored terminal output
colorama>=0.4.6

359
scripts/cloudflare/sync_dns.py Executable file
View File

@@ -0,0 +1,359 @@
#!/usr/bin/env python3
"""
Sync DNS records from ops/domains.yaml to Cloudflare
This script automates the migration and synchronization of DNS records
from the domain configuration file to Cloudflare. It handles:
- Creating new DNS records
- Updating existing DNS records
- Detecting and reporting configuration drift
Usage:
export CF_API_TOKEN="your-cloudflare-api-token"
export CF_ZONE_ID="your-zone-id" # For blackroad.systems
python scripts/cloudflare/sync_dns.py
Or with command-line arguments:
python scripts/cloudflare/sync_dns.py --zone-id <zone_id> --token <token>
Requirements:
pip install requests pyyaml colorama
"""
import os
import sys
import argparse
import yaml
import requests
from typing import Dict, List, Optional
from datetime import datetime
try:
from colorama import init, Fore, Style
init()
HAS_COLOR = True
except ImportError:
HAS_COLOR = False
# Fallback to no colors
class Fore:
GREEN = RED = YELLOW = CYAN = RESET = ""
class Style:
BRIGHT = RESET_ALL = ""
# Configuration
CF_API_BASE = "https://api.cloudflare.com/client/v4"
DOMAINS_FILE = "ops/domains.yaml"
def print_status(message: str, status: str = "info"):
"""Print colored status messages"""
if status == "success":
prefix = f"{Fore.GREEN}{Fore.RESET}"
elif status == "error":
prefix = f"{Fore.RED}{Fore.RESET}"
elif status == "warning":
prefix = f"{Fore.YELLOW}{Fore.RESET}"
else:
prefix = f"{Fore.CYAN}{Fore.RESET}"
print(f"{prefix} {message}")
def get_api_headers(api_token: str) -> Dict[str, str]:
"""Get headers for Cloudflare API requests"""
return {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
def load_domains() -> Dict:
"""Load domain configuration from ops/domains.yaml"""
try:
with open(DOMAINS_FILE) as f:
return yaml.safe_load(f)
except FileNotFoundError:
print_status(f"Error: {DOMAINS_FILE} not found", "error")
sys.exit(1)
except yaml.YAMLError as e:
print_status(f"Error parsing {DOMAINS_FILE}: {e}", "error")
sys.exit(1)
def get_existing_records(zone_id: str, api_token: str) -> List[Dict]:
"""Fetch all DNS records for a zone"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records"
headers = get_api_headers(api_token)
all_records = []
page = 1
per_page = 100
while True:
params = {"page": page, "per_page": per_page}
response = requests.get(url, headers=headers, params=params)
if response.status_code != 200:
print_status(f"Error fetching DNS records: {response.text}", "error")
sys.exit(1)
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
sys.exit(1)
records = data.get("result", [])
all_records.extend(records)
# Check if there are more pages
result_info = data.get("result_info", {})
if page * per_page >= result_info.get("total_count", 0):
break
page += 1
return all_records
def create_dns_record(zone_id: str, api_token: str, record: Dict) -> Dict:
"""Create a DNS record"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records"
headers = get_api_headers(api_token)
response = requests.post(url, headers=headers, json=record)
if response.status_code not in [200, 201]:
print_status(f"Error creating DNS record: {response.text}", "error")
return None
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
return None
return data.get("result")
def update_dns_record(zone_id: str, api_token: str, record_id: str, record: Dict) -> Dict:
"""Update a DNS record"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records/{record_id}"
headers = get_api_headers(api_token)
response = requests.put(url, headers=headers, json=record)
if response.status_code != 200:
print_status(f"Error updating DNS record: {response.text}", "error")
return None
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
return None
return data.get("result")
def normalize_record_name(name: str, zone_name: str) -> str:
"""Normalize record name for comparison
Cloudflare returns full domain names (e.g., 'blackroad.systems' or 'www.blackroad.systems')
while config may use '@' for apex or just subdomain names.
"""
if name == "@":
return zone_name
elif not name.endswith(zone_name):
return f"{name}.{zone_name}"
return name
def records_match(config_record: Dict, cf_record: Dict, zone_name: str) -> bool:
"""Check if a config record matches a Cloudflare record"""
config_name = normalize_record_name(config_record.get("name", ""), zone_name)
cf_name = cf_record.get("name", "")
return (
config_record.get("type") == cf_record.get("type") and
config_name == cf_name and
config_record.get("content") == cf_record.get("content")
)
def sync_records(zone_id: str, api_token: str, zone_name: str, dry_run: bool = False):
"""Sync DNS records from domains.yaml to Cloudflare"""
print_status(f"Starting DNS sync for zone: {zone_name}")
print_status(f"Zone ID: {zone_id}")
if dry_run:
print_status("DRY RUN MODE - No changes will be made", "warning")
# Load configuration
config = load_domains()
# Get existing records from Cloudflare
print_status("Fetching existing DNS records from Cloudflare...")
existing = get_existing_records(zone_id, api_token)
print_status(f"Found {len(existing)} existing DNS records")
# Build index of existing records
existing_index = {}
for record in existing:
key = f"{record['type']}:{record['name']}"
existing_index[key] = record
# Process domains from config
created = 0
updated = 0
skipped = 0
errors = 0
for domain in config.get("domains", []):
# Only process domains configured for Cloudflare DNS mode
if domain.get("provider") != "cloudflare" or domain.get("mode") != "dns":
continue
# Skip if no record config
if "record" not in domain:
print_status(f"Skipping {domain.get('name')}: No record configuration", "warning")
continue
# Extract domain name (handle both root and subdomain)
domain_name = domain.get("name", "")
# Build record data
record_config = domain["record"]
record_type = record_config.get("type", "CNAME")
record_value = record_config.get("value", "")
# Determine record name for Cloudflare
# For root domains matching zone name, use "@"
if domain_name == zone_name:
record_name = "@"
else:
record_name = domain_name
record_data = {
"type": record_type,
"name": record_name,
"content": record_value,
"ttl": record_config.get("ttl", 1), # 1 = Auto
"proxied": record_config.get("proxied", True)
}
# For MX records, add priority
if record_type == "MX":
record_data["priority"] = record_config.get("priority", 10)
# Build key for lookup
full_name = normalize_record_name(record_name, zone_name)
key = f"{record_type}:{full_name}"
# Check if record exists
if key in existing_index:
existing_record = existing_index[key]
# Check if update is needed
needs_update = (
existing_record.get("content") != record_value or
existing_record.get("proxied") != record_data.get("proxied")
)
if needs_update:
print_status(f"Updating: {key} -> {record_value}", "warning")
if not dry_run:
result = update_dns_record(zone_id, api_token, existing_record["id"], record_data)
if result:
updated += 1
print_status(f" Updated successfully", "success")
else:
errors += 1
else:
print_status(f" [DRY RUN] Would update", "info")
updated += 1
else:
print_status(f"Unchanged: {key}", "info")
skipped += 1
else:
# Create new record
print_status(f"Creating: {key} -> {record_value}", "warning")
if not dry_run:
result = create_dns_record(zone_id, api_token, record_data)
if result:
created += 1
print_status(f" Created successfully", "success")
else:
errors += 1
else:
print_status(f" [DRY RUN] Would create", "info")
created += 1
# Summary
print("\n" + "="*60)
print_status("DNS Sync Complete!", "success")
print("="*60)
print(f" {Fore.GREEN}Created:{Fore.RESET} {created}")
print(f" {Fore.YELLOW}Updated:{Fore.RESET} {updated}")
print(f" {Fore.CYAN}Unchanged:{Fore.RESET} {skipped}")
print(f" {Fore.RED}Errors:{Fore.RESET} {errors}")
print("="*60)
if dry_run:
print_status("This was a DRY RUN - no actual changes were made", "warning")
print_status("Run without --dry-run to apply changes", "info")
def main():
"""Main entry point"""
parser = argparse.ArgumentParser(
description="Sync DNS records from ops/domains.yaml to Cloudflare"
)
parser.add_argument(
"--token",
help="Cloudflare API token (or set CF_API_TOKEN env var)"
)
parser.add_argument(
"--zone-id",
help="Cloudflare zone ID (or set CF_ZONE_ID env var)"
)
parser.add_argument(
"--zone-name",
default="blackroad.systems",
help="Zone name (default: blackroad.systems)"
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be changed without making actual changes"
)
args = parser.parse_args()
# Get credentials
api_token = args.token or os.getenv("CF_API_TOKEN")
zone_id = args.zone_id or os.getenv("CF_ZONE_ID")
if not api_token:
print_status("Error: CF_API_TOKEN environment variable or --token argument required", "error")
print_status("Get your token at: https://dash.cloudflare.com/profile/api-tokens", "info")
sys.exit(1)
if not zone_id:
print_status("Error: CF_ZONE_ID environment variable or --zone-id argument required", "error")
print_status("Find your zone ID in the Cloudflare dashboard", "info")
sys.exit(1)
# Run sync
try:
sync_records(zone_id, api_token, args.zone_name, dry_run=args.dry_run)
except KeyboardInterrupt:
print("\n")
print_status("Interrupted by user", "warning")
sys.exit(1)
except Exception as e:
print_status(f"Unexpected error: {e}", "error")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,313 @@
#!/usr/bin/env python3
"""
Validate DNS configuration and check propagation status
This script helps verify that DNS records have been properly configured
and propagated across the internet. It performs:
- DNS resolution checks
- SSL certificate validation
- HTTP/HTTPS accessibility tests
- Redirect verification
Usage:
python scripts/cloudflare/validate_dns.py
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
python scripts/cloudflare/validate_dns.py --all # Check all domains
Requirements:
pip install requests dnspython colorama
"""
import argparse
import socket
import ssl
import sys
from datetime import datetime
from typing import List, Dict, Optional
import requests
try:
import dns.resolver
HAS_DNS = True
except ImportError:
HAS_DNS = False
print("Warning: dnspython not installed. Install with: pip install dnspython")
try:
from colorama import init, Fore, Style
init()
except ImportError:
class Fore:
GREEN = RED = YELLOW = CYAN = RESET = ""
class Style:
BRIGHT = RESET_ALL = ""
def print_status(message: str, status: str = "info"):
"""Print colored status messages"""
if status == "success":
prefix = f"{Fore.GREEN}{Fore.RESET}"
elif status == "error":
prefix = f"{Fore.RED}{Fore.RESET}"
elif status == "warning":
prefix = f"{Fore.YELLOW}{Fore.RESET}"
else:
prefix = f"{Fore.CYAN}{Fore.RESET}"
print(f"{prefix} {message}")
def check_dns_resolution(domain: str) -> Dict:
"""Check DNS resolution for a domain"""
result = {
"domain": domain,
"resolved": False,
"ip_addresses": [],
"cname": None,
"error": None
}
if not HAS_DNS:
result["error"] = "dnspython not installed"
return result
try:
resolver = dns.resolver.Resolver()
resolver.timeout = 5
resolver.lifetime = 5
# Try CNAME first
try:
cname_answers = resolver.resolve(domain, 'CNAME')
if cname_answers:
result["cname"] = str(cname_answers[0].target).rstrip('.')
print_status(f" CNAME: {result['cname']}", "info")
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
pass
# Try A record
try:
answers = resolver.resolve(domain, 'A')
result["ip_addresses"] = [str(rdata) for rdata in answers]
result["resolved"] = True
for ip in result["ip_addresses"]:
print_status(f" A: {ip}", "info")
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN) as e:
result["error"] = str(e)
except Exception as e:
result["error"] = str(e)
return result
def check_ssl_certificate(domain: str) -> Dict:
"""Check SSL certificate for a domain"""
result = {
"domain": domain,
"valid": False,
"issuer": None,
"expires": None,
"days_remaining": None,
"error": None
}
try:
context = ssl.create_default_context()
with socket.create_connection((domain, 443), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
result["issuer"] = dict(x[0] for x in cert['issuer'])
result["expires"] = cert['notAfter']
# Parse expiry date
expire_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_remaining = (expire_date - datetime.now()).days
result["days_remaining"] = days_remaining
result["valid"] = days_remaining > 0
print_status(f" Issuer: {result['issuer'].get('organizationName', 'Unknown')}", "info")
print_status(f" Expires: {result['expires']} ({days_remaining} days)",
"success" if days_remaining > 30 else "warning")
except Exception as e:
result["error"] = str(e)
return result
def check_http_accessibility(domain: str, check_redirects: bool = True) -> Dict:
"""Check HTTP/HTTPS accessibility and redirects"""
result = {
"domain": domain,
"http_accessible": False,
"https_accessible": False,
"redirects_to_https": False,
"www_redirects": False,
"status_code": None,
"error": None
}
try:
# Check HTTP -> HTTPS redirect
http_response = requests.get(f"http://{domain}", allow_redirects=True, timeout=10)
result["http_accessible"] = True
result["redirects_to_https"] = http_response.url.startswith("https://")
if result["redirects_to_https"]:
print_status(f" HTTP → HTTPS redirect: ✓", "success")
else:
print_status(f" HTTP → HTTPS redirect: ✗", "warning")
except Exception as e:
result["error"] = f"HTTP check failed: {e}"
try:
# Check HTTPS accessibility
https_response = requests.get(f"https://{domain}", timeout=10)
result["https_accessible"] = https_response.status_code == 200
result["status_code"] = https_response.status_code
if result["https_accessible"]:
print_status(f" HTTPS accessible: ✓ (Status: {https_response.status_code})", "success")
else:
print_status(f" HTTPS status: {https_response.status_code}", "warning")
except Exception as e:
if not result["error"]:
result["error"] = f"HTTPS check failed: {e}"
# Check www redirect if requested
if check_redirects and not domain.startswith("www."):
try:
www_response = requests.get(f"https://www.{domain}", allow_redirects=True, timeout=10)
result["www_redirects"] = www_response.url == f"https://{domain}/" or www_response.url == f"https://{domain}"
if result["www_redirects"]:
print_status(f" www → apex redirect: ✓", "success")
else:
print_status(f" www redirect: ✗ (goes to {www_response.url})", "warning")
except Exception as e:
print_status(f" www redirect check failed: {e}", "info")
return result
def validate_domain(domain: str, full_check: bool = True) -> bool:
"""Validate a single domain"""
print(f"\n{'='*60}")
print(f"{Style.BRIGHT}Validating: {domain}{Style.RESET_ALL}")
print(f"{'='*60}")
all_passed = True
# DNS Resolution
print(f"\n{Fore.CYAN}[1/3] DNS Resolution{Fore.RESET}")
dns_result = check_dns_resolution(domain)
if dns_result["resolved"]:
print_status(f"DNS resolved successfully", "success")
else:
print_status(f"DNS resolution failed: {dns_result.get('error', 'Unknown error')}", "error")
all_passed = False
if not full_check:
return all_passed
# SSL Certificate
print(f"\n{Fore.CYAN}[2/3] SSL Certificate{Fore.RESET}")
ssl_result = check_ssl_certificate(domain)
if ssl_result["valid"]:
print_status(f"SSL certificate is valid", "success")
else:
print_status(f"SSL certificate check failed: {ssl_result.get('error', 'Unknown error')}", "error")
all_passed = False
# HTTP Accessibility
print(f"\n{Fore.CYAN}[3/3] HTTP Accessibility{Fore.RESET}")
http_result = check_http_accessibility(domain)
if http_result["https_accessible"]:
print_status(f"Site is accessible via HTTPS", "success")
else:
print_status(f"Site accessibility check failed: {http_result.get('error', 'Unknown error')}", "error")
all_passed = False
# Summary
print(f"\n{'='*60}")
if all_passed:
print_status(f"{domain}: All checks passed! ✓", "success")
else:
print_status(f"{domain}: Some checks failed", "warning")
print(f"{'='*60}")
return all_passed
def main():
"""Main entry point"""
parser = argparse.ArgumentParser(
description="Validate DNS configuration and check propagation status"
)
parser.add_argument(
"--domain",
help="Domain to validate (default: blackroad.systems)"
)
parser.add_argument(
"--all",
action="store_true",
help="Check all BlackRoad domains"
)
parser.add_argument(
"--dns-only",
action="store_true",
help="Only check DNS resolution (skip SSL and HTTP checks)"
)
args = parser.parse_args()
# List of BlackRoad domains
all_domains = [
"blackroad.systems",
"blackroad.ai",
"blackroad.network",
"blackroad.me",
"lucidia.earth",
"aliceqi.com",
"blackroadqi.com",
"roadwallet.com",
"aliceos.io",
"blackroadquantum.com"
]
if args.all:
domains = all_domains
elif args.domain:
domains = [args.domain]
else:
domains = ["blackroad.systems"]
full_check = not args.dns_only
all_passed = True
for domain in domains:
passed = validate_domain(domain, full_check=full_check)
if not passed:
all_passed = False
# Final summary
print(f"\n{'='*60}")
print(f"{Style.BRIGHT}VALIDATION SUMMARY{Style.RESET_ALL}")
print(f"{'='*60}")
print(f"Domains checked: {len(domains)}")
if all_passed:
print_status("All validations passed!", "success")
sys.exit(0)
else:
print_status("Some validations failed", "warning")
sys.exit(1)
if __name__ == "__main__":
main()