Y
Published on

Complete Guide Parental Web Monitoring System on Ubuntu

Authors
  • avatar
    Name
    Yinhuan Yuan
    Twitter

Complete Guide: Parental Web Monitoring System on Ubuntu

Part 1: Important Preliminary Considerations

  • Ownership: Ensure you legally own the laptop or have explicit authority to monitor it
  • Age-appropriate transparency: Consider telling your child about monitoring based on their age:
    • Under 10: Basic explanation about "keeping safe online"
    • 10-14: More detailed discussion about online dangers
    • 15+: Frank conversation about trust and safety balance
  • Local laws: Verify your local regulations regarding parental monitoring

Communication Strategy

Before implementing technical solutions:

  1. Have an age-appropriate conversation about online safety
  2. Establish family internet rules together
  3. Explain that monitoring is about safety, not punishment
  4. Consider a written family technology agreement

Part 2: Multi-Layer Monitoring Architecture

System Overview

[Internet] ← → [Router/DNS Filter] ← → [Proxy Server] ← → [Child's Laptop]
                        ↓                      ↓                ↓
                  [DNS Logs]          [Proxy Logs]      [Local Monitoring]
                        ↓                      ↓                ↓
                  [Centralized Monitoring Dashboard on Parent's System]

Part 3: Implementation Tutorial

Method 1: Squid Proxy with Comprehensive Logging

Step 1: Install and Configure Squid Proxy
# On your Ubuntu monitoring server (can be your own machine)
sudo apt update
sudo apt install squid apache2 sarg

# Backup original configuration
sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.backup

# Edit Squid configuration
sudo nano /etc/squid/squid.conf
Step 2: Configure Squid for Transparent Monitoring

Add/modify these lines in squid.conf:

# Define your local network
acl localnet src 192.168.1.0/24  # Adjust to your network range

# Define safe ports
acl SSL_ports port 443
acl Safe_ports port 80      # http
acl Safe_ports port 443     # https
acl Safe_ports port 21      # ftp

# Deny unsafe ports
http_access deny !Safe_ports

# Allow local network
http_access allow localnet
http_access allow localhost

# Define cache directory
cache_dir ufs /var/spool/squid 10000 16 256

# Comprehensive logging
access_log daemon:/var/log/squid/access.log squid
cache_log /var/log/squid/cache.log

# Log format with full details
logformat custom %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt "%{User-Agent}>h" "%{Referer}>h"
access_log /var/log/squid/detailed.log custom

# Block inappropriate content categories
acl blocked_sites dstdomain "/etc/squid/blocked_sites.txt"
http_access deny blocked_sites

# Time-based restrictions (optional)
acl school_hours time MTWHF 09:00-15:00
acl leisure_sites dstdomain .youtube.com .twitch.tv .discord.com
http_access deny leisure_sites school_hours
Step 3: Create Blocked Sites List
sudo nano /etc/squid/blocked_sites.txt

Add domains (one per line) you want to block:

.adult-site.com
.gambling-site.com
.violent-content.com
Step 4: Set Up Real-time Monitoring Script

Create a Python monitoring script:

#!/usr/bin/env python3
# save as /opt/monitor/web_monitor.py

import time
import re
import smtplib
import subprocess
from datetime import datetime
from email.mime.text import MIMEText
from collections import defaultdict
import json

class WebMonitor:
    def __init__(self):
        self.config = {
            'log_file': '/var/log/squid/access.log',
            'alert_email': 'parent@example.com',
            'alert_keywords': ['violence', 'drug', 'adult', 'weapon'],
            'suspicious_patterns': [
                r'chat\.',
                r'onion\.',
                r'torproject\.',
            ],
            'report_file': '/var/www/html/monitoring/daily_report.html'
        }
        self.visits = defaultdict(list)
        
    def parse_log_line(self, line):
        """Parse Squid log line for URL and timestamp"""
        parts = line.split()
        if len(parts) >= 7:
            timestamp = float(parts[0])
            url = parts[6]
            client_ip = parts[2]
            return {
                'time': datetime.fromtimestamp(timestamp),
                'url': url,
                'client': client_ip
            }
        return None
    
    def check_suspicious(self, url):
        """Check if URL matches suspicious patterns"""
        url_lower = url.lower()
        
        # Check keywords
        for keyword in self.config['alert_keywords']:
            if keyword in url_lower:
                return True, f"Keyword '{keyword}' detected"
        
        # Check patterns
        for pattern in self.config['suspicious_patterns']:
            if re.search(pattern, url_lower):
                return True, f"Pattern '{pattern}' matched"
        
        return False, None
    
    def send_alert(self, url, reason, timestamp):
        """Send email alert for suspicious activity"""
        subject = f"Web Monitoring Alert - {timestamp}"
        body = f"""
        Suspicious web activity detected:
        
        URL: {url}
        Reason: {reason}
        Time: {timestamp}
        
        Please review the activity and take appropriate action.
        """
        
        # Email sending code (configure SMTP settings)
        try:
            msg = MIMEText(body)
            msg['Subject'] = subject
            msg['From'] = 'monitor@localhost'
            msg['To'] = self.config['alert_email']
            
            # Send via local mail or configured SMTP
            s = smtplib.SMTP('localhost')
            s.send_message(msg)
            s.quit()
        except Exception as e:
            print(f"Failed to send alert: {e}")
    
    def generate_daily_report(self):
        """Generate HTML report of daily activity"""
        html = """
        <html>
        <head>
            <title>Daily Web Activity Report</title>
            <style>
                body { font-family: Arial, sans-serif; }
                table { border-collapse: collapse; width: 100%; }
                th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
                th { background-color: #4CAF50; color: white; }
                .suspicious { background-color: #ffcccc; }
            </style>
        </head>
        <body>
            <h1>Daily Web Activity Report - {date}</h1>
            <h2>Summary</h2>
            <p>Total sites visited: {total}</p>
            <p>Suspicious activities: {suspicious}</p>
            
            <h2>Detailed Activity</h2>
            <table>
                <tr>
                    <th>Time</th>
                    <th>URL</th>
                    <th>Category</th>
                    <th>Status</th>
                </tr>
                {rows}
            </table>
        </body>
        </html>
        """
        
        rows = ""
        suspicious_count = 0
        
        for client, visits in self.visits.items():
            for visit in visits:
                is_suspicious, reason = self.check_suspicious(visit['url'])
                if is_suspicious:
                    suspicious_count += 1
                    row_class = 'suspicious'
                    status = f"⚠️ {reason}"
                else:
                    row_class = ''
                    status = "✓ Safe"
                
                rows += f"""
                <tr class="{row_class}">
                    <td>{visit['time']}</td>
                    <td>{visit['url']}</td>
                    <td>{self.categorize_url(visit['url'])}</td>
                    <td>{status}</td>
                </tr>
                """
        
        report = html.format(
            date=datetime.now().strftime('%Y-%m-%d'),
            total=sum(len(v) for v in self.visits.values()),
            suspicious=suspicious_count,
            rows=rows
        )
        
        with open(self.config['report_file'], 'w') as f:
            f.write(report)
    
    def categorize_url(self, url):
        """Categorize URL into general categories"""
        categories = {
            'Social Media': ['facebook', 'twitter', 'instagram', 'tiktok', 'snapchat'],
            'Video': ['youtube', 'vimeo', 'twitch', 'netflix'],
            'Gaming': ['steam', 'epic', 'roblox', 'minecraft'],
            'Educational': ['edu', 'wikipedia', 'khan', 'coursera'],
            'Search': ['google', 'bing', 'duckduckgo'],
            'Shopping': ['amazon', 'ebay', 'shopify'],
        }
        
        url_lower = url.lower()
        for category, keywords in categories.items():
            for keyword in keywords:
                if keyword in url_lower:
                    return category
        return 'Other'
    
    def monitor_realtime(self):
        """Monitor log file in real-time"""
        print("Starting real-time monitoring...")
        
        # Use tail -f for real-time monitoring
        process = subprocess.Popen(
            ['tail', '-f', self.config['log_file']],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        
        for line in process.stdout:
            entry = self.parse_log_line(line)
            if entry:
                # Store for reporting
                self.visits[entry['client']].append(entry)
                
                # Check for suspicious activity
                is_suspicious, reason = self.check_suspicious(entry['url'])
                if is_suspicious:
                    print(f"ALERT: {entry['url']} - {reason}")
                    self.send_alert(entry['url'], reason, entry['time'])

if __name__ == "__main__":
    monitor = WebMonitor()
    monitor.monitor_realtime()
Step 5: Configure Child's Laptop

On your son's laptop, configure proxy settings:

# System-wide proxy configuration
sudo nano /etc/environment

Add:

http_proxy="http://192.168.1.100:3128"  # Your proxy server IP
https_proxy="http://192.168.1.100:3128"
ftp_proxy="http://192.168.1.100:3128"
no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"

Method 2: DNS-Based Monitoring with Pi-hole

Step 1: Install Pi-hole
# Can be installed on Raspberry Pi or Ubuntu server
curl -sSL https://install.pi-hole.net | bash
Step 2: Configure Custom Blocklists
# Access Pi-hole admin interface
# http://pi.hole/admin

# Add custom blocklists for child safety:
# - https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
# - https://someonewhocares.org/hosts/zero/hosts
# - https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt
Step 3: Query Logging Analysis Script
#!/usr/bin/env python3
# DNS monitoring script for Pi-hole
import sqlite3
import time
from datetime import datetime, timedelta

class DNSMonitor:
    def __init__(self):
        self.db_path = '/etc/pihole/pihole-FTL.db'
        self.client_ip = '192.168.1.150'  # Child's device IP
        
    def get_recent_queries(self, hours=1):
        """Get DNS queries from the last N hours"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        timestamp = int(time.time()) - (hours * 3600)
        
        query = """
        SELECT timestamp, domain, status 
        FROM queries 
        WHERE client = ? AND timestamp > ?
        ORDER BY timestamp DESC
        """
        
        cursor.execute(query, (self.client_ip, timestamp))
        results = cursor.fetchall()
        conn.close()
        
        return results
    
    def analyze_patterns(self, queries):
        """Analyze browsing patterns"""
        domains = {}
        blocked_count = 0
        
        for timestamp, domain, status in queries:
            if domain not in domains:
                domains[domain] = {'count': 0, 'blocked': False}
            
            domains[domain]['count'] += 1
            if status in [1, 4, 5, 9, 10, 11]:  # Blocked status codes
                domains[domain]['blocked'] = True
                blocked_count += 1
        
        return {
            'unique_domains': len(domains),
            'total_queries': len(queries),
            'blocked_attempts': blocked_count,
            'top_domains': sorted(domains.items(), 
                                 key=lambda x: x[1]['count'], 
                                 reverse=True)[:20]
        }

monitor = DNSMonitor()
queries = monitor.get_recent_queries(24)  # Last 24 hours
analysis = monitor.analyze_patterns(queries)
print(json.dumps(analysis, indent=2))

Method 3: Browser-Level Monitoring

Step 1: Create Firefox/Chrome Extension for Monitoring

Create manifest.json:

{
  "manifest_version": 2,
  "name": "Family Safety Monitor",
  "version": "1.0",
  "description": "Monitors web activity for family safety",
  
  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "storage",
    "tabs",
    "<all_urls>"
  ],
  
  "background": {
    "scripts": ["background.js"],
    "persistent": true
  },
  
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"]
  }]
}

Create background.js:

// Monitoring server endpoint
const MONITOR_SERVER = 'http://192.168.1.100:8080/log';

// Track all web requests
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    // Log URL visit
    logVisit(details.url, details.timeStamp);
    
    // Check against local rules
    if (shouldBlock(details.url)) {
      return {cancel: true};
    }
  },
  {urls: ["<all_urls>"]},
  ["blocking"]
);

function logVisit(url, timestamp) {
  // Send to monitoring server
  fetch(MONITOR_SERVER, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      url: url,
      timestamp: timestamp,
      user: 'child_laptop'
    })
  }).catch(err => console.error('Logging failed:', err));
  
  // Store locally as backup
  chrome.storage.local.get(['history'], function(result) {
    let history = result.history || [];
    history.push({url, timestamp});
    
    // Keep last 1000 entries
    if (history.length > 1000) {
      history = history.slice(-1000);
    }
    
    chrome.storage.local.set({history: history});
  });
}

function shouldBlock(url) {
  const blockedKeywords = [
    'adult', 'gambling', 'violence', 'drugs'
  ];
  
  const urlLower = url.toLowerCase();
  return blockedKeywords.some(keyword => urlLower.includes(keyword));
}

// Monitor active tab time
let activeTab = null;
let tabStartTime = {};

chrome.tabs.onActivated.addListener(function(activeInfo) {
  chrome.tabs.get(activeInfo.tabId, function(tab) {
    if (activeTab) {
      // Log time spent on previous tab
      const timeSpent = Date.now() - tabStartTime[activeTab];
      logTimeSpent(activeTab, timeSpent);
    }
    
    activeTab = tab.url;
    tabStartTime[tab.url] = Date.now();
  });
});

function logTimeSpent(url, duration) {
  fetch(MONITOR_SERVER, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      type: 'time_spent',
      url: url,
      duration: duration,
      user: 'child_laptop'
    })
  });
}
Step 2: Deploy Extension
# Package extension for deployment
# In Chrome: chrome://extensions/ → Developer mode → Load unpacked
# In Firefox: about:debugging → This Firefox → Load Temporary Add-on

# For permanent installation, sign the extension through browser stores
# Or use enterprise policy to force-install

Part 4: Centralized Monitoring Dashboard

Create Web Dashboard
#!/usr/bin/env python3
# monitoring_dashboard.py
from flask import Flask, render_template, jsonify
import sqlite3
from datetime import datetime, timedelta
import json

app = Flask(__name__)

class MonitoringDashboard:
    def __init__(self):
        self.db_path = '/var/log/monitoring/activity.db'
        self.init_database()
    
    def init_database(self):
        """Initialize SQLite database for storing logs"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS web_activity (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                url TEXT,
                domain TEXT,
                user TEXT,
                category TEXT,
                risk_level INTEGER,
                blocked BOOLEAN DEFAULT 0
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS alerts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                alert_type TEXT,
                description TEXT,
                url TEXT,
                resolved BOOLEAN DEFAULT 0
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def get_activity_summary(self, hours=24):
        """Get activity summary for dashboard"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        since = datetime.now() - timedelta(hours=hours)
        
        # Get top visited sites
        cursor.execute('''
            SELECT domain, COUNT(*) as visits, 
                   MAX(risk_level) as max_risk
            FROM web_activity
            WHERE timestamp > ?
            GROUP BY domain
            ORDER BY visits DESC
            LIMIT 20
        ''', (since,))
        
        top_sites = cursor.fetchall()
        
        # Get recent alerts
        cursor.execute('''
            SELECT * FROM alerts
            WHERE timestamp > ? AND resolved = 0
            ORDER BY timestamp DESC
        ''', (since,))
        
        alerts = cursor.fetchall()
        
        # Get activity timeline
        cursor.execute('''
            SELECT strftime('%H', timestamp) as hour, 
                   COUNT(*) as activity
            FROM web_activity
            WHERE timestamp > ?
            GROUP BY hour
        ''', (since,))
        
        timeline = cursor.fetchall()
        
        conn.close()
        
        return {
            'top_sites': top_sites,
            'alerts': alerts,
            'timeline': timeline
        }

dashboard = MonitoringDashboard()

@app.route('/')
def index():
    return render_template('dashboard.html')

@app.route('/api/summary')
def api_summary():
    return jsonify(dashboard.get_activity_summary())

@app.route('/log', methods=['POST'])
def log_activity():
    # Endpoint for receiving logs from various monitors
    data = request.json
    
    conn = sqlite3.connect(dashboard.db_path)
    cursor = conn.cursor()
    
    cursor.execute('''
        INSERT INTO web_activity (url, domain, user, category, risk_level)
        VALUES (?, ?, ?, ?, ?)
    ''', (
        data.get('url'),
        extract_domain(data.get('url')),
        data.get('user'),
        categorize_url(data.get('url')),
        assess_risk(data.get('url'))
    ))
    
    conn.commit()
    conn.close()
    
    return jsonify({'status': 'logged'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Part 5: Network-Level Implementation

Configure Router-Level Monitoring
# For routers running OpenWRT/DD-WRT
# SSH into router
ssh root@192.168.1.1

# Install monitoring packages
opkg update
opkg install tcpdump netfilter-log

# Create monitoring script
cat > /root/monitor_traffic.sh << 'EOF'
#!/bin/sh
# Log all HTTP/HTTPS traffic from child's device
CHILD_MAC="aa:bb:cc:dd:ee:ff"  # Replace with actual MAC

tcpdump -i br-lan -w /tmp/child_traffic.pcap \
  "ether src $CHILD_MAC and (port 80 or port 443)" &

# Parse and send logs periodically
while true; do
  sleep 300  # Every 5 minutes
  tshark -r /tmp/child_traffic.pcap -T fields \
    -e frame.time -e ip.src -e http.host -e http.request.uri \
    2>/dev/null | while read line; do
    # Send to monitoring server
    wget -q -O- --post-data="$line" http://192.168.1.100:8080/router-log
  done
  > /tmp/child_traffic.pcap  # Clear capture file
done
EOF

chmod +x /root/monitor_traffic.sh

Part 6: Safety Features and Alerts

Implement Multi-tier Alert System
# alert_system.py
import smtplib
import requests
from twilio.rest import Client  # For SMS alerts

class AlertSystem:
    def __init__(self):
        self.email_config = {
            'smtp_server': 'smtp.gmail.com',
            'smtp_port': 587,
            'sender': 'your-email@gmail.com',
            'password': 'your-app-password'
        }
        
        # Twilio config for SMS (optional)
        self.twilio_config = {
            'account_sid': 'your_account_sid',
            'auth_token': 'your_auth_token',
            'from_number': '+1234567890',
            'to_number': '+0987654321'
        }
        
        self.alert_levels = {
            'LOW': 1,      # Log only
            'MEDIUM': 2,   # Email notification
            'HIGH': 3,     # Email + SMS
            'CRITICAL': 4  # Email + SMS + Phone call
        }
    
    def assess_threat(self, url, context):
        """Determine threat level based on URL and context"""
        high_risk_indicators = [
            'chat', 'cam', 'live', 'private', 'anonymous',
            'onion', 'tor', 'vpn', 'proxy'
        ]
        
        critical_indicators = [
            'suicide', 'self-harm', 'meet', 'location',
            'address', 'phone', 'personal'
        ]
        
        url_lower = url.lower()
        
        for indicator in critical_indicators:
            if indicator in url_lower:
                return 'CRITICAL'
        
        for indicator in high_risk_indicators:
            if indicator in url_lower:
                return 'HIGH'
        
        # Check time-based threats (late night activity)
        hour = datetime.now().hour
        if hour >= 23 or hour <= 5:
            return 'MEDIUM'
        
        return 'LOW'
    
    def send_alert(self, threat_level, message, url):
        """Send alert based on threat level"""
        if threat_level == 'LOW':
            self.log_alert(message, url)
        
        elif threat_level == 'MEDIUM':
            self.log_alert(message, url)
            self.send_email_alert(message, url)
        
        elif threat_level == 'HIGH':
            self.log_alert(message, url)
            self.send_email_alert(message, url)
            self.send_sms_alert(message)
        
        elif threat_level == 'CRITICAL':
            self.log_alert(message, url)
            self.send_email_alert(message, url)
            self.send_sms_alert(message)
            self.make_phone_call(message)
    
    def send_email_alert(self, message, url):
        """Send email alert"""
        subject = f"Web Safety Alert - {datetime.now()}"
        body = f"""
        URGENT: Potentially dangerous web activity detected
        
        Details: {message}
        URL: {url}
        Time: {datetime.now()}
        
        Please check on your child immediately.
        
        View full report: http://192.168.1.100:8080/dashboard
        """
        
        # Send email implementation
        server = smtplib.SMTP(self.email_config['smtp_server'], 
                             self.email_config['smtp_port'])
        server.starttls()
        server.login(self.email_config['sender'], 
                    self.email_config['password'])
        server.sendmail(self.email_config['sender'],
                       'parent@email.com',
                       f"Subject: {subject}\n\n{body}")
        server.quit()

Part 7: Educational Component

Create Educational Blocking Page
<!-- /var/www/html/blocked.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Website Blocked - Let's Talk</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        .container {
            text-align: center;
            padding: 40px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 20px;
        }
        .emoji { font-size: 72px; }
        h1 { margin: 20px 0; }
        .reasons {
            background: rgba(255, 255, 255, 0.2);
            padding: 20px;
            border-radius: 10px;
            margin: 20px 0;
        }
        .alternatives {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 30px;
        }
        .alt-button {
            background: white;
            color: #667eea;
            padding: 15px 30px;
            border-radius: 25px;
            text-decoration: none;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="emoji">🛡️</div>
        <h1>This Website Has Been Blocked</h1>
        <p>We blocked this site to keep you safe online.</p>
        
        <div class="reasons">
            <h3>Why was this blocked?</h3>
            <p id="block-reason">This site may contain content that's not appropriate for your age or could put your personal information at risk.</p>
        </div>
        
        <p><strong>Want to talk about it?</strong><br>
        If you think this was blocked by mistake, or if you have questions, let's discuss it together!</p>
        
        <div class="alternatives">
            <a href="https://www.coolmathgames.com" class="alt-button">Play Games</a>
            <a href="https://www.khanacademy.org" class="alt-button">Learn Something</a>
            <a href="http://192.168.1.100:8080/request-access" class="alt-button">Request Access</a>
        </div>
        
        <p style="margin-top: 30px; opacity: 0.8;">
        Remember: The internet is amazing, but staying safe is important! 💪
        </p>
    </div>
    
    <script>
        // Log the block event
        fetch('/log-block', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                url: document.referrer,
                timestamp: new Date().toISOString()
            })
        });
    </script>
</html>

Part 8: Age-Appropriate Configuration

Create Age-Based Filtering Profiles
# age_profiles.py
class AgeProfile:
    def __init__(self, age):
        self.age = age
        self.rules = self.get_rules_for_age(age)
    
    def get_rules_for_age(self, age):
        """Return filtering rules based on child's age"""
        if age < 8:
            return {
                'whitelist_only': True,
                'allowed_sites': [
                    'pbskids.org',
                    'nickjr.com',
                    'disney.com',
                    'coolmathgames.com',
                    'abcmouse.com'
                ],
                'time_limits': {
                    'weekday': 60,  # minutes
                    'weekend': 120
                },
                'blocked_categories': ['all'],
                'safe_search': 'strict'
            }
        
        elif 8 <= age < 13:
            return {
                'whitelist_only': False,
                'blocked_categories': [
                    'adult', 'violence', 'gambling', 'drugs',
                    'weapons', 'hate', 'self-harm'
                ],
                'time_limits': {
                    'weekday': 120,
                    'weekend': 180
                },
                'social_media': 'blocked',
                'safe_search': 'strict',
                'youtube': 'restricted_mode'
            }
        
        elif 13 <= age < 16:
            return {
                'whitelist_only': False,
                'blocked_categories': [
                    'adult', 'gambling', 'drugs', 'weapons', 'hate'
                ],
                'time_limits': {
                    'weekday': 180,
                    'weekend': 240
                },
                'social_media': 'monitored',
                'safe_search': 'moderate',
                'chat_apps': 'logged'
            }
        
        else:  # 16+
            return {
                'whitelist_only': False,
                'blocked_categories': [
                    'malware', 'phishing', 'illegal'
                ],
                'time_limits': None,
                'monitoring': 'light',
                'safe_search': 'off',
                'privacy_mode': 'available'
            }

Part 9: Deployment and Maintenance

System Setup Script
#!/bin/bash
# setup_monitoring.sh

echo "Ubuntu Parental Monitoring System Setup"
echo "========================================"

# Check if running as root
if [ "$EUID" -ne 0 ]; then 
    echo "Please run as root (use sudo)"
    exit 1
fi

# Install required packages
apt-get update
apt-get install -y \
    squid \
    apache2 \
    python3-pip \
    sqlite3 \
    tcpdump \
    tshark \
    fail2ban \
    ufw

# Python dependencies
pip3 install \
    flask \
    requests \
    python-dateutil \
    twilio \
    beautifulsoup4

# Create directory structure
mkdir -p /opt/monitoring/{scripts,logs,data,web}
mkdir -p /var/www/html/monitoring
mkdir -p /etc/monitoring/profiles

# Set up firewall
ufw allow 3128/tcp  # Squid proxy
ufw allow 8080/tcp  # Monitoring dashboard
ufw allow 80/tcp    # Web server
ufw enable

# Create systemd services
cat > /etc/systemd/system/web-monitor.service << EOF
[Unit]
Description=Web Activity Monitor
After=network.target

[Service]
Type=simple
User=monitor
ExecStart=/usr/bin/python3 /opt/monitoring/scripts/web_monitor.py
Restart=always

[Install]
WantedBy=multi-user.target
EOF

cat > /etc/systemd/system/monitoring-dashboard.service << EOF
[Unit]
Description=Monitoring Dashboard
After=network.target

[Service]
Type=simple
User=www-data
ExecStart=/usr/bin/python3 /opt/monitoring/web/dashboard.py
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# Enable services
systemctl daemon-reload
systemctl enable web-monitor
systemctl enable monitoring-dashboard
systemctl start web-monitor
systemctl start monitoring-dashboard

echo "Setup complete! Access dashboard at http://$(hostname -I | cut -d' ' -f1):8080"
Backup and Reporting
#!/bin/bash
# daily_maintenance.sh
# Add to crontab: 0 2 * * * /opt/monitoring/daily_maintenance.sh

# Backup monitoring data
DATE=$(date +%Y%m%d)
tar -czf /backup/monitoring_$DATE.tar.gz /var/log/monitoring/

# Generate daily report
python3 /opt/monitoring/scripts/generate_report.py

# Clean old logs (keep 30 days)
find /var/log/monitoring -name "*.log" -mtime +30 -delete

# Update blocklists
wget -O /etc/squid/blocked_sites.txt \
    https://your-blocklist-source.com/family-safe.txt
    
systemctl reload squid

Part 10: Alternative Solutions to Consider

Commercial Options Worth Evaluating:

  1. OpenDNS FamilyShield - Free DNS filtering
  2. Qustodio - Comprehensive parental control
  3. Circle Home Plus - Network device management
  4. Bark - AI-powered content monitoring
  5. Disney Circle - Time limits and filtering

Open Source Alternatives:

  1. TimeLimitAuth - Time-based access control
  2. DansGuardian - Content filtering proxy
  3. E2guardian - Web content filter
  4. FamilyShield - DNS-based filtering

Important Final Considerations

Privacy Balance:

  • Start with less invasive monitoring and increase if needed
  • Consider giving older children some private browsing time
  • Regularly review and adjust rules as your child grows

Communication is Key:

  • Explain why monitoring exists
  • Show your child the dashboard (age-appropriate parts)
  • Use alerts as conversation starters, not punishment triggers
  • Celebrate good online behavior
  • Ensure compliance with local privacy laws
  • Keep monitoring within your own network
  • Don't monitor other family members without consent
  • Secure all collected data properly

Technical Security:

# Secure your monitoring system
chmod 600 /etc/monitoring/*
chown -R monitor:monitor /opt/monitoring
encrypt_partition /var/log/monitoring

# Regular security updates
apt update && apt upgrade -y

This comprehensive system provides multiple layers of protection while maintaining a balance between safety and privacy. Remember that technical solutions should complement, not replace, open communication about online safety.

Would you like me to elaborate on any specific component or provide additional configuration for your particular use case?