# Install ## debian 13 ### vps provider debian 10 install default root: ``` 8txlD7djkkKk ``` Good catch 👍 — you’re right. Debian 11 _Bullseye_ moved from the **main mirrors** to the **Debian archive repository** after its LTS phase ended in 2026. That means: - You **can still upgrade** from Debian 10 → 11 → 12 → 13, - But for Debian 11 you’ll need to point your `sources.list` to the **archive.debian.org** service, since the normal `deb.debian.org` no longer carries Bullseye. --- ## 🔧 How to Handle Missing Debian 11 (Bullseye) Repos When upgrading **Debian 10 → 11**, change your `/etc/apt/sources.list` to use the archive: ```bash sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list ``` Then explicitly set it to Bullseye: ``` deb http://archive.debian.org/debian bullseye main contrib non-free deb http://archive.debian.org/debian-security bullseye-security main contrib non-free ``` ⚠️ Important: you also need to **disable `Valid-Until` checks** (since archive metadata is old). Add this to `/etc/apt/apt.conf.d/99no-check-valid-until`: ``` Acquire::Check-Valid-Until "false"; ``` After that, `apt update` will work again for Debian 11 packages. --- ## 🔄 Recommended Path - **Debian 10 → Debian 11 (Bullseye)** using `archive.debian.org` - **Debian 11 → Debian 12 (Bookworm)** switch back to `deb.debian.org` - **Debian 12 → Debian 13 (Trixie)** upgrade normally from main repos --- ## ⚠️ Alternative Approach (Skip Hop?) Some admins **reinstall instead of multi-hop upgrades** when they’re more than 2 releases behind. It’s often faster and cleaner to install Debian 13 fresh and migrate configs/data. --- 👉 Do you want me to prepare the **exact `sources.list` entries** for each step (10 → 11, 11 → 12, 12 → 13), so you can just copy-paste them before each upgrade? ## traefik ```compose.yml services: 10:47:35 [24/1240] traefik: image: traefik:v3.4 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true networks: [traefik] ports: - "80:80" - "443:443" - "8080:8080" # dashboard volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt - ./dynamic:/dynamic:ro command: # Entrypoints - "--entrypoints.web.address=:80" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--entrypoints.web.http.redirections.entrypoint.permanent=true" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.tls=true" # Providers - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=traefik" - "--providers.file.directory=/dynamic" - "--providers.file.watch=true" # Let's Encrypt (ACME) - "--certificatesresolvers.letsencrypt.acme.email=admin@windy.me" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" # Dashboard - "--api.dashboard=true" - "--api.insecure=false" # Logging - "--log.level=INFO" - "--accesslog=true" # Metrics (optional) - "--metrics.prometheus=true" labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`npm.chans.xyz`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker" - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$wrhTVUaG$$tcchNFj..." networks: traefik: external: true ``` dashboard user and pass ``` Ahku+eRei_chu3ah ``` ``` htpasswd -nb windy "Ahku+eRei_chu3ah" ``` ``` windy:$apr1$wrhTVUaG$tcchNFj.yyA3OpK8f9XnA. ``` ## 一步改成 MASTER 执行以下命令即可统一切换类型: ``` docker compose exec -T db psql -U pdns -d pdns -c "UPDATE domains SET type='MASTER';" ``` 执行完,再确认: ``` docker compose exec -T db psql -U pdns -d pdns -c "SELECT id, name, type FROM domains ORDER BY name;" ``` 应输出: ``` id | name | type ----+-----------+--------- 7 | chans.xyz | MASTER 9 | windy.me | MASTER 8 | wsvc.info | MASTER (3 rows) ``` --- ## ✅ 一、明确两种元数据的作用 |kind|作用|主节点是否需要| |---|---|---| |`PRESIGNED`|表示该 zone 的 DNSSEC 已经签好,不需要 PowerDNS 重新签名|✅ 需要保留| |`AXFR-MASTER-TSIG`|从节点用来验证上游 master(旧主)的 TSIG 密钥|❌ 主节点不需要| --- ## 🧹 二、删除无用的 `AXFR-MASTER-TSIG` 记录 执行: ```bash docker compose exec -T db psql -U pdns -d pdns -c "DELETE FROM domainmetadata WHERE kind='AXFR-MASTER-TSIG';" ``` 验证删除结果: ```bash docker compose exec -T db psql -U pdns -d pdns -c "SELECT domain_id, kind, content FROM domainmetadata;" ``` 应该只剩: ``` domain_id | kind | content ------------+------------+--------- 7 | PRESIGNED | 1 8 | PRESIGNED | 1 9 | PRESIGNED | 1 (3 rows) ``` --- ## 🧩 三、保留 `PRESIGNED`(不要删) 这三条 `PRESIGNED` 的存在说明你的 zone 已经是“预签名区”, 也就是在数据库里已经有 DNSKEY、RRSIG、NSEC/NSEC3 等签名记录, PowerDNS 不会去重新签名,非常正确 ✅ --- ## 🧰 四、确保 `supermasters` 已清空(如果还没执行) ```bash docker compose exec -T db psql -U pdns -d pdns -c "TRUNCATE TABLE supermasters;" ``` --- ## 🚀 五、重启 PDNS 并验证主节点状态 ```bash docker compose exec auth pdnsutil list-all-zones docker compose exec auth pdnsutil check-all-zones ``` 预期输出: ``` Zone "chans.xyz." (MASTER) Zone "windy.me." (MASTER) Zone "wsvc.info." (MASTER) All zones OK ``` --- ## ✅ 六、总结(当前应保留状态) |表|应保留内容|已处理状态| |---|---|---| |domains|type=MASTER|✅| |domainmetadata|仅 `PRESIGNED`|🧹 已清理| |supermasters|空表|✅| |records / cryptokeys / tsigkeys|原样保留|✅| --- 如果你愿意,我可以帮你生成一个命令脚本,一次性完成: - 把所有域设为 MASTER - 删除 AXFR/MASTER 相关 metadata - 清空 supermasters - 验证 zone 状态 你只需执行一条命令即可让任何副节点快照变主节点。是否要我生成? ``` docker compose exec auth pdnsutil metadata set wsvc.info ALLOW-AXFR-FROM "202.91.35.141" docker compose exec auth pdnsutil metadata set windy.me ALLOW-AXFR-FROM "202.91.35.141" docker compose exec auth pdnsutil metadata set chans.xyz ALLOW-AXFR-FROM "202.91.35.141" docker compose exec auth pdnsutil metadata set wsvc.info TSIG-ALLOW-AXFR "mykey." Set 'wsvc.info' meta TSIG-ALLOW-AXFR = mykey. docker compose exec auth pdnsutil metadata set windy.me TSIG-ALLOW-AXFR "mykey." Set 'windy.me' meta TSIG-ALLOW-AXFR = mykey. docker compose exec auth pdnsutil metadata set chans.xyz TSIG-ALLOW-AXFR "mykey." Set 'chans.xyz' meta TSIG-ALLOW-AXFR = mykey. docker compose exec auth pdns_control notify windy.me docker compose exec auth pdns_control notify chans.xyz docker compose exec auth pdns_control notify wsvc.info ``` db-init/01-init.sh ```bash #!/bin/bash set -e echo "🔧 Creating PowerDNS role and databases..." psql -v ON_ERROR_STOP=1 --username "$PGUSER" <<-'EOSQL' DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'pdns') THEN CREATE USER pdns WITH PASSWORD 'windyboy'; END IF; END $$; EOSQL for dbname in pdns pdnsadmin; do if ! psql -tAc "SELECT 1 FROM pg_database WHERE datname='${dbname}'" | grep -q 1; then echo "🆕 Creating database ${dbname} owned by pdns" psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -c "CREATE DATABASE ${dbname} OWNER pdns;" else echo "✅ Database ${dbname} already exists" fi done echo "✅ Initialization finished." ``` ``` for z in windy.me chans.xyz wsvc.info; do docker compose exec auth pdnsutil zone unset-presigned $z docker compose exec auth pdnsutil zone secure $z docker compose exec auth pdnsutil zone rectify $z done ``` ``` docker compose exec auth pdnsutil zone list-all | while read z; do docker compose exec auth pdnsutil zone list "$z" > "auth/export/$z.zone" done ``` ``` labels: - "traefik.enable=true" - "traefik.http.routers.pgweb.rule=Host(`pgweb.wsvc.info`)" - "traefik.http.routers.pgweb.entrypoints=websecure" - "traefik.http.routers.pgweb.tls.certresolver=letsencrypt" - "traefik.http.services.pgweb.loadbalancer.server.port=8081" ``` ## AdGuard Home ```bash htpasswd -B -C 10 -n -b zhiqiang 6kjmnGwseQ3jlsW1 ``` ``` zhiqiang:$2y$10$IMskdbhx33L.L1TVptYad.4AhV4eQUy121/UtzwjXTR/Qa6eUUpHa ```