Wiki major update
updated with recent documentation
This commit is contained in:
604
wiki/service-docs/pihole.md
Normal file
604
wiki/service-docs/pihole.md
Normal file
@@ -0,0 +1,604 @@
|
||||
# Pi-hole - Network-Wide Ad Blocker
|
||||
|
||||
## Table of Contents
|
||||
- [Overview](#overview)
|
||||
- [What is Pi-hole?](#what-is-pi-hole)
|
||||
- [Why Use Pi-hole?](#why-use-pi-hole)
|
||||
- [How It Works](#how-it-works)
|
||||
- [Configuration in AI-Homelab](#configuration-in-ai-homelab)
|
||||
- [Official Resources](#official-resources)
|
||||
- [Educational Resources](#educational-resources)
|
||||
- [Docker Configuration](#docker-configuration)
|
||||
- [Setup and Management](#setup-and-management)
|
||||
- [Advanced Topics](#advanced-topics)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Overview
|
||||
|
||||
**Category:** Infrastructure / Network
|
||||
**Docker Image:** [pihole/pihole](https://hub.docker.com/r/pihole/pihole)
|
||||
**Default Stack:** `infrastructure.yml`
|
||||
**Web UI:** `https://pihole.${DOMAIN}/admin` or `http://SERVER_IP:8181/admin`
|
||||
**Authentication:** Admin password set via environment variable
|
||||
**DNS Port:** 53 (TCP/UDP)
|
||||
|
||||
## What is Pi-hole?
|
||||
|
||||
Pi-hole is a network-level advertisement and internet tracker blocking application that acts as a DNS sinkhole. Originally designed for Raspberry Pi, it now runs on any Linux system including Docker. It blocks ads for all devices on your network without requiring per-device configuration.
|
||||
|
||||
### Key Features
|
||||
- **Network-Wide Blocking:** Blocks ads on all devices (phones, tablets, smart TVs)
|
||||
- **DNS Level Blocking:** Intercepts DNS queries before ads load
|
||||
- **No Client Software:** Works for all devices automatically
|
||||
- **Extensive Blocklists:** Millions of known ad/tracking domains blocked
|
||||
- **Web Interface:** Beautiful dashboard with statistics
|
||||
- **Whitelist/Blacklist:** Custom domain control
|
||||
- **DHCP Server:** Optional network DHCP service
|
||||
- **DNS Over HTTPS:** Encrypted DNS queries (DoH)
|
||||
- **Query Logging:** See all DNS queries on network
|
||||
- **Group Management:** Different blocking rules for different devices
|
||||
- **Regex Filtering:** Advanced domain pattern blocking
|
||||
|
||||
## Why Use Pi-hole?
|
||||
|
||||
1. **Block Ads Everywhere:** Mobile apps, smart TVs, IoT devices
|
||||
2. **Faster Browsing:** Pages load faster without ads
|
||||
3. **Privacy Protection:** Block trackers and analytics
|
||||
4. **Save Bandwidth:** Don't download ad content
|
||||
5. **Malware Protection:** Block known malicious domains
|
||||
6. **Family Safety:** Block inappropriate content
|
||||
7. **Network Visibility:** See what devices are connecting where
|
||||
8. **Free:** No subscription fees
|
||||
9. **Customizable:** Full control over blocking
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
Device (Phone/Computer/TV)
|
||||
↓
|
||||
DNS Query: "ads.example.com"
|
||||
↓
|
||||
Router/DHCP → Pi-hole (DNS Server)
|
||||
↓
|
||||
Is domain in blocklist?
|
||||
├─ YES → Return 0.0.0.0 (blocked)
|
||||
└─ NO → Forward to upstream DNS → Return real IP
|
||||
```
|
||||
|
||||
### Blocking Process
|
||||
|
||||
1. **Device makes request:** "I want to visit ads.google.com"
|
||||
2. **DNS query sent:** Device asks "What's the IP for ads.google.com?"
|
||||
3. **Pi-hole receives query:** Checks against blocklists
|
||||
4. **If blocked:** Returns 0.0.0.0 (null IP) - ad doesn't load
|
||||
5. **If allowed:** Forwards to real DNS (1.1.1.1, 8.8.8.8, etc.)
|
||||
6. **Result cached:** Faster subsequent queries
|
||||
|
||||
### Network Setup
|
||||
|
||||
**Before Pi-hole:**
|
||||
```
|
||||
Device → Router DNS → ISP DNS → Internet
|
||||
```
|
||||
|
||||
**After Pi-hole:**
|
||||
```
|
||||
Device → Router (points to Pi-hole) → Pi-hole → Upstream DNS → Internet
|
||||
↓
|
||||
(blocks ads)
|
||||
```
|
||||
|
||||
## Configuration in AI-Homelab
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
/opt/stacks/infrastructure/pihole/
|
||||
├── etc-pihole/ # Pi-hole configuration
|
||||
│ ├── gravity.db # Blocklist database
|
||||
│ ├── custom.list # Local DNS records
|
||||
│ └── pihole-FTL.db # Query log database
|
||||
└── etc-dnsmasq.d/ # DNS server config
|
||||
└── custom.conf # Custom DNS rules
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Web Interface Password
|
||||
WEBPASSWORD=your-secure-password-here
|
||||
|
||||
# Timezone
|
||||
TZ=America/New_York
|
||||
|
||||
# Upstream DNS Servers
|
||||
PIHOLE_DNS_=1.1.1.1;8.8.8.8 # Cloudflare and Google
|
||||
# PIHOLE_DNS_=9.9.9.9;149.112.112.112 # Quad9 (privacy-focused)
|
||||
|
||||
# Web Interface Settings
|
||||
WEBTHEME=default-dark # or default-light
|
||||
VIRTUAL_HOST=pihole.yourdomain.com
|
||||
WEB_PORT=80
|
||||
|
||||
# Optional: DHCP Server
|
||||
DHCP_ACTIVE=false # Set true if using Pi-hole as DHCP
|
||||
DHCP_START=192.168.1.100
|
||||
DHCP_END=192.168.1.200
|
||||
DHCP_ROUTER=192.168.1.1
|
||||
```
|
||||
|
||||
## Official Resources
|
||||
|
||||
- **Website:** https://pi-hole.net
|
||||
- **Documentation:** https://docs.pi-hole.net
|
||||
- **GitHub:** https://github.com/pi-hole/pi-hole
|
||||
- **Docker Hub:** https://hub.docker.com/r/pihole/pihole
|
||||
- **Discourse Forum:** https://discourse.pi-hole.net
|
||||
- **Reddit:** https://reddit.com/r/pihole
|
||||
- **Blocklists:** https://firebog.net
|
||||
|
||||
## Educational Resources
|
||||
|
||||
### Videos
|
||||
- [Pi-hole - Network-Wide Ad Blocking (NetworkChuck)](https://www.youtube.com/watch?v=KBXTnrD_Zs4)
|
||||
- [Ultimate Pi-hole Setup Guide (Techno Tim)](https://www.youtube.com/watch?v=FnFtWsZ8IP0)
|
||||
- [How DNS Works (Explained)](https://www.youtube.com/watch?v=72snZctFFtA)
|
||||
- [Pi-hole Docker Setup (DB Tech)](https://www.youtube.com/watch?v=NRe2-vye3ik)
|
||||
|
||||
### Articles & Guides
|
||||
- [Pi-hole Official Documentation](https://docs.pi-hole.net)
|
||||
- [Docker Pi-hole Setup](https://github.com/pi-hole/docker-pi-hole/)
|
||||
- [Best Blocklists (Firebog)](https://firebog.net)
|
||||
- [DNS Over HTTPS Setup](https://docs.pi-hole.net/guides/dns/cloudflared/)
|
||||
|
||||
### Concepts to Learn
|
||||
- **DNS (Domain Name System):** Translates domains to IP addresses
|
||||
- **DNS Sinkhole:** Returns null IP for blocked domains
|
||||
- **Upstream DNS:** Real DNS servers Pi-hole forwards to
|
||||
- **Blocklists:** Lists of known ad/tracker domains
|
||||
- **Regex Filtering:** Pattern-based domain blocking
|
||||
- **DHCP:** Network device IP assignment
|
||||
- **DNS Over HTTPS (DoH):** Encrypted DNS queries
|
||||
- **Local DNS:** Custom local domain resolution
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
### Complete Service Definition
|
||||
|
||||
```yaml
|
||||
pihole:
|
||||
image: pihole/pihole:latest
|
||||
container_name: pihole
|
||||
restart: unless-stopped
|
||||
hostname: pihole
|
||||
networks:
|
||||
- traefik-network
|
||||
ports:
|
||||
- "53:53/tcp" # DNS TCP
|
||||
- "53:53/udp" # DNS UDP
|
||||
- "8181:80/tcp" # Web Interface (remapped to avoid conflict)
|
||||
# - "67:67/udp" # DHCP (optional, uncomment if using)
|
||||
volumes:
|
||||
- /opt/stacks/infrastructure/pihole/etc-pihole:/etc/pihole
|
||||
- /opt/stacks/infrastructure/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- WEBPASSWORD=${PIHOLE_PASSWORD}
|
||||
- PIHOLE_DNS_=1.1.1.1;8.8.8.8
|
||||
- WEBTHEME=default-dark
|
||||
- VIRTUAL_HOST=pihole.${DOMAIN}
|
||||
- DNSMASQ_LISTENING=all
|
||||
cap_add:
|
||||
- NET_ADMIN # Required for DHCP functionality
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
|
||||
- "traefik.http.routers.pihole.entrypoints=websecure"
|
||||
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.pihole.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
### Important Notes
|
||||
|
||||
1. **Port 53:** DNS must be on port 53 (cannot be remapped)
|
||||
2. **Web Port:** Can use 8181 externally, 80 internally
|
||||
3. **NET_ADMIN:** Required capability for DHCP and network features
|
||||
4. **Password:** Set strong password via WEBPASSWORD variable
|
||||
|
||||
## Setup and Management
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. **Deploy Pi-hole:** Start the container
|
||||
2. **Wait 60 seconds:** Let gravity database build
|
||||
3. **Access Web UI:** `https://pihole.yourdomain.com/admin`
|
||||
4. **Login:** Use password from WEBPASSWORD
|
||||
5. **Configure Router:** Point DNS to Pi-hole server IP
|
||||
|
||||
### Router Configuration
|
||||
|
||||
**Method 1: DHCP DNS Settings (Recommended)**
|
||||
1. Access router admin panel
|
||||
2. Find DHCP settings
|
||||
3. Set Primary DNS: Pi-hole server IP (e.g., 192.168.1.10)
|
||||
4. Set Secondary DNS: 1.1.1.1 or 8.8.8.8 (fallback)
|
||||
5. Save and reboot router
|
||||
|
||||
**Method 2: Per-Device Configuration**
|
||||
- Set DNS manually on each device
|
||||
- Not recommended for whole-network blocking
|
||||
|
||||
### Dashboard Overview
|
||||
|
||||
**Main Dashboard Shows:**
|
||||
- Total queries (last 24h)
|
||||
- Queries blocked (percentage)
|
||||
- Blocklist domains count
|
||||
- Top allowed/blocked domains
|
||||
- Query types (A, AAAA, PTR, etc.)
|
||||
- Client activity
|
||||
- Real-time query log
|
||||
|
||||
### Managing Blocklists
|
||||
|
||||
**Add Blocklists:**
|
||||
1. Group Management → Adlists
|
||||
2. Add list URL
|
||||
3. Update Gravity (Tools → Update Gravity)
|
||||
|
||||
**Popular Blocklists (Firebog):**
|
||||
```
|
||||
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
https://v.firebog.net/hosts/AdguardDNS.txt
|
||||
https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt
|
||||
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
|
||||
```
|
||||
|
||||
**Update Gravity:**
|
||||
```bash
|
||||
# Via CLI
|
||||
docker exec pihole pihole -g
|
||||
|
||||
# Or Web UI: Tools → Update Gravity
|
||||
```
|
||||
|
||||
### Whitelist/Blacklist
|
||||
|
||||
**Whitelist Domain (Allow):**
|
||||
1. Whitelist → Add domain
|
||||
2. Example: `example.com`
|
||||
3. Supports wildcards: `*.example.com`
|
||||
|
||||
**Blacklist Domain (Block):**
|
||||
1. Blacklist → Add domain
|
||||
2. Example: `ads.example.com`
|
||||
|
||||
**Via CLI:**
|
||||
```bash
|
||||
# Whitelist
|
||||
docker exec pihole pihole -w example.com
|
||||
|
||||
# Blacklist
|
||||
docker exec pihole pihole -b ads.example.com
|
||||
|
||||
# Regex whitelist
|
||||
docker exec pihole pihole --regex-whitelist "^example\.com$"
|
||||
|
||||
# Regex blacklist
|
||||
docker exec pihole pihole --regex "^ad[sx]?[0-9]*\..*"
|
||||
```
|
||||
|
||||
### Query Log
|
||||
|
||||
**View Queries:**
|
||||
1. Query Log → See all DNS requests
|
||||
2. Filter by client, domain, type
|
||||
3. Whitelist/Blacklist directly from log
|
||||
|
||||
**Privacy Modes:**
|
||||
- Show Everything
|
||||
- Hide Domains
|
||||
- Hide Domains and Clients
|
||||
- Anonymous Mode
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Local DNS Records
|
||||
|
||||
Create custom local DNS entries:
|
||||
|
||||
**Via Web UI:**
|
||||
1. Local DNS → DNS Records
|
||||
2. Add domain → IP mapping
|
||||
3. Example: `nas.local → 192.168.1.50`
|
||||
|
||||
**Via File:**
|
||||
```bash
|
||||
# /opt/stacks/infrastructure/pihole/etc-pihole/custom.list
|
||||
192.168.1.50 nas.local
|
||||
192.168.1.51 server.local
|
||||
```
|
||||
|
||||
### Group Management
|
||||
|
||||
Different blocking rules for different devices:
|
||||
|
||||
1. **Create Groups:**
|
||||
- Group Management → Groups → Add Group
|
||||
- Example: "Kids Devices", "Guest Network"
|
||||
|
||||
2. **Assign Clients:**
|
||||
- Group Management → Clients → Add client to group
|
||||
|
||||
3. **Configure Adlists per Group:**
|
||||
- Group Management → Adlists → Assign to groups
|
||||
|
||||
### Regex Filtering
|
||||
|
||||
Advanced pattern-based blocking:
|
||||
|
||||
**Common Patterns:**
|
||||
```regex
|
||||
# Block all subdomains of ads.example.com
|
||||
^ad[sx]?[0-9]*\.example\.com$
|
||||
|
||||
# Block tracking parameters
|
||||
.*\?utm_.*
|
||||
|
||||
# Block all Facebook tracking
|
||||
^(.+[_.-])?facebook\.[a-z]+$
|
||||
```
|
||||
|
||||
**Add Regex:**
|
||||
1. Domains → Regex Filter
|
||||
2. Add regex pattern
|
||||
3. Test with Query Log
|
||||
|
||||
### DNS Over HTTPS (DoH)
|
||||
|
||||
Encrypt DNS queries to upstream servers:
|
||||
|
||||
**Using Cloudflared:**
|
||||
```yaml
|
||||
cloudflared:
|
||||
image: cloudflare/cloudflared:latest
|
||||
container_name: cloudflared
|
||||
restart: unless-stopped
|
||||
command: proxy-dns
|
||||
environment:
|
||||
- TUNNEL_DNS_UPSTREAM=https://1.1.1.1/dns-query,https://1.0.0.1/dns-query
|
||||
- TUNNEL_DNS_PORT=5053
|
||||
- TUNNEL_DNS_ADDRESS=0.0.0.0
|
||||
|
||||
pihole:
|
||||
environment:
|
||||
- PIHOLE_DNS_=cloudflared#5053 # Use cloudflared as upstream
|
||||
```
|
||||
|
||||
### Conditional Forwarding
|
||||
|
||||
Forward specific domains to specific DNS:
|
||||
|
||||
**Example:** Local domain to local DNS
|
||||
```bash
|
||||
# /opt/stacks/infrastructure/pihole/etc-dnsmasq.d/02-custom.conf
|
||||
server=/local/192.168.1.1
|
||||
```
|
||||
|
||||
### DHCP Server
|
||||
|
||||
Use Pi-hole as network DHCP server:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- DHCP_ACTIVE=true
|
||||
- DHCP_START=192.168.1.100
|
||||
- DHCP_END=192.168.1.200
|
||||
- DHCP_ROUTER=192.168.1.1
|
||||
- DHCP_LEASETIME=24
|
||||
- PIHOLE_DOMAIN=lan
|
||||
|
||||
ports:
|
||||
- "67:67/udp" # DHCP port
|
||||
```
|
||||
|
||||
**Steps:**
|
||||
1. Disable DHCP on router
|
||||
2. Enable DHCP in Pi-hole
|
||||
3. Restart network devices
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pi-hole Not Blocking Ads
|
||||
|
||||
```bash
|
||||
# Check if Pi-hole is receiving queries
|
||||
docker logs pihole | grep query
|
||||
|
||||
# Verify DNS is set correctly on device
|
||||
# Windows: ipconfig /all
|
||||
# Linux/Mac: cat /etc/resolv.conf
|
||||
# Should show Pi-hole IP
|
||||
|
||||
# Test DNS resolution
|
||||
nslookup ads.google.com PIHOLE_IP
|
||||
# Should return 0.0.0.0 if blocked
|
||||
|
||||
# Check gravity database
|
||||
docker exec pihole pihole -g
|
||||
```
|
||||
|
||||
### DNS Not Resolving
|
||||
|
||||
```bash
|
||||
# Check if Pi-hole is running
|
||||
docker ps | grep pihole
|
||||
|
||||
# Check DNS ports
|
||||
sudo netstat -tulpn | grep :53
|
||||
|
||||
# Test DNS
|
||||
dig @PIHOLE_IP google.com
|
||||
|
||||
# Check upstream DNS
|
||||
docker exec pihole pihole -q
|
||||
```
|
||||
|
||||
### Web Interface Not Accessible
|
||||
|
||||
```bash
|
||||
# Check container logs
|
||||
docker logs pihole
|
||||
|
||||
# Verify port mapping
|
||||
docker port pihole
|
||||
|
||||
# Access via IP
|
||||
http://SERVER_IP:8181/admin
|
||||
|
||||
# Check Traefik routing
|
||||
docker logs traefik | grep pihole
|
||||
```
|
||||
|
||||
### High CPU/Memory Usage
|
||||
|
||||
```bash
|
||||
# Check container stats
|
||||
docker stats pihole
|
||||
|
||||
# Database optimization
|
||||
docker exec pihole pihole -q database optimize
|
||||
|
||||
# Reduce query logging
|
||||
# Settings → Privacy → Anonymous mode
|
||||
|
||||
# Clear old queries
|
||||
docker exec pihole sqlite3 /etc/pihole/pihole-FTL.db "DELETE FROM queries WHERE timestamp < strftime('%s', 'now', '-7 days')"
|
||||
```
|
||||
|
||||
### False Positives (Sites Broken)
|
||||
|
||||
```bash
|
||||
# Check query log for blocked domains
|
||||
# Web UI → Query Log → Find blocked domain
|
||||
|
||||
# Whitelist domain
|
||||
docker exec pihole pihole -w problematic-domain.com
|
||||
|
||||
# Or via Web UI:
|
||||
# Whitelist → Add domain
|
||||
|
||||
# Common false positives:
|
||||
# - microsoft.com CDNs
|
||||
# - google-analytics.com (breaks some sites)
|
||||
# - doubleclick.net (ad network but some sites need it)
|
||||
```
|
||||
|
||||
### Blocklist Update Issues
|
||||
|
||||
```bash
|
||||
# Manually update gravity
|
||||
docker exec pihole pihole -g
|
||||
|
||||
# Check disk space
|
||||
df -h
|
||||
|
||||
# Clear cache
|
||||
docker exec pihole pihole -r
|
||||
# Choose: Repair
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Strong Password:** Use complex WEBPASSWORD
|
||||
2. **Authelia Protection:** Add Authelia middleware for external access
|
||||
3. **Firewall Rules:** Only expose port 53 as needed
|
||||
4. **Update Regularly:** Keep Pi-hole container updated
|
||||
5. **Backup Config:** Regular backups of `/etc/pihole` directory
|
||||
6. **Query Privacy:** Enable privacy mode for sensitive networks
|
||||
7. **Upstream DNS:** Use privacy-focused DNS (Quad9, Cloudflare)
|
||||
8. **Monitor Logs:** Watch for unusual query patterns
|
||||
9. **Network Segmentation:** Separate IoT devices
|
||||
10. **HTTPS Only:** Use HTTPS for web interface access
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
# Increase cache size
|
||||
- CACHE_SIZE=10000
|
||||
|
||||
# Disable query logging (improves performance)
|
||||
- QUERY_LOGGING=false
|
||||
|
||||
# Optimize DNS settings
|
||||
- DNSSEC=false # Disable if not needed
|
||||
```
|
||||
|
||||
**Database Maintenance:**
|
||||
```bash
|
||||
# Optimize database weekly
|
||||
docker exec pihole sqlite3 /etc/pihole/pihole-FTL.db "VACUUM"
|
||||
|
||||
# Clear old queries (keep 7 days)
|
||||
docker exec pihole pihole -f
|
||||
```
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
### Backup
|
||||
|
||||
**Via Web UI:**
|
||||
1. Settings → Teleporter
|
||||
2. Click "Backup"
|
||||
3. Download tar.gz file
|
||||
|
||||
**Via CLI:**
|
||||
```bash
|
||||
# Backup entire config
|
||||
tar -czf pihole-backup-$(date +%Y%m%d).tar.gz /opt/stacks/infrastructure/pihole/
|
||||
|
||||
# Backup only settings
|
||||
docker exec pihole pihole -a -t
|
||||
```
|
||||
|
||||
### Restore
|
||||
|
||||
**Via Web UI:**
|
||||
1. Settings → Teleporter
|
||||
2. Choose file
|
||||
3. Click "Restore"
|
||||
|
||||
**Via CLI:**
|
||||
```bash
|
||||
# Restore from backup
|
||||
tar -xzf pihole-backup-20240112.tar.gz -C /opt/stacks/infrastructure/pihole/
|
||||
docker restart pihole
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Pi-hole provides network-wide ad blocking by acting as a DNS server that filters requests before they reach the internet. It:
|
||||
- Blocks ads on all devices automatically
|
||||
- Improves browsing speed and privacy
|
||||
- Provides visibility into network DNS queries
|
||||
- Offers extensive customization
|
||||
- Protects against malware and tracking
|
||||
|
||||
**Setup Priority:**
|
||||
1. Deploy Pi-hole container
|
||||
2. Set strong admin password
|
||||
3. Configure router DNS settings
|
||||
4. Add blocklists (Firebog)
|
||||
5. Monitor dashboard
|
||||
6. Whitelist as needed
|
||||
7. Configure DoH for privacy
|
||||
8. Regular backups
|
||||
|
||||
**Remember:**
|
||||
- DNS is critical - test thoroughly before deploying
|
||||
- Keep secondary DNS as fallback
|
||||
- Some sites may break - use whitelist
|
||||
- Monitor query log initially
|
||||
- Update gravity weekly
|
||||
- Backup before major changes
|
||||
Reference in New Issue
Block a user