vault backup: 2026-01-05 13:03:55
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
|
||||
postgresql:
|
||||
dendrite/windyboy2006
|
||||
|
||||
reCAPTCHA
|
||||
key: 6LemvrUlAAAAAPqUuH_1V-lWdKAeEORzeAEhor46
|
||||
secret: 6LemvrUlAAAAAOzHkBnRH3Qxiw2q3YI0ZHdLf6Bh
|
||||
|
||||
admin:
|
||||
windy/catalog@2006
|
||||
|
||||
AccessToken: D0lJWbpHRSO4s3zfqxSvO9ZmdWJuV2iPTC5K9VijuuU
|
||||
|
||||
|
||||
matrix media repo:
|
||||
media_repo:windyboy2006@localhost:matrix_media_repo
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
打开http://192.168.1.1直接用超级管理员账户telecomadmin 密码nE7jA%5m登录;
|
||||
|
||||
|
||||
### 设备基本信息
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|设备类型:|YMe 2+1 wifi|
|
||||
|生产厂家:|SCTY|
|
||||
|设备型号:|TEWA-600AGM|
|
||||
|设备标识号:|40F420-4D84440F420AD9629|
|
||||
|硬件版本:|V1.0|
|
||||
|软件版本:|Tianyi_V1.0.P05|
|
||||
|
||||
### PON信息
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|线路协议:|GPON|
|
||||
|连接状态:|成功-已注册已认证|
|
||||
|连接时间:|717326|
|
||||
|发送光功率:|1.7|
|
||||
|接收光功率:|-19.5|
|
||||
|
||||
### 网关注册信息
|
||||
|
||||
| | |
|
||||
| ------- | --------------- |
|
||||
| 逻辑ID: | GZ0153330711821 |
|
||||
|
||||
|
||||
### 业务信息
|
||||
|
||||
| | | | | | |
|
||||
| -------- | ---- | -------------- | ------------------------------ | ------------------------------ | ---------------------- |
|
||||
| 业务类型 | 状态 | IP协议 | 连接方式 | 可用端口 | 连接名称 |
|
||||
| 上网业务 | 可用 | IPV4 | 桥接(电脑拨号) | 有线:网口1,无线:ChinaNet-vKRJ, | 1_INTERNET_B_VID_41 |
|
||||
| 可用 | IPV6 | 桥接(电脑拨号) | 有线:网口1,无线:ChinaNet-vKRJ, | 1_INTERNET_B_VID_41 | |
|
||||
| iTV | 可用 | IPV4 | 桥接 | iTV, | 1_Other_B_VID_45 |
|
||||
| 可用 | IPV6 | 桥接 | iTV, | 1_Other_B_VID_45 | |
|
||||
| 语音 | 可用 | IPV4 | 路由 | 电话 | 1_TR069_VOICE_R_VID_46 |
|
||||
| 管理 | 可用 | IPV4 | 路由 | | 1_TR069_VOICE_R_VID_46 |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
|
|
||||
|
||||
internet:
|
||||
vlan:41
|
||||
802.lp:0
|
||||
|
||||
iptv:
|
||||
vlan_id: 45
|
||||
802.1p: 5
|
||||
@@ -0,0 +1,424 @@
|
||||
|
||||
|
||||
# Matrix ESS (Community) — Single‑Node Install on Debian 13 (K3s + Traefik + cert‑manager)
|
||||
_Last updated: 2025-09-25 08:45 UTC_
|
||||
|
||||
This guide installs **Element Server Suite (ESS) Community** (Synapse + MAS + Element Web + Matrix RTC) on a **single Debian 13** node using **K3s**, **Traefik** (default in K3s), and **cert‑manager** with **Let’s Encrypt**. It is tailored to your domain choices:
|
||||
|
||||
- **serverName**: `chans.xyz`
|
||||
- **Hosts**: `synapse.chans.xyz`, `account.chans.xyz`, `chat.chans.xyz`, `mrtc.chans.xyz`
|
||||
|
||||
> Tip: if you already have K3s and cert‑manager installed and working, you can jump to **5. Values files** and **6. Install ESS**.
|
||||
|
||||
---
|
||||
|
||||
## 0) Requirements & Ports
|
||||
|
||||
- Debian 13 (root/sudo), public IPv4 (and optional IPv6).
|
||||
- DNS control for `chans.xyz`.
|
||||
- Open/forward these ports to this node:
|
||||
- **80/tcp**, **443/tcp** (ACME + HTTPS + federation)
|
||||
- **30881/tcp**, **30882/udp** (Matrix RTC SFU)
|
||||
- Time in sync (`systemd-timesyncd` or equivalent).
|
||||
|
||||
---
|
||||
|
||||
## 1) DNS Setup
|
||||
|
||||
Create A/AAAA records that point to your node’s public IP(s):
|
||||
|
||||
```
|
||||
chans.xyz A / AAAA -> <YOUR_IP>
|
||||
synapse.chans.xyz A / AAAA -> <YOUR_IP>
|
||||
account.chans.xyz A / AAAA -> <YOUR_IP>
|
||||
chat.chans.xyz A / AAAA -> <YOUR_IP>
|
||||
mrtc.chans.xyz A / AAAA -> <YOUR_IP>
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- **Do not** use a `CNAME` at the **apex** (`chans.xyz`)—use `A/AAAA`. Subdomains can be `CNAME`s if you prefer.
|
||||
- Federation relies on `https://chans.xyz/.well-known/matrix/server` which the chart serves for you.
|
||||
|
||||
---
|
||||
|
||||
## 2) (Optional) Cloud‑Init (without firewalld)
|
||||
|
||||
If you build the node via cloud‑init, this minimal config installs K3s & Helm and disables swap:
|
||||
|
||||
```yaml
|
||||
#cloud-config
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
packages: [curl, ca-certificates, gnupg, lsb-release]
|
||||
|
||||
runcmd:
|
||||
- swapoff -a
|
||||
- sed -ri 's/^[^#].*\sswap\s/## &/g' /etc/fstab
|
||||
- curl -sfL https://get.k3s.io | sh -s - server
|
||||
- mkdir -p /home/windy/.kube
|
||||
- cp /etc/rancher/k3s/k3s.yaml /home/windy/.kube/config
|
||||
- chown windy:windy /home/windy/.kube/config && chmod 600 /home/windy/.kube/config
|
||||
- bash -lc 'echo export KUBECONFIG=$HOME/.kube/config >> /home/windy/.bashrc'
|
||||
- su - windy -c "curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash"
|
||||
```
|
||||
|
||||
You can manage ports at the cloud firewall or your router (no `firewalld` required).
|
||||
|
||||
---
|
||||
|
||||
## 3) Manual K3s + Helm (if not using cloud‑init)
|
||||
|
||||
```bash
|
||||
# Install latest K3s
|
||||
curl -sfL https://get.k3s.io | sh -s - server
|
||||
|
||||
# kubeconfig for your user (replace 'windy' if needed)
|
||||
mkdir -p ~windy/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml ~windy/.kube/config
|
||||
sudo chown windy:windy ~windy/.kube/config
|
||||
chmod 600 ~windy/.kube/config
|
||||
echo 'export KUBECONFIG=$HOME/.kube/config' | sudo tee -a ~windy/.bashrc
|
||||
|
||||
# Helm
|
||||
sudo -iu windy bash -lc 'curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash'
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
kubectl get nodes -o wide
|
||||
kubectl get pods -A
|
||||
```
|
||||
|
||||
You should see the node `Ready` and `traefik` running in `kube-system`.
|
||||
|
||||
---
|
||||
|
||||
## 4) cert‑manager + Let’s Encrypt (ClusterIssuer)
|
||||
|
||||
If you haven’t installed cert‑manager yet:
|
||||
|
||||
```bash
|
||||
helm repo add jetstack https://charts.jetstack.io --force-update
|
||||
kubectl create namespace cert-manager 2>/dev/null || true
|
||||
helm install cert-manager jetstack/cert-manager -n cert-manager --set crds.enabled=true
|
||||
```
|
||||
|
||||
Create a production ClusterIssuer (`letsencrypt-prod`):
|
||||
|
||||
```yaml
|
||||
# clusterissuer.yaml
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod-private-key
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: traefik
|
||||
```
|
||||
|
||||
Apply:
|
||||
```bash
|
||||
kubectl apply -f clusterissuer.yaml
|
||||
kubectl get clusterissuer
|
||||
```
|
||||
|
||||
You should see `letsencrypt-prod READY=True`.
|
||||
|
||||
---
|
||||
|
||||
## 5) Values files (hosts + TLS)
|
||||
|
||||
Create the directory and values files:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/ess-config-values
|
||||
```
|
||||
|
||||
**`~/ess-config-values/hostnames.yaml`**
|
||||
```yaml
|
||||
serverName: chans.xyz
|
||||
|
||||
elementWeb:
|
||||
ingress:
|
||||
host: chat.chans.xyz
|
||||
|
||||
synapse:
|
||||
ingress:
|
||||
host: synapse.chans.xyz
|
||||
|
||||
matrixAuthenticationService:
|
||||
ingress:
|
||||
host: account.chans.xyz
|
||||
|
||||
matrixRTC:
|
||||
ingress:
|
||||
host: mrtc.chans.xyz
|
||||
```
|
||||
|
||||
**`~/ess-config-values/tls.yaml`**
|
||||
```yaml
|
||||
global:
|
||||
ingress:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
tls:
|
||||
enabled: true
|
||||
issuer: letsencrypt-prod
|
||||
```
|
||||
|
||||
> The TLS values ensure your Ingresses are annotated for cert‑manager and include TLS host entries so Certificates are created automatically.
|
||||
|
||||
---
|
||||
|
||||
## 6) Install ESS (matrix‑stack chart)
|
||||
|
||||
```bash
|
||||
kubectl create namespace ess 2>/dev/null || true
|
||||
|
||||
helm upgrade --install ess oci://ghcr.io/element-hq/ess-helm/matrix-stack -n ess -f ~/ess-config-values/hostnames.yaml -f ~/ess-config-values/tls.yaml --wait
|
||||
```
|
||||
|
||||
Check status:
|
||||
```bash
|
||||
kubectl get pods -n ess
|
||||
kubectl get ingress -n ess
|
||||
```
|
||||
|
||||
You should see ingresses for `synapse`, `account`, `chat`, `mrtc`, and `well-known` with `CLASS=traefik`.
|
||||
|
||||
---
|
||||
|
||||
## 7) Certificates issuance
|
||||
|
||||
Confirm the ingresses have TLS + issuer:
|
||||
```bash
|
||||
kubectl -n ess get ingress -o jsonpath='{range .items[*]}{.metadata.name}{" issuer="}{.metadata.annotations.cert-manager\.io/cluster-issuer}{" tlsHosts="}{range .spec.tls[*].hosts}{.}{" "}{end}{"\n"}{end}'
|
||||
```
|
||||
|
||||
Then watch certs:
|
||||
```bash
|
||||
kubectl get certificate -n ess
|
||||
kubectl get order,challenge -n ess
|
||||
```
|
||||
|
||||
When ready, confirm live certs:
|
||||
```bash
|
||||
for h in synapse.chans.xyz account.chans.xyz chat.chans.xyz mrtc.chans.xyz chans.xyz; do
|
||||
echo "=== $h ==="
|
||||
openssl s_client -connect "$h:443" -servername "$h" </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject -dates
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8) Well‑Known verification (federation & clients)
|
||||
|
||||
```bash
|
||||
curl -s https://chans.xyz/.well-known/matrix/server | jq .
|
||||
curl -s https://chans.xyz/.well-known/matrix/client | jq .
|
||||
```
|
||||
|
||||
Expected:
|
||||
- `server` → `{ "m.server": "synapse.chans.xyz:443" }`
|
||||
- `client` → `{ "m.homeserver": { "base_url": "https://synapse.chans.xyz" }, ... }`
|
||||
|
||||
Optional federation tester: <https://federationtester.matrix.org/#chans.xyz>
|
||||
|
||||
---
|
||||
|
||||
## 9) Create the first admin account
|
||||
|
||||
Interactive:
|
||||
```bash
|
||||
kubectl exec -n ess -it deploy/ess-matrix-authentication-service -- mas-cli manage register-user --admin
|
||||
```
|
||||
|
||||
Non‑interactive example:
|
||||
```bash
|
||||
kubectl exec -n ess deploy/ess-matrix-authentication-service -- mas-cli manage register-user --yes --admin --username admin --password 'CHANGE_ME_strong_password'
|
||||
```
|
||||
|
||||
Login at **https://chat.chans.xyz**.
|
||||
|
||||
---
|
||||
|
||||
## 10) Enable self‑registration (optional)
|
||||
|
||||
```yaml
|
||||
# ~/ess-config-values/mas-registration.yaml
|
||||
matrixAuthenticationService:
|
||||
additional:
|
||||
registration.yaml:
|
||||
config: |
|
||||
account:
|
||||
password_registration_enabled: true
|
||||
password_recovery_enabled: true
|
||||
login_with_email_allowed: true
|
||||
```
|
||||
|
||||
Apply (include this file):
|
||||
```bash
|
||||
helm upgrade --install ess oci://ghcr.io/element-hq/ess-helm/matrix-stack -n ess -f ~/ess-config-values/hostnames.yaml -f ~/ess-config-values/tls.yaml -f ~/ess-config-values/mas-registration.yaml --wait
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11) Outbound email (MAS required, Synapse optional)
|
||||
|
||||
### 11.1 MAS SMTP (required for signup/reset)
|
||||
|
||||
**Option A — inline values (simple):**
|
||||
```yaml
|
||||
# ~/ess-config-values/mas-email.yaml
|
||||
matrixAuthenticationService:
|
||||
additional:
|
||||
user-config.yaml:
|
||||
config: |
|
||||
email:
|
||||
from: '"Matrix @ chans.xyz" <noreply@chans.xyz>'
|
||||
reply_to: '"Support" <support@chans.xyz>'
|
||||
transport: smtp
|
||||
mode: starttls
|
||||
hostname: smtp.windy.me
|
||||
port: 587
|
||||
username: noreply@chans.xyz # authenticate as the sender
|
||||
password: "MAILBOX_PASSWORD"
|
||||
account:
|
||||
password_registration_enabled: true
|
||||
password_recovery_enabled: true
|
||||
login_with_email_allowed: true
|
||||
```
|
||||
|
||||
**Option B — secret ref (keeps password out of Git):**
|
||||
```bash
|
||||
cat > /tmp/mas-user-config.yaml <<'YAML'
|
||||
email:
|
||||
from: '"Matrix @ chans.xyz" <noreply@chans.xyz>'
|
||||
reply_to: '"Support" <support@chans.xyz>'
|
||||
transport: smtp
|
||||
mode: starttls
|
||||
hostname: smtp.windy.me
|
||||
port: 587
|
||||
username: noreply@chans.xyz
|
||||
password: "MAILBOX_PASSWORD"
|
||||
account:
|
||||
password_registration_enabled: true
|
||||
password_recovery_enabled: true
|
||||
login_with_email_allowed: true
|
||||
YAML
|
||||
|
||||
kubectl -n ess create secret generic mas-extra-config --from-file=user-config.yaml=/tmp/mas-user-config.yaml
|
||||
```
|
||||
|
||||
Then reference it:
|
||||
```yaml
|
||||
# ~/ess-config-values/mas-email-secretref.yaml
|
||||
matrixAuthenticationService:
|
||||
additional:
|
||||
user-config.yaml:
|
||||
configSecret: mas-extra-config
|
||||
configSecretKey: user-config.yaml
|
||||
```
|
||||
|
||||
Apply (include one of the two files above):
|
||||
```bash
|
||||
helm upgrade --install ess oci://ghcr.io/element-hq/ess-helm/matrix-stack -n ess -f ~/ess-config-values/hostnames.yaml -f ~/ess-config-values/tls.yaml -f ~/ess-config-values/mas-email.yaml --wait
|
||||
# or replace mas-email.yaml with mas-email-secretref.yaml if you used a Secret
|
||||
```
|
||||
|
||||
> **Mailcow 553 fix**: If authenticating as `zhiqiang@windy.me` and sending as `noreply@chans.xyz`, Mailcow rejects with `553 5.7.1 Sender address rejected`. Either (a) **authenticate as** `noreply@chans.xyz` by creating that mailbox in Mailcow and publishing SPF/DKIM/DMARC for `chans.xyz`; or (b) allow “send as” in Mailcow’s **Sender ACL** for `zhiqiang@windy.me`. Hosting the `chans.xyz` mailbox gives best deliverability (DKIM/DMARC alignment).
|
||||
|
||||
Monitor while testing:
|
||||
```bash
|
||||
kubectl -n ess logs deploy/ess-matrix-authentication-service -f | grep -iE 'smtp|email|send'
|
||||
```
|
||||
|
||||
### 11.2 Synapse email notifications (optional)
|
||||
```yaml
|
||||
# ~/ess-config-values/synapse-email.yaml
|
||||
synapse:
|
||||
additional:
|
||||
email.yaml:
|
||||
config: |
|
||||
email:
|
||||
smtp_host: "smtp.windy.me"
|
||||
smtp_port: 587
|
||||
smtp_user: "noreply@chans.xyz"
|
||||
smtp_pass: "MAILBOX_PASSWORD"
|
||||
require_transport_security: true
|
||||
notif_from: "Matrix on chans.xyz <noreply@chans.xyz>"
|
||||
enable_notifs: true
|
||||
```
|
||||
|
||||
Include this file in your next Helm upgrade.
|
||||
|
||||
---
|
||||
|
||||
## 12) Health checks & troubleshooting
|
||||
|
||||
**Basic:**
|
||||
```bash
|
||||
kubectl get pods,svc,ingress,certificate -n ess -o wide
|
||||
```
|
||||
|
||||
**Certs flow:**
|
||||
```bash
|
||||
kubectl get certificate,order,challenge -n ess
|
||||
kubectl describe challenge -n ess <name>
|
||||
kubectl logs -n kube-system deploy/traefik --tail=200
|
||||
```
|
||||
|
||||
**Well‑known + federation:**
|
||||
```bash
|
||||
curl -s https://chans.xyz/.well-known/matrix/server | jq .
|
||||
curl -s https://chans.xyz/.well-known/matrix/client | jq .
|
||||
```
|
||||
|
||||
**Common pitfalls:**
|
||||
- Ingresses lack TLS + `cert-manager.io/cluster-issuer` → fix `tls.yaml`.
|
||||
- `553 Sender address rejected` from Mailcow → align SMTP auth user with sender or allow “send as”, and set SPF/DKIM/DMARC for `chans.xyz`.
|
||||
- Port 80 blocked → Let’s Encrypt HTTP‑01 fails (check challenges).
|
||||
- Apex `chans.xyz` not pointing at the node → `.well-known` fails → federation fails.
|
||||
|
||||
---
|
||||
|
||||
## 13) Upgrades / Uninstall
|
||||
|
||||
Upgrade to latest chart:
|
||||
```bash
|
||||
helm repo update # if using repos
|
||||
helm upgrade --install ess oci://ghcr.io/element-hq/ess-helm/matrix-stack -n ess -f ~/ess-config-values/hostnames.yaml -f ~/ess-config-values/tls.yaml --wait
|
||||
```
|
||||
|
||||
Uninstall ESS (keeps PVCs unless you delete them):
|
||||
```bash
|
||||
helm uninstall ess -n ess
|
||||
kubectl delete namespace ess
|
||||
```
|
||||
|
||||
Reset K3s (if ever needed):
|
||||
```bash
|
||||
sudo /usr/local/bin/k3s-uninstall.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14) Quick copy‑paste checklist
|
||||
|
||||
1. DNS A/AAAA for: `chans.xyz`, `synapse.`, `account.`, `chat.`, `mrtc.` → your IP.
|
||||
2. K3s running with Traefik; cert‑manager installed; `ClusterIssuer letsencrypt-prod` **Ready**.
|
||||
3. `hostnames.yaml` with `*.ingress.host` set to your subdomains.
|
||||
4. `tls.yaml` with `global.ingress.annotations.cert-manager.io/cluster-issuer=letsencrypt-prod` and TLS enabled.
|
||||
5. `helm upgrade --install ess …` with both files.
|
||||
6. `kubectl get certificate -n ess` → `READY=True`.
|
||||
7. `/.well-known` returns correct JSON; federation tester OK.
|
||||
8. Create admin via MAS CLI; log in at `https://chat.chans.xyz`.
|
||||
9. Configure SMTP for MAS (and optionally Synapse), fix Mailcow sender policy if needed.
|
||||
@@ -0,0 +1,294 @@
|
||||
|
||||
|
||||
docker compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
networks:
|
||||
proxy:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
|
||||
traefik:
|
||||
image: "traefik"
|
||||
restart: "unless-stopped"
|
||||
command:
|
||||
- "--api=true"
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" # Ensure HTTP challenge uses the web entry point
|
||||
- "--certificatesresolvers.myresolver.acme.email=zhiqiang@windy.me" # Set your email for Let's Encrypt
|
||||
- "--certificatesresolvers.myresolver.acme.storage=/certs/acme.json" # Path to store certs
|
||||
- "--entrypoints.web.address=:80" # Entry point for HTTP
|
||||
- "--entrypoints.websecure.address=:443" # Entry point for HTTPS
|
||||
- "--log.level=DEBUG" # Set the log level (optional)
|
||||
ports:
|
||||
- "80:80" # Ensure port 80 is exposed for HTTP challenge
|
||||
- "443:443" # Port 443 for HTTPS
|
||||
- "8080:8080" # Dashboard (Optional)
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- "./certs/acme.json:/certs/acme.json"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
well-known:
|
||||
image: "nginx"
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- ./well-known:/etc/nginx/conf.d
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.well-known.entrypoints=websecure"
|
||||
- "traefik.http.routers.well-known.rule=Host(`chans.xyz`) && PathPrefix(`/.well-known`)"
|
||||
- "traefik.http.routers.well-known.tls=true"
|
||||
- "traefik.http.routers.well-known.tls.certresolver=myresolver"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
synapse:
|
||||
image: docker.io/matrixdotorg/synapse
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
|
||||
volumes:
|
||||
- ./data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "db", "5432"]
|
||||
interval: 10s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
timeout: 2s
|
||||
depends_on:
|
||||
- db
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.synapse.rule=Host(`synapse.chans.xyz`)" # Router for synapse.chans.xyz
|
||||
- "traefik.http.routers.synapse.entrypoints=websecure" # HTTPS traffic
|
||||
- "traefik.http.routers.synapse.tls=true" # Enable TLS
|
||||
- "traefik.http.routers.synapse.tls.certresolver=myresolver" # Use Let's Encrypt resolver
|
||||
- "traefik.http.services.synapse.loadbalancer.server.port=8008" # Synapse backend port
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
db:
|
||||
image: docker.io/postgres:14-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=synapse
|
||||
- POSTGRES_PASSWORD=ucdN6Upc|J,V*J0?
|
||||
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
```
|
||||
|
||||
well-known
|
||||
default.conf
|
||||
```conf
|
||||
location /.well-known/matrix/server {
|
||||
access_log off;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
default_type application/json;
|
||||
return 200 '{"m.server": "matrix.chans.xyz:443"}';
|
||||
}
|
||||
|
||||
location /.well-known/matrix/client {
|
||||
access_log off;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
default_type application/json;
|
||||
return 200 '{"m.homeserver": {"base_url": "https://app.chans.xyz"}}';
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
generate config:
|
||||
|
||||
```bash
|
||||
|
||||
docker run -it --rm --volume ./data:/data -e SYNAPSE_SERVER_NAME=chans.xyz -e SYNAPSE_REPORT_STATS=yes matrixdotorg/synapse generate
|
||||
|
||||
```
|
||||
|
||||
|
||||
homeserver.yml
|
||||
database:
|
||||
|
||||
```yaml
|
||||
name: psycopg2
|
||||
txn_limit: 10000
|
||||
args:
|
||||
user: synapse
|
||||
password: ucdN6Upc|J,V*J0?
|
||||
database: synapse
|
||||
host: synapse_db
|
||||
port: 5432
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
|
||||
```
|
||||
|
||||
|
||||
```yaml
|
||||
#
|
||||
# This is a YAML file: see [1] for a quick introduction. Note in particular
|
||||
# that *indentation is important*: all the elements of a list or dictionary
|
||||
# should have the same indentation.
|
||||
#
|
||||
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
|
||||
#
|
||||
# For more information on how to configure Synapse, including a complete accounting of
|
||||
# each option, go to docs/usage/configuration/config_documentation.md or
|
||||
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html
|
||||
server_name: "chans.xyz"
|
||||
pid_file: /data/homeserver.pid
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
database:
|
||||
name: psycopg2
|
||||
txn_limit: 10000
|
||||
args:
|
||||
user: synapse
|
||||
password: ucdN6Upc|J,V*J0?
|
||||
database: synapse
|
||||
host: synapse_db
|
||||
port: 5432
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
log_config: "/data/chans.xyz.log.config"
|
||||
media_store_path: /data/media_store
|
||||
registration_shared_secret: "lTjbS&oVJ7==Co+4YdbDxR,u7.:d+3qgofIR@9c#*1ULc;M2,*"
|
||||
report_stats: true
|
||||
macaroon_secret_key: "fe@vZvVnFFA3j:;hK;DI27;vZk@lHHk~w7foB*Q0D0nd.;tGho"
|
||||
form_secret: "G*bdHINrFR+@,A3^P=IpayYU3aluiAKcI5@L&E-f#Du:s@MgB6"
|
||||
signing_key_path: "/data/chans.xyz.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
sudo certbot --nginx -d chans.xyz -d synapse.chans.xyz
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008
|
||||
```
|
||||
|
||||
key:
|
||||
```
|
||||
EsT1 s6mK hgBT 3Cnv iYbW SNBD Bf3C LwPs nPbq dXJ8 cbbg aiEs
|
||||
```
|
||||
|
||||
|
||||
```yaml
|
||||
# The Matrix integration
|
||||
matrix:
|
||||
homeserver: https://chans.xyz
|
||||
username: "@zhiqiang:chans.xyz"
|
||||
password: "vaz6PQV5vjg1aya-mvr"
|
||||
rooms:
|
||||
- "#hass:chans.xyz"
|
||||
commands:
|
||||
- word: testword
|
||||
name: testword
|
||||
rooms:
|
||||
- "#hass:chans.xyz"
|
||||
- expression: "My name is (?P<name>.*)"
|
||||
name: introduction
|
||||
|
||||
notify:
|
||||
- name: matrix_notify
|
||||
platform: matrix
|
||||
default_room: "#hass:chans.xyz"
|
||||
|
||||
automation:
|
||||
- alias: "React to !testword"
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: matrix_command
|
||||
event_data:
|
||||
command: testword
|
||||
actions:
|
||||
- action: notify.matrix_notify
|
||||
data:
|
||||
message: "It looks like you wrote !testword"
|
||||
|
||||
- alias: "React to an introduction"
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: matrix_command
|
||||
event_data:
|
||||
command: introduction
|
||||
actions:
|
||||
- action: notify.matrix_notify
|
||||
data:
|
||||
message: "Hello {{trigger.event.data.args['name']}}"
|
||||
```
|
||||
|
||||
get token
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" -d '{
|
||||
"type": "m.login.password",
|
||||
"user": "hass",
|
||||
"password": ".P.fPdJL6.wz77q*9VjD"
|
||||
}' "https://chans.xyz/_matrix/client/r0/login"
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
syt_aGFzcw_cBpXCxWpUSawmWXXmZFL_0v4BCE
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
curl -XPOST "https://synapse.chans.xyz/_matrix/client/v3/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "m.login.password",
|
||||
"identifier": {
|
||||
"type": "m.id.user",
|
||||
"user": "zhiqiang"
|
||||
},
|
||||
"password": "vaz6PQV5vjg1aya-mvr"
|
||||
}'
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
{"access_token":"mct_yDGcVmMw2QyTiPPq4DVEHr5BPjQeqh_w1qQx1","device_id":"MryevHEy6k","user_id":"@zhiqiang:chans.xyz"}%
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
mct_yDGcVmMw2QyTiPPq4DVEHr5BPjQeqh_w1qQx1
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
matrix:
|
||||
homeserver: chans.xyz
|
||||
secret: 'wqfJ1r4cyaQbRNzGUUxjOyFf1g2hvC8F'
|
||||
endpoint: https://synapse.chans.xyz/
|
||||
|
||||
```
|
||||
@@ -0,0 +1,312 @@
|
||||
|
||||
|
||||
docker compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
networks:
|
||||
proxy:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
|
||||
traefik:
|
||||
image: "traefik"
|
||||
restart: "unless-stopped"
|
||||
command:
|
||||
- "--api=true"
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" # Ensure HTTP challenge uses the web entry point
|
||||
- "--certificatesresolvers.myresolver.acme.email=zhiqiang@windy.me" # Set your email for Let's Encrypt
|
||||
- "--certificatesresolvers.myresolver.acme.storage=/certs/acme.json" # Path to store certs
|
||||
- "--entrypoints.web.address=:80" # Entry point for HTTP
|
||||
- "--entrypoints.websecure.address=:443" # Entry point for HTTPS
|
||||
- "--log.level=DEBUG" # Set the log level (optional)
|
||||
ports:
|
||||
- "80:80" # Ensure port 80 is exposed for HTTP challenge
|
||||
- "443:443" # Port 443 for HTTPS
|
||||
- "8080:8080" # Dashboard (Optional)
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- "./certs/acme.json:/certs/acme.json"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
well-known:
|
||||
image: "nginx"
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- ./well-known:/etc/nginx/conf.d
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.well-known.entrypoints=websecure"
|
||||
- "traefik.http.routers.well-known.rule=Host(`chans.xyz`) && PathPrefix(`/.well-known`)"
|
||||
- "traefik.http.routers.well-known.tls=true"
|
||||
- "traefik.http.routers.well-known.tls.certresolver=myresolver"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
synapse:
|
||||
image: docker.io/matrixdotorg/synapse
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
|
||||
volumes:
|
||||
- ./data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "db", "5432"]
|
||||
interval: 10s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
timeout: 2s
|
||||
depends_on:
|
||||
- db
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.synapse.rule=Host(`synapse.chans.xyz`)" # Router for synapse.chans.xyz
|
||||
- "traefik.http.routers.synapse.entrypoints=websecure" # HTTPS traffic
|
||||
- "traefik.http.routers.synapse.tls=true" # Enable TLS
|
||||
- "traefik.http.routers.synapse.tls.certresolver=myresolver" # Use Let's Encrypt resolver
|
||||
- "traefik.http.services.synapse.loadbalancer.server.port=8008" # Synapse backend port
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
db:
|
||||
image: docker.io/postgres:14-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=synapse
|
||||
- POSTGRES_PASSWORD=ucdN6Upc|J,V*J0?
|
||||
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
```
|
||||
|
||||
well-known
|
||||
default.conf
|
||||
```conf
|
||||
location /.well-known/matrix/server {
|
||||
access_log off;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
default_type application/json;
|
||||
return 200 '{"m.server": "matrix.chans.xyz:443"}';
|
||||
}
|
||||
|
||||
location /.well-known/matrix/client {
|
||||
access_log off;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
default_type application/json;
|
||||
return 200 '{"m.homeserver": {"base_url": "https://app.chans.xyz"}}';
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
generate config:
|
||||
|
||||
```bash
|
||||
|
||||
docker run -it --rm --volume ./data:/data -e SYNAPSE_SERVER_NAME=chans.xyz -e SYNAPSE_REPORT_STATS=yes matrixdotorg/synapse generate
|
||||
|
||||
```
|
||||
|
||||
|
||||
homeserver.yml
|
||||
database:
|
||||
|
||||
```yaml
|
||||
name: psycopg2
|
||||
txn_limit: 10000
|
||||
args:
|
||||
user: synapse
|
||||
password: ucdN6Upc|J,V*J0?
|
||||
database: synapse
|
||||
host: synapse_db
|
||||
port: 5432
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
|
||||
```
|
||||
|
||||
|
||||
```yaml
|
||||
#
|
||||
# This is a YAML file: see [1] for a quick introduction. Note in particular
|
||||
# that *indentation is important*: all the elements of a list or dictionary
|
||||
# should have the same indentation.
|
||||
#
|
||||
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
|
||||
#
|
||||
# For more information on how to configure Synapse, including a complete accounting of
|
||||
# each option, go to docs/usage/configuration/config_documentation.md or
|
||||
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html
|
||||
server_name: "chans.xyz"
|
||||
pid_file: /data/homeserver.pid
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
database:
|
||||
name: psycopg2
|
||||
txn_limit: 10000
|
||||
args:
|
||||
user: synapse
|
||||
password: ucdN6Upc|J,V*J0?
|
||||
database: synapse
|
||||
host: synapse_db
|
||||
port: 5432
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
log_config: "/data/chans.xyz.log.config"
|
||||
media_store_path: /data/media_store
|
||||
registration_shared_secret: "lTjbS&oVJ7==Co+4YdbDxR,u7.:d+3qgofIR@9c#*1ULc;M2,*"
|
||||
report_stats: true
|
||||
macaroon_secret_key: "fe@vZvVnFFA3j:;hK;DI27;vZk@lHHk~w7foB*Q0D0nd.;tGho"
|
||||
form_secret: "G*bdHINrFR+@,A3^P=IpayYU3aluiAKcI5@L&E-f#Du:s@MgB6"
|
||||
signing_key_path: "/data/chans.xyz.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
sudo certbot --nginx -d chans.xyz -d synapse.chans.xyz
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008
|
||||
```
|
||||
|
||||
key:
|
||||
```
|
||||
EsT1 s6mK hgBT 3Cnv iYbW SNBD Bf3C LwPs nPbq dXJ8 cbbg aiEs
|
||||
```
|
||||
|
||||
|
||||
```yaml
|
||||
# The Matrix integration
|
||||
matrix:
|
||||
homeserver: https://chans.xyz
|
||||
username: "@zhiqiang:chans.xyz"
|
||||
password: "vaz6PQV5vjg1aya-mvr"
|
||||
rooms:
|
||||
- "#hass:chans.xyz"
|
||||
commands:
|
||||
- word: testword
|
||||
name: testword
|
||||
rooms:
|
||||
- "#hass:chans.xyz"
|
||||
- expression: "My name is (?P<name>.*)"
|
||||
name: introduction
|
||||
|
||||
notify:
|
||||
- name: matrix_notify
|
||||
platform: matrix
|
||||
default_room: "#hass:chans.xyz"
|
||||
|
||||
automation:
|
||||
- alias: "React to !testword"
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: matrix_command
|
||||
event_data:
|
||||
command: testword
|
||||
actions:
|
||||
- action: notify.matrix_notify
|
||||
data:
|
||||
message: "It looks like you wrote !testword"
|
||||
|
||||
- alias: "React to an introduction"
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: matrix_command
|
||||
event_data:
|
||||
command: introduction
|
||||
actions:
|
||||
- action: notify.matrix_notify
|
||||
data:
|
||||
message: "Hello {{trigger.event.data.args['name']}}"
|
||||
```
|
||||
|
||||
get token
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" -d '{
|
||||
"type": "m.login.password",
|
||||
"user": "hass",
|
||||
"password": ".P.fPdJL6.wz77q*9VjD"
|
||||
}' "https://chans.xyz/_matrix/client/r0/login"
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
syt_aGFzcw_cBpXCxWpUSawmWXXmZFL_0v4BCE
|
||||
```
|
||||
|
||||
|
||||
|
||||
new matrix ess recover key
|
||||
```
|
||||
EsTR 895B q1wv 4ibr ZRaK 9KCK 7nLc xHCm XUGX eYjh TcE5 4XSJ
|
||||
```
|
||||
|
||||
|
||||
|
||||
iris account:
|
||||
```
|
||||
Awa5noeW9vzLiPRY
|
||||
```
|
||||
|
||||
|
||||
hass account:
|
||||
```
|
||||
sgHoMmOWn8SkYJf#
|
||||
```
|
||||
|
||||
```
|
||||
kubectl -n ess exec deploy/ess-matrix-authentication-service -- mas-cli manage register-user --yes hass -p "sgHoMmOWn8SkYJf#"
|
||||
Defaulted container "matrix-authentication-service" out of: matrix-authentication-service, render-config (init), db-wait (init), database-migrate (init)
|
||||
User attributes
|
||||
Username: hass
|
||||
Matrix ID: @hass:chans.xyz
|
||||
Password: ********
|
||||
No email address provided, user will be prompted to add one
|
||||
2025-10-22T09:25:36.174135Z WARN mas_cli::commands::manage:818 No email address provided, user will need to add one
|
||||
2025-10-22T09:25:36.209840Z INFO mas_cli::commands::manage:835 User registered user.id=01K85KSXSEB2FB6MJHNKZP0BDV
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
matrix:
|
||||
homeserver: "https://chans.xyz"
|
||||
username: "@hass:chans.xyz"
|
||||
password: "sgHoMmOWn8SkYJf#"
|
||||
rooms:
|
||||
- "#guangzhou:chans.xyz"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
synapse:
|
||||
additional:
|
||||
config: |
|
||||
auto_join_rooms_for_users_on_first_login: true
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
squid:
|
||||
image: sameersbn/squid
|
||||
volumes:
|
||||
- ./squid.conf:/etc/squid/squid.conf:ro
|
||||
- squid_cache:/var/spool/squid
|
||||
ports:
|
||||
- "3128"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
nghttpx:
|
||||
image: nghttpx/nghttpx
|
||||
command: nghttpx -f /etc/nghttpx/nghttpx.conf
|
||||
volumes:
|
||||
- ./nghttpx.conf:/etc/nghttpx/nghttpx.conf:ro
|
||||
environment:
|
||||
- http_proxy=http://squid:3128
|
||||
- https_proxy=http://squid:3128
|
||||
- no_proxy=localhost,127.0.0.1,172.20.*
|
||||
ports:
|
||||
- "80"
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
|
||||
volumes:
|
||||
squid_cache:
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
name: npm
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
## dns.windy.lan
|
||||
domain: dns.windy.lan
|
||||
ip: 192.168.66.36
|
||||
root: windyboy
|
||||
user: windy/windyboy
|
||||
@@ -0,0 +1,305 @@
|
||||
|
||||
# 🌀 从 Slave 节点恢复 PowerDNS Authoritative 主节点(5.0.0 + PostgreSQL)
|
||||
|
||||
> 本文记录如何从 PowerDNS 从节点完整恢复主节点,包括数据库重建、Zone 导入、TSIG 同步与 DNSSEC 校验。
|
||||
> 适用于 **PowerDNS Authoritative 5.0.0** + **PostgreSQL gpgsql backend** 环境。
|
||||
|
||||
---
|
||||
|
||||
## 一、系统角色
|
||||
|
||||
|节点|地址|角色|说明|
|
||||
|---|---|---|---|
|
||||
|主节点|154.36.174.161|primary|新建|
|
||||
|从节点|202.91.35.141|secondary|当前持有所有 zone|
|
||||
|数据库|PostgreSQL 15|backend|gpgsql|
|
||||
|TSIG|mykey (hmac-sha512)|用于 AXFR 验证||
|
||||
|
||||
---
|
||||
|
||||
## 二、从 Slave 导出数据
|
||||
|
||||
### 1️⃣ 列出所有 zone
|
||||
|
||||
```bash
|
||||
sudo pdnsutil zone list-all
|
||||
```
|
||||
|
||||
### 2️⃣ 导出 zone 文件(PowerDNS 5.0 无 dump-zone)
|
||||
|
||||
```bash
|
||||
sudo pdnsutil zone list windy.me > /var/tmp/windy.me.zone
|
||||
sudo pdnsutil zone list wsvc.info > /var/tmp/wsvc.info.zone
|
||||
sudo pdnsutil zone list chans.xyz > /var/tmp/chans.xyz.zone
|
||||
```
|
||||
|
||||
### 3️⃣ 导出 TSIG 密钥
|
||||
|
||||
```bash
|
||||
sudo pdnsutil tsigkey list
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```
|
||||
mykey. hmac-sha512. 4es15ROFVNZh76mqbn7sVu1kodAdULYKp8I/jGAWvmH/uyxeyDwqoBiYYBKPro5M+TRkKYn7ulxZKskfKIBKNg==
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、部署主节点环境
|
||||
|
||||
### 1️⃣ 目录结构
|
||||
|
||||
```
|
||||
/opt/pdns-primary/
|
||||
├── docker-compose.yml
|
||||
├── pdns.conf
|
||||
└── db-init/
|
||||
└── 01-init.sql
|
||||
```
|
||||
|
||||
### 2️⃣ docker-compose.yml
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
services:
|
||||
pdns-db:
|
||||
image: postgres:15
|
||||
environment:
|
||||
POSTGRES_USER: pdns
|
||||
POSTGRES_PASSWORD: windyboy2006
|
||||
POSTGRES_DB: pdns
|
||||
volumes:
|
||||
- ./db-init:/docker-entrypoint-initdb.d
|
||||
- pdns-db-data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
auth:
|
||||
image: powerdns/pdns-auth-50:latest
|
||||
depends_on:
|
||||
- pdns-db
|
||||
volumes:
|
||||
- ./pdns.conf:/etc/powerdns/pdns.conf:ro
|
||||
- ./import:/import:ro
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "8081:8081"
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
pdns-db-data:
|
||||
```
|
||||
|
||||
### 3️⃣ 初始化数据库
|
||||
|
||||
`db-init/01-init.sql`:
|
||||
|
||||
```sql
|
||||
CREATE USER pdns WITH PASSWORD 'windyboy2006';
|
||||
CREATE DATABASE pdns OWNER pdns ENCODING 'UTF8';
|
||||
```
|
||||
|
||||
启动数据库:
|
||||
|
||||
```bash
|
||||
docker compose up -d pdns-db
|
||||
sleep 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、主节点配置(pdns.conf)
|
||||
|
||||
```ini
|
||||
primary=yes
|
||||
secondary=no
|
||||
launch=gpgsql
|
||||
gpgsql-host=pdns-db
|
||||
gpgsql-port=5432
|
||||
gpgsql-dbname=pdns
|
||||
gpgsql-user=pdns
|
||||
gpgsql-password=windyboy2006
|
||||
gpgsql-dnssec=yes
|
||||
|
||||
local-address=0.0.0.0
|
||||
local-port=53
|
||||
setuid=pdns
|
||||
setgid=pdns
|
||||
loglevel=4
|
||||
version-string=anonymous
|
||||
|
||||
api=yes
|
||||
api-key=SuperSecretKey
|
||||
webserver=yes
|
||||
webserver-address=0.0.0.0
|
||||
webserver-port=8081
|
||||
|
||||
default-soa-edit=INCEPTION-INCREMENT
|
||||
default-soa-edit-signed=INCEPTION-INCREMENT
|
||||
disable-axfr=no
|
||||
```
|
||||
|
||||
✅ 所有字段均为 **5.0.0 有效选项**,无 `default-soa-edit-api`。
|
||||
|
||||
---
|
||||
|
||||
## 五、导入 Zone 数据
|
||||
|
||||
### 1️⃣ 创建空 zone 并设为 master
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil zone create windy.me
|
||||
docker compose exec auth pdnsutil zone set-kind windy.me master
|
||||
|
||||
docker compose exec auth pdnsutil zone create wsvc.info
|
||||
docker compose exec auth pdnsutil zone set-kind wsvc.info master
|
||||
|
||||
docker compose exec auth pdnsutil zone create chans.xyz
|
||||
docker compose exec auth pdnsutil zone set-kind chans.xyz master
|
||||
```
|
||||
|
||||
### 2️⃣ 导入 zone 文件
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil zone load windy.me /import/windy.me.zone
|
||||
docker compose exec auth pdnsutil zone load wsvc.info /import/wsvc.info.zone
|
||||
docker compose exec auth pdnsutil zone load chans.xyz /import/chans.xyz.zone
|
||||
```
|
||||
|
||||
### 3️⃣ 如 zone 含有 RRSIG/DNSKEY,设为 presigned
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil zone set-presigned windy.me
|
||||
docker compose exec auth pdnsutil zone set-presigned wsvc.info
|
||||
docker compose exec auth pdnsutil zone set-presigned chans.xyz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、导入 TSIG 密钥并授权从节点
|
||||
|
||||
### 1️⃣ 导入 TSIG key
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil tsigkey import "mykey." hmac-sha512 "4es15ROFVNZh76mqbn7sVu1kodAdULYKp8I/jGAWvmH/uyxeyDwqoBiYYBKPro5M+TRkKYn7ulxZKskfKIBKNg=="
|
||||
```
|
||||
|
||||
### 2️⃣ 授权从节点(202.91.35.141)
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil metadata set windy.me TSIG-ALLOW-AXFR "mykey."
|
||||
docker compose exec auth pdnsutil metadata set windy.me ALLOW-AXFR-FROM "202.91.35.141"
|
||||
docker compose exec auth pdnsutil metadata set windy.me ALSO-NOTIFY "202.91.35.141"
|
||||
|
||||
docker compose exec auth pdnsutil metadata set wsvc.info TSIG-ALLOW-AXFR "mykey."
|
||||
docker compose exec auth pdnsutil metadata set wsvc.info ALLOW-AXFR-FROM "202.91.35.141"
|
||||
docker compose exec auth pdnsutil metadata set wsvc.info ALSO-NOTIFY "202.91.35.141"
|
||||
|
||||
docker compose exec auth pdnsutil metadata set chans.xyz TSIG-ALLOW-AXFR "mykey."
|
||||
docker compose exec auth pdnsutil metadata set chans.xyz ALLOW-AXFR-FROM "202.91.35.141"
|
||||
docker compose exec auth pdnsutil metadata set chans.xyz ALSO-NOTIFY "202.91.35.141"
|
||||
```
|
||||
|
||||
> ⚠️ 不带 `@mykey.`,因为已全局指定 TSIG key。
|
||||
|
||||
---
|
||||
|
||||
## 七、在从节点配置新的主节点
|
||||
|
||||
```bash
|
||||
sudo pdnsutil zone create-secondary windy.me 154.36.174.161
|
||||
sudo pdnsutil metadata set windy.me AXFR-MASTER-TSIG "mykey."
|
||||
|
||||
sudo pdnsutil zone create-secondary wsvc.info 154.36.174.161
|
||||
sudo pdnsutil metadata set wsvc.info AXFR-MASTER-TSIG "mykey."
|
||||
|
||||
sudo pdnsutil zone create-secondary chans.xyz 154.36.174.161
|
||||
sudo pdnsutil metadata set chans.xyz AXFR-MASTER-TSIG "mykey."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、触发 AXFR 同步
|
||||
|
||||
### 主节点发送 NOTIFY
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdns_control notify windy.me
|
||||
docker compose exec auth pdns_control notify wsvc.info
|
||||
docker compose exec auth pdns_control notify chans.xyz
|
||||
```
|
||||
|
||||
### 从节点主动获取
|
||||
|
||||
```bash
|
||||
sudo pdns_control retrieve windy.me
|
||||
sudo pdns_control retrieve wsvc.info
|
||||
sudo pdns_control retrieve chans.xyz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、验证结果
|
||||
|
||||
### 检查 zone 状态
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil zone list-all
|
||||
```
|
||||
|
||||
### 对比 SOA 序列号
|
||||
|
||||
```bash
|
||||
dig @154.36.174.161 soa windy.me +short
|
||||
dig @202.91.35.141 soa windy.me +short
|
||||
```
|
||||
|
||||
应相同。
|
||||
|
||||
### 查看日志
|
||||
|
||||
主节点:
|
||||
|
||||
```
|
||||
AXFR-out zone 'windy.me', client '202.91.35.141' transfer started/done
|
||||
```
|
||||
|
||||
从节点:
|
||||
|
||||
```
|
||||
AXFR done for 'windy.me'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、常见错误与修复
|
||||
|
||||
|日志|原因|修复|
|
||||
|---|---|---|
|
||||
|Signature with TSIG key failed|双方 TSIG secret 不一致|重新导入一致的 key|
|
||||
|Server Not Authoritative / Not Authorized|主节点未授权从节点|执行 metadata set ALLOW-AXFR-FROM|
|
||||
|AXFR-out denied: client has no permission|同上|增加 ALLOW-AXFR-FROM|
|
||||
|Trying to set unknown setting 'default-soa-edit-api'|配置无效|删除该字段|
|
||||
|
||||
---
|
||||
|
||||
## 十一、备份与维护
|
||||
|
||||
### 1️⃣ 数据库备份
|
||||
|
||||
```bash
|
||||
docker compose exec pdns-db pg_dump -U pdns pdns > /backup/pdns-$(date +%F).dump
|
||||
```
|
||||
|
||||
### 2️⃣ 导出所有 zone 文件
|
||||
|
||||
```bash
|
||||
mkdir -p /backup/zones
|
||||
for z in $(docker compose exec auth pdnsutil zone list-all | tr -d '\r'); do
|
||||
docker compose exec auth pdnsutil zone list "$z" > "/backup/zones/$z-$(date +%F).zone"
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
gzzn:
|
||||
410 456 544
|
||||
|
||||
password:
|
||||
```
|
||||
w42YyME_y3jVb!qa4X.c
|
||||
```
|
||||
|
||||
|
||||
win vm:
|
||||
```
|
||||
517 010 265
|
||||
```
|
||||
|
||||
password:
|
||||
```
|
||||
uW!g6CU6kteozaHUaJX*
|
||||
```
|
||||
@@ -0,0 +1,445 @@
|
||||
|
||||
|
||||
````markdown
|
||||
# Soft Serve 安装指南(Docker Compose + Traefik TCP + CNAME)
|
||||
|
||||
## 1. 目标与最终形态
|
||||
|
||||
- 域名:`repo.windy.me`
|
||||
- DNS:`repo.windy.me` **CNAME → `us2.wsvc.info`**
|
||||
- 部署主机:`us2.wsvc.info` 对应的 VPS(本文称 "us2")
|
||||
- Soft Serve 镜像:`ghcr.io/charmbracelet/soft-serve:latest`
|
||||
- 数据持久化:宿主机 `./data` → 容器 `/var/lib/soft-serve`
|
||||
- 访问方式:SSH(Soft Serve SSH 服务端口为容器内 `23231`)
|
||||
- 暴露方式(推荐):Traefik TCP entrypoint `ssh` 监听宿主机 `2222`,转发到容器 `23231`
|
||||
|
||||
---
|
||||
|
||||
## 2. 前置条件清单
|
||||
|
||||
### 2.1 DNS(CNAME)
|
||||
|
||||
你已设置:
|
||||
- `repo.windy.me` CNAME → `us2.wsvc.info`
|
||||
|
||||
关键含义:
|
||||
- 用户访问 `repo.windy.me` 时,最终会解析到 **us2 的公网 IP**
|
||||
- 只要 us2 上对外开放 SSH 入口端口(示例:2222),访问就成立
|
||||
|
||||
建议验证(任意机器):
|
||||
```bash
|
||||
dig +short repo.windy.me CNAME
|
||||
dig +short repo.windy.me A
|
||||
````
|
||||
|
||||
### 2.2 网络与防火墙
|
||||
|
||||
在 us2 上确保对外放行你用于 Soft Serve SSH 的端口(示例 2222):
|
||||
|
||||
- 入站允许:TCP 2222
|
||||
|
||||
### 2.3 Traefik 已存在并使用外部网络
|
||||
|
||||
你当前 compose 使用:
|
||||
|
||||
- external network:`vw-net`
|
||||
|
||||
确保 Traefik 容器也在同一个 `vw-net` 网络内。
|
||||
|
||||
---
|
||||
|
||||
## 3. 准备目录与配置文件
|
||||
|
||||
在 us2 上:
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/soft-serve
|
||||
cd /opt/soft-serve
|
||||
mkdir -p data
|
||||
```
|
||||
|
||||
最终结构:
|
||||
|
||||
```
|
||||
/opt/soft-serve/
|
||||
compose.yml
|
||||
.env
|
||||
data/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 准备初始化管理员公钥(必须)
|
||||
|
||||
Soft Serve 首次启动会根据环境变量写入初始管理员 key。你已经验证的公钥写法如下(单行):
|
||||
|
||||
`.env`:
|
||||
|
||||
```env
|
||||
SOFT_SERVE_INITIAL_ADMIN_KEYS=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE9irsGu03p+1xrwIfzrzjGZCcExJ/XFEgkqsgfEN70j windy@windy-mbp
|
||||
```
|
||||
|
||||
注意事项:
|
||||
|
||||
- 必须是 **完整公钥的一整行**
|
||||
- 只在 **数据目录首次初始化(空目录)** 时生效
|
||||
|
||||
---
|
||||
|
||||
## 5. Docker Compose(推荐:Traefik TCP 暴露 SSH)
|
||||
|
||||
`compose.yml`(与你当前成功的结构一致,并保留注释):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
soft-serve:
|
||||
image: ghcr.io/charmbracelet/soft-serve:latest
|
||||
container_name: soft-serve
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
SOFT_SERVE_DATA_PATH: /var/lib/soft-serve
|
||||
SOFT_SERVE_INITIAL_ADMIN: windy
|
||||
SOFT_SERVE_INITIAL_ADMIN_KEYS: ${SOFT_SERVE_INITIAL_ADMIN_KEYS}
|
||||
|
||||
volumes:
|
||||
- ./data:/var/lib/soft-serve
|
||||
|
||||
# 方案B:直连端口映射(不走 Traefik)
|
||||
# ports:
|
||||
# - "2222:23231"
|
||||
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
|
||||
# SSH over TCP via Traefik (entryPoint ssh -> container port 23231)
|
||||
- traefik.tcp.routers.softserve-ssh.entrypoints=ssh
|
||||
- traefik.tcp.routers.softserve-ssh.rule=HostSNI(`*`)
|
||||
- traefik.tcp.routers.softserve-ssh.tls=false
|
||||
- traefik.tcp.services.softserve-ssh.loadbalancer.server.port=23231
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
name: vw-net
|
||||
```
|
||||
|
||||
### 关于 "SSH 不能走 Traefik 代理域名分流"的结论
|
||||
|
||||
- SSH 不是 HTTP;Traefik 在这里是 **TCP 转发**
|
||||
- 不要使用 `HostSNI(repo.windy.me)` 之类的规则来"按域名"分流 SSH(会引发 TLS/HostSNI 相关报错)
|
||||
- 最稳妥的做法就是:
|
||||
- `tls=false`
|
||||
- `HostSNI('*')`
|
||||
- 依赖端口入口(2222)
|
||||
|
||||
---
|
||||
|
||||
## 6. Traefik 静态配置要求(必须有 entrypoint)
|
||||
|
||||
你必须在 Traefik 的静态配置中定义 `ssh` entrypoint,并监听对外端口(示例:2222)。
|
||||
|
||||
示例(只示意关键段):
|
||||
|
||||
```yaml
|
||||
entryPoints:
|
||||
ssh:
|
||||
address: ":2222"
|
||||
```
|
||||
|
||||
如果缺失,会出现典型错误:
|
||||
|
||||
- `EntryPoint doesn't exist entryPointName=ssh`
|
||||
|
||||
---
|
||||
|
||||
## 7. 首次启动与"只初始化一次"的规则
|
||||
|
||||
### 7.1 首次启动
|
||||
|
||||
在 `/opt/soft-serve`:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### 7.2 初始化只发生一次(关键规则)
|
||||
|
||||
如需重新初始化(比如 `.env` 修改后不生效),必须清空数据目录:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
rm -rf ./data
|
||||
mkdir -p ./data
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 客户端连接与"user not found"修正方法
|
||||
|
||||
### 8.1 强制使用指定 key(排错与首次推荐)
|
||||
|
||||
你最终验证成功的关键点是:**固定 key + IdentitiesOnly**。
|
||||
|
||||
```bash
|
||||
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||
```
|
||||
|
||||
若成功会输出类似:
|
||||
|
||||
```
|
||||
Username: admin (或 windy)
|
||||
Admin: true
|
||||
Public keys: ...
|
||||
```
|
||||
|
||||
### 8.2 把默认用户名从 `admin` 改成 `windy`
|
||||
|
||||
你已成功的改名命令(注意同样要固定 key):
|
||||
|
||||
```bash
|
||||
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me set-username windy
|
||||
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||
```
|
||||
|
||||
**解释:**"user not found" 的真实根因通常不是 Soft Serve 没用户,而是 SSH 客户端未固定 key 时选用了另一把 key,导致 Soft Serve 无法把该连接映射到已存在的用户。
|
||||
|
||||
### 8.3 永久固化:写 `~/.ssh/config`
|
||||
|
||||
在本机写入:
|
||||
|
||||
```sshconfig
|
||||
Host repo.windy.me
|
||||
HostName repo.windy.me
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
IdentitiesOnly yes
|
||||
```
|
||||
|
||||
之后即可:
|
||||
|
||||
```bash
|
||||
ssh repo.windy.me info
|
||||
ssh repo.windy.me repo list
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 创建仓库与 Git clone/push
|
||||
|
||||
### 9.1 创建仓库
|
||||
|
||||
```bash
|
||||
ssh repo.windy.me repo create test
|
||||
ssh repo.windy.me repo list
|
||||
```
|
||||
|
||||
### 9.2 Clone(推荐写法)
|
||||
|
||||
写法 A(最清晰):
|
||||
|
||||
```bash
|
||||
git clone ssh://repo.windy.me:2222/test.git
|
||||
```
|
||||
|
||||
写法 B(scp 风格,依赖 ssh config 的 Port):
|
||||
|
||||
```bash
|
||||
git clone repo.windy.me:test.git
|
||||
```
|
||||
|
||||
### 9.3 Push 验证
|
||||
|
||||
```bash
|
||||
cd test
|
||||
echo "# test" > README.md
|
||||
git add .
|
||||
git commit -m "init"
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 常见故障排查(快速定位)
|
||||
|
||||
### 10.1 连接到错误端口
|
||||
|
||||
现象:你以为是 23231,但实际对外是 2222(由 Traefik entrypoint 决定)。
|
||||
|
||||
验证(在 us2 上):
|
||||
|
||||
```bash
|
||||
ss -lntp | grep :2222
|
||||
```
|
||||
|
||||
应看到 Traefik 监听 2222。
|
||||
|
||||
### 10.2 `EntryPoint doesn't exist entryPointName=ssh`
|
||||
|
||||
原因:Traefik 静态配置未定义 `entryPoints.ssh`。
|
||||
|
||||
修复:给 Traefik 增加:
|
||||
|
||||
```yaml
|
||||
entryPoints:
|
||||
ssh:
|
||||
address: ":2222"
|
||||
```
|
||||
|
||||
并重启 Traefik。
|
||||
|
||||
### 10.3 `Error: user not found`
|
||||
|
||||
高概率原因:SSH 客户端用了"另一把 key"。
|
||||
|
||||
修复(强制固定 key):
|
||||
|
||||
```bash
|
||||
ssh -vvv -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||
```
|
||||
|
||||
观察日志中是否出现:
|
||||
|
||||
- `Offering public key: ... id_ed25519`
|
||||
- `Server accepts key: ... id_ed25519`
|
||||
|
||||
---
|
||||
|
||||
## 11. 备份与恢复(生产建议)
|
||||
|
||||
### 11.1 需要备份的内容
|
||||
|
||||
Soft Serve 核心数据都在宿主机 `./data`(映射自 `/var/lib/soft-serve`):
|
||||
|
||||
- `soft-serve.db`(用户/设置)
|
||||
- `repos/`(仓库数据,如存在)
|
||||
- `ssh/`(host keys 等)
|
||||
|
||||
### 11.2 最简单备份命令
|
||||
|
||||
在 us2 上:
|
||||
|
||||
```bash
|
||||
cd /opt/soft-serve
|
||||
tar -czf soft-serve-backup-$(date +%F).tar.gz ./data
|
||||
```
|
||||
|
||||
恢复流程:
|
||||
|
||||
1. `docker compose down`
|
||||
2. 解压覆盖 `./data`
|
||||
3. `docker compose up -d`
|
||||
|
||||
---
|
||||
|
||||
## 12. 推荐的"最终检查清单"
|
||||
|
||||
- `repo.windy.me` CNAME 指向 `us2.wsvc.info`,并能解析到 us2 IP
|
||||
- us2 对外开放 TCP 2222
|
||||
- Traefik 静态配置存在 `entryPoints.ssh=:2222`
|
||||
- Soft Serve 数据目录持久化:`./data:/var/lib/soft-serve`
|
||||
- 客户端 `~/.ssh/config` 固定 `IdentityFile` + `IdentitiesOnly yes`
|
||||
- `ssh repo.windy.me info` 输出 `Username: windy` 且 `Admin: true`
|
||||
|
||||
---
|
||||
|
||||
## 附录:生产级配置建议(可选)
|
||||
|
||||
### A.1 生产级 compose(healthcheck、日志限制、只读 filesystem、资源限制)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
soft-serve:
|
||||
image: ghcr.io/charmbracelet/soft-serve:latest
|
||||
container_name: soft-serve
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
SOFT_SERVE_DATA_PATH: /var/lib/soft-serve
|
||||
SOFT_SERVE_INITIAL_ADMIN: windy
|
||||
SOFT_SERVE_INITIAL_ADMIN_KEYS: ${SOFT_SERVE_INITIAL_ADMIN_KEYS}
|
||||
|
||||
volumes:
|
||||
- ./data:/var/lib/soft-serve:rw
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.tcp.routers.softserve-ssh.entrypoints=ssh
|
||||
- traefik.tcp.routers.softserve-ssh.rule=HostSNI(`*`)
|
||||
- traefik.tcp.routers.softserve-ssh.tls=false
|
||||
- traefik.tcp.services.softserve-ssh.loadbalancer.server.port=23231
|
||||
|
||||
# 健康检查
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "localhost", "23231"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# 资源限制
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.25'
|
||||
|
||||
# 安全设置
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:size=100M,mode=1777
|
||||
|
||||
# 日志限制
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
name: vw-net
|
||||
```
|
||||
|
||||
### A.2 Traefik 静态配置片段
|
||||
|
||||
示例 Traefik 静态配置(`traefik.yml` 或命令行参数):
|
||||
|
||||
```yaml
|
||||
# traefik.yml 示例
|
||||
entryPoints:
|
||||
ssh:
|
||||
address: ":2222"
|
||||
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
network: vw-net
|
||||
```
|
||||
|
||||
或通过命令行参数:
|
||||
|
||||
```bash
|
||||
--entrypoints.ssh.address=:2222
|
||||
```
|
||||
|
||||
---
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
service key:
|
||||
```
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFldWRtbGdvc2p2dnJzbWxkY3RrIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc2NTUwMjMyOCwiZXhwIjoyMDgxMDc4MzI4fQ.2rujZwkqatXYyvNwr4hkAWgSGi2q-FqWREicE-5sFBA
|
||||
```
|
||||
|
||||
|
||||
url:
|
||||
```
|
||||
https://qeudmlgosjvvrsmldctk.supabase.co
|
||||
```
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
|
||||
# WSVC
|
||||
|
||||
Client Secret
|
||||
211073924279107589@wsvc.info
|
||||
|
||||
|
||||
wsvc project:
|
||||
211074961312382981@wsvc.info
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
## Docker + firewalld + iptables 关系总结
|
||||
|
||||
### 1. 三者分工
|
||||
|
||||
- **iptables**:内核防火墙引擎,真正执行包过滤和 NAT。
|
||||
- **firewalld**:iptables 的“策略管理层”,按 **zone / service / masquerade** 等抽象生成规则。
|
||||
- **Docker(iptables=true)**:在 iptables 中写入 **容器相关** 的规则:
|
||||
- 容器出网 SNAT(MASQUERADE)
|
||||
- 宿主端口 → 容器端口的 DNAT
|
||||
- 容器网络之间的隔离(DOCKER-ISOLATION)
|
||||
|
||||
三者是“共用 iptables,各管一摊”,不是互相替代。
|
||||
|
||||
---
|
||||
|
||||
### 2. Docker 关键配置项
|
||||
|
||||
`/etc/docker/daemon.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"iptables": true,
|
||||
"ip-masq": true
|
||||
}
|
||||
```
|
||||
|
||||
- `"iptables": true`(默认)
|
||||
- Docker 创建/维护 DOCKER 链、端口映射、容器出网 NAT 等规则。
|
||||
- 必须开启,否则大多数容器网络功能会坏(包括端口映射、bridge 容器出网)。
|
||||
|
||||
- `"iptables": false`
|
||||
- Docker 不再改 iptables,**不再创建 DOCKER/NAT 规则**。
|
||||
- 需要你手工写所有 NAT / 端口映射规则。
|
||||
- 常见现象:宿主机 & `--network host` 容器有网,但所有 bridge 容器出不了网。
|
||||
|
||||
- `"ip-masq": true`
|
||||
- 为 Docker 私网(如 172.17.0.0/16)自动加 MASQUERADE,容器可用宿主 IP 出网。
|
||||
|
||||
---
|
||||
|
||||
### 3. firewalld 与 Docker 的协作方式
|
||||
|
||||
典型做法(推荐):
|
||||
|
||||
1. 保持 Docker 使用 iptables:
|
||||
```json
|
||||
{
|
||||
"iptables": true,
|
||||
"ip-masq": true
|
||||
}
|
||||
```
|
||||
2. 在 firewalld 里:
|
||||
- 为 `docker0`、`br-xxxx` 等网桥分配到 `docker` zone:
|
||||
```bash
|
||||
firewall-cmd --zone=docker --add-interface=docker0 --permanent
|
||||
firewall-cmd --zone=docker --add-interface=br-xxxx --permanent
|
||||
```
|
||||
- 打开 masquerade 与 forward:
|
||||
```bash
|
||||
firewall-cmd --zone=docker --add-masquerade --permanent
|
||||
firewall-cmd --zone=docker --add-forward --permanent
|
||||
firewall-cmd --reload
|
||||
```
|
||||
|
||||
**原则:**
|
||||
|
||||
- Docker 负责:**容器内部路由 + NAT + 端口映射的具体规则**;
|
||||
- firewalld 负责:**哪些接口/zone 允许转发、伪装、对外开放哪些端口**。
|
||||
|
||||
---
|
||||
|
||||
### 4. 典型坑点(本次踩到的)
|
||||
|
||||
- 设置:
|
||||
|
||||
```json
|
||||
{
|
||||
"iptables": false
|
||||
}
|
||||
```
|
||||
|
||||
- 结果:
|
||||
- 宿主机有网;
|
||||
- `--network host` 容器有网;
|
||||
- 所有 bridge 网络容器无外网、访问 LE 超时。
|
||||
- 根因:
|
||||
- Docker 停止管理 iptables,不再生成容器 NAT 规则;
|
||||
- firewalld 只负责 zone 和 masquerade,但**不知道容器网络细节**,无法替 Docker 完成 SNAT/端口映射。
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
|
||||
```
|
||||
create database vaultwarden;
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
CREATE USER vaultwarden WITH ENCRYPTED PASSWORD 'windysecurity';
|
||||
GRANT ALL PRIVILEGES ON DATABASE vaultwarden TO vaultwarden;
|
||||
```
|
||||
|
||||
|
||||
```bitwarden.load
|
||||
LOAD DATABASE
|
||||
FROM sqlite:///opt/vaultwarden/vw-data/db.sqlite3
|
||||
INTO postgresql://vaultwarden:windysecurity@localhost:5432/vaultwarden
|
||||
|
||||
WITH include drop, create tables, create indexes, reset sequences
|
||||
EXCLUDING TABLE NAMES LIKE '__diesel_schema_migrations'
|
||||
ALTER SCHEMA 'main' RENAME TO 'public'
|
||||
;
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
pgloader bitwarden.load
|
||||
```
|
||||
|
||||
```
|
||||
-- Grant usage and create permissions on the public schema
|
||||
GRANT USAGE ON SCHEMA public TO vaultwarden;
|
||||
GRANT CREATE ON SCHEMA public TO vaultwarden;
|
||||
|
||||
-- Optionally, grant all permissions on the public schema
|
||||
GRANT ALL ON SCHEMA public TO vaultwarden;
|
||||
|
||||
-- Transfer ownership of the public schema to vaultwarden (optional)
|
||||
ALTER SCHEMA public OWNER TO vaultwarden;
|
||||
|
||||
```
|
||||
|
||||
|
||||
```.env
|
||||
DOMAIN="https://auth.wsvc.info/"
|
||||
DATABASE_URL=postgresql://vaultwarden:windysecurity@172.18.0.1:5432/vaultwarden
|
||||
SMTP_HOST=smtp.windy.me
|
||||
SMTP_FROM=<vnet@windy.me>
|
||||
SMTP_PORT=587
|
||||
SMTP_SECURITY=starttls
|
||||
SMTP_USERNAME=vnet@windy.me
|
||||
SMTP_PASSWORD=windyboy2006
|
||||
```
|
||||
|
||||
```admin token
|
||||
i8aHqBZvgTjCoHKRqMqHxmbFs3JFwWnrzPuub09sUnYKTfwZ7m1VCKXABlSxRkJ6
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
echo -n "VjoM4sndg4.8uCzPmodH" | argon2 "$(openssl rand -base64 32)" -e -id -k 19456 -t 2 -p 1
|
||||
```
|
||||
|
||||
```
|
||||
$argon2id$v=19$m=19456,t=2,p=1$eXhRMTBiVXRjR2pFalpRYStCQys1SmtkaGVONTFJWm9HQmNMVDg2ZGlkVT0$ssdf1xrdTwXP7S7xoRiams1R3nGeSS3dkuKcPD/sO90
|
||||
```
|
||||
|
||||
```
|
||||
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$d3Pa5o/TrvEhaVvj/bypWSnBqIFjU/rqkRV+Th7KmHU$ZDwdhqyIrTTvnAsIAUURjN3t3bgNWJfEh8Mv2cY0gUs'
|
||||
```
|
||||
Reference in New Issue
Block a user