377 lines
9.1 KiB
Markdown
377 lines
9.1 KiB
Markdown
|
||
|
||
# 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
|
||
```
|
||
|
||
|