# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# USER CONFIGURATION
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# On the first run, leave cfRecordId empty "".
# Once you get the ID from the Log, paste it here (e.g., :local cfRecordId "abcdef123456...")
:local cfRecordId ""
:local cfToken "YOUR_CLOUDFLARE_API_TOKEN"
:local cfZoneId "YOUR_CLOUDFLARE_ZONE_ID"
:local cfRecordName "ddns.domain.com"
:local wanInterface "ether1"
# Specify the DNS server used to resolve your Cloudflare domain IP (e.g., 1.1.1.1 or 8.8.8.8)
:local dnsServer "1.1.1.1"
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# AUTOMATIC PROCESS (Determined by the cfRecordId status above)
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:local httpHeaders "Authorization: Bearer $cfToken"
# If cfRecordId is empty, fetch the ID from Cloudflare and print it to the log
:if ([:len $cfRecordId] = 0) do={
:log warning "CF-DDNS: [STEP 1] cfRecordId is EMPTY. Fetching ID from Cloudflare..."
:local getUrl "https://api.cloudflare.com/client/v4/zones/$cfZoneId/dns_records"
:local fetchResult ""
:do {
:set fetchResult [/tool fetch url=$getUrl http-header-field=$httpHeaders as-value output=user]
} on-error={
:log error "CF-DDNS: Failed to connect to Cloudflare API. Check your Token/Zone ID."
}
:if ($fetchResult != "") do={
:local responseData ($fetchResult->"data")
:local idKeyword "\"id\":\""
:local idPos [:find $responseData $idKeyword]
:if ($idPos > 0) do={
:local idStart ($idPos + [:len $idKeyword])
:local idEnd [:find $responseData "\"" $idStart]
:local fetchedId [:pick $responseData $idStart $idEnd]
# Action required: Print the Record ID to the log for copying
:log error "=========================================================="
:log warning "CF-DDNS: [SUCCESS] Your Record ID is: $fetchedId"
:log warning "CF-DDNS: Please copy this ID and paste it into ':local cfRecordId \"\"' at the top of this script!"
:log error "=========================================================="
} else={
:log error "CF-DDNS: DNS Record Name not found on Cloudflare. Please check your spelling."
}
}
} else={
# If cfRecordId is provided, proceed to check IP and update DDNS
:local currentIp [/ip address get [/ip address find interface=$wanInterface] address]
:set currentIp [:pick $currentIp 0 [:find $currentIp "/"]]
:local cloudflareIp ""
:do {
# Resolve the domain using the specific DNS resolver configured above
:set cloudflareIp [:resolve $cfRecordName server=$dnsServer]
} on-error={
:log info "CF-DDNS: Cannot resolve $cfRecordName via $dnsServer, proceeding to check update."
}
# Only execute API update if the WAN IP has changed
:if ($currentIp != $cloudflareIp) do={
:log info "CF-DDNS: IP changed from $cloudflareIp to $currentIp. Updating Cloudflare..."
:local putUrl ("https://api.cloudflare.com/client/v4/zones/" . $cfZoneId . "/dns_records/" . $cfRecordId)
:local putData "{\"type\":\"A\",\"name\":\"$cfRecordName\",\"content\":\"$currentIp\",\"ttl\":300,\"proxied\":false}"
:do {
/tool fetch url=$putUrl http-method=put http-data=$putData http-header-field=$httpHeaders as-value output=user
:log info "CF-DDNS: Successfully updated $cfRecordName to $currentIp"
} on-error={
:log error "CF-DDNS: Failed to update IP on Cloudflare."
}
}
}
leakung
28 กรกฎาคม 2569
Mikrotik script for update cloudflare DNS IP
27 มิถุนายน 2569
Mikrotik container : zerotier router
/interface bridge
add name=containers
/ip address
add address=172.17.0.1/24 interface=containers
/interface veth
add address=172.17.0.2/24 gateway=172.17.0.1 name=veth-zerotier
/interface bridge port
add bridge=containers interface=veth-zerotier
/container envs
add list=zerotier key=ZEROTIER_ONE_GATEWAY_MODE value=both
add list=zerotier key=ZEROTIER_ONE_LOCAL_PHYS value=veth-zerotier
add list=zerotier key=ZEROTIER_ONE_NETWORK_IDS value=0d66ea7479dd0d63
add list=zerotier key=ZEROTIER_ONE_USE_IPTABLES_NFT value=true
/container mounts
add list=zerotier src=/zerotier-lib dst=/var/lib/zerotier-one
/container
add interface=veth-zerotier \
name=zerotier:router \
remote-image=ghcr.io/zyclonite/zerotier:router \
root-dir=/disk1/zerotier \
envlists=zerotier \
mountlists=zerotier \
logging=yes\
start-on-boot=yes
Ref : https://github.com/zyclonite/zerotier-docker
16 มิถุนายน 2569
dig kdig doggo
DoT
dig @dns.google example.com +tls (+tls-ca)
kdig @dns.google example.com +tls (+tls-ca) (-d)
doggo @tls://dns.google example.com
DoH
dig @dns.google example.com +https (+tls-ca)
kdig @dns.google example.com +https (+tls-ca) (-d)
doggo @https://dns.google/dns-query example.com
dig ไม่มีการตรวจสอบ TLS certificate โดยค่าเริ่มต้น ต้องใช้ +tls-ca
kdig ไม่มีการตรวจสอบ TLS certificate โดยค่าเริ่มต้น ต้องใช้ +tls-ca และใช้ -d เพื่อแสดงข้อมูล TLS certificate
doggo มีการตรวจสอบ TLS Certificate โดยค่าเริ่มต้น (Default) อยู่แล้ว
29 พฤษภาคม 2569
Mikrotik container : PowerDNS DNSdist
/interface veth
add address=10.0.0.20/24 gateway=10.0.0.1 name=veth-dnsdist
/interface bridge port
add bridge=br-lan interface=veth-dnsdist
/file
add name="/dnsdist-conf/dnsdist.conf" \
contents="setLocal('0.0.0.0:53')\n\
\n\
setACL(\"0.0.0.0/0\")\n\
\n\
webserver(\"0.0.0.0:8083\")\n\
setWebserverConfig({\n\
\tpassword=hashPassword(\"admin\"),\n\
\tapiKey=hashPassword(\"admin\"),\n\
\tacl=\"0.0.0.0/0\"\n\
})\n\
\n\
newServer({\n\
\tname=\"cloudflare-DoT\",\n\
\taddress=\"1.1.1.1:853\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"1.1.1.1\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"cloudflare-dns.com\"\n\
})\n\
\n\
newServer({\n\
\tname=\"google-DoT\",\n\
\taddress=\"8.8.8.8:853\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"8.8.8.8\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"dns.google\"\n\
})\n\
\n\
newServer({\n\
\tname=\"quad9-DoT\",\n\
\taddress=\"9.9.9.9:853\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"9.9.9.9\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"dns.quad9.com\"\n\
})\n\
\n\
newServer({\n\
\tname=\"cloudflare-DoH\",\n\
\taddress=\"1.1.1.1:443\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"1.1.1.1\",\n\
\tdohPath=\"/dns-query\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"cloudflare-dns.com\"\n\
})\n\
\n\
newServer({\n\
\tname=\"google-DoH\",\n\
\taddress=\"8.8.8.8:443\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"8.8.8.8\",\n\
\tdohPath=\"/dns-query\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"dns.google\"\n\
})\n\
\n\
newServer({\n\
\tname=\"quad9-DoH\",\n\
\taddress=\"9.9.9.9:443\",\n\
\ttls=\"openssl\",\n\
\tsubjectName=\"9.9.9.9\",\n\
\tdohPath=\"/dns-query\",\n\
\tvalidateCertificates=true,\n\
\tpool=\"main-pool\",\n\
\n\
\thealthCheckMode = \"lazy\",\n\
\tcheckInterval = 30,\n\
\tmaxCheckFailures = 3,\n\
\trise = 2,\n\
\tcheckName = \"dns.quad9.com\"\n\
})\n\
\n\
setServerPolicy(leastOutstanding)\n\
\n\
global_cache = newPacketCache(10000)\n\
getPool(\"main-pool\"):setCache(global_cache)\n\
\n\
addAction(AllRule(), PoolAction(\"main-pool\"))\n"
/container/mounts
add list=dnsdist-conf src="/dnsdist-conf/dnsdist.conf" dst="/etc/dnsdist/dnsdist.conf"
/container
add name=dnsdist \
interface=veth-dnsdist \
remote-image="registry-1.docker.io/powerdns/dnsdist-19:latest" \
mountlists=dnsdist-conf \
root-dir="/dnsdist-root" \
user=0 \
start-on-boot=yes \
logging=yes
Mikrotik container : AdGuard DNS Proxy
/interface veth
add address=10.0.0.20/24 gateway=10.0.0.1 name=veth-dnsproxy
/interface bridge port
add bridge=br-lan interface=veth-dnsproxy
/container
add name=dnsproxy \
interface=veth-dnsproxy \
remote-image=registry-1.docker.io/adguard/dnsproxy:latest \
root-dir=/dnsproxy \
cmd="--upstream-mode parallel \
-u h3://1.1.1.1/dns-query \
-u h3://8.8.8.8/dns-query \
-u h3://9.9.9.9/dns-query \
-u tls://1.1.1.1 \
-u tls://8.8.8.8 \
-u tls://9.9.9.9 \
-u quic://9.9.9.9" \
start-on-boot=yes \
logging=yes
02 มีนาคม 2569
Crowdsec command
cscli decisions list
ดูรายชื่อ IP ที่โดนแบนอยู่ทั้งหมด (Local + CAPI)
cscli decisions list --origin CAPI
cscli decisions list --origin CAPI | wc -l
ดูเฉพาะ IP มหาโจรจากส่วนกลาง (Community List)
cscli decisions add --ip 1.2.3.4 --duration 1h
สั่งแบน IP 1.2.3.4 เป็นเวลา 1 ชั่วโมง
cscli decisions delete --ip 1.2.3.4
ปลดแบน IP 1.2.3.4 (Whitelist คืนมา)
cscli decisions delete --all
ล้างรายการแบนทั้งหมด (ใช้ตอนเผลอบล็อกตัวเองยกแผง)
cscli bouncers list
เช็คว่า Traefik Bouncer ยัง Online (✔️) อยู่ไหม
cscli bouncers add <name>
สร้าง API Key ชุดใหม่ (เอาไปใส่ใน Traefik Middleware)
cscli bouncers delete <name>
ลบ Bouncer ที่ไม่ได้ใช้งานแล้ว
cscli capi register
ลงทะเบียนเครื่องนี้กับส่วนกลาง (ทำครั้งแรกครั้งเดียว)
cscli capi status
เพื่อเช็คการเชื่อมต่อส่วนกลาง
cscli metrics
สำคัญมาก! ดูว่า CrowdSec อ่าน Log ไปกี่บรรทัด และบล็อกไปกี่ครั้ง
cscli alerts list
ดูเหตุการณ์ที่ CrowdSec ตรวจพบ (ใคร ทำอะไร ที่ไหน)
cscli alerts inspect <ID>
ดูรายละเอียดเชิงลึกของ Alert นั้นๆ (เช่น Log บรรทัดที่เป็นปัญหา)
cscli hub update
อัปเดตรายชื่อ Scenario ล่าสุด (เหมือน Update Antivirus)
cscli hub upgrade
สังอัปเกรด Scenario ที่ติดตั้งไว้ให้เป็นเวอร์ชันใหม่
cscli collections list
"ดูว่าเราติดตั้งการป้องกันอะไรไว้บ้าง (Traefik, HTTP, etc.)"
cscli collections install <name>
ติดตั้งการป้องกันเพิ่ม (เช่น crowdsecurity/wordpress)
22 ธันวาคม 2568
traefix wildcard SSL with muli provider
docker-compose.yml
services:
traefik:
image: traefik:v3.6
container_name: traefik-test
restart: unless-stopped
networks:
- traefik_net
ports:
- "80:80"
- "443:443"
- "8080:8080"
environment:
- CF_DNS_API_TOKEN=${CLOUDFLARE_TOKEN}
- SPACESHIP_API_KEY=${SPACESHIP_API_KEY}
- SPACESHIP_API_SECRET=${SPACESHIP_API_SECRET}
volumes:
- ./traefik:/etc/traefik:ro
- ./letsencrypt:/letsencrypt
command:
- --configFile=/etc/traefik/traefik_config.yml
php-apache:
image: php:8.4-apache
container_name: php-apache-test
restart: unless-stopped
networks:
- traefik_net
volumes:
- ./php-src:/var/www/html
networks:
traefik_net:
driver: bridge
traefik_config.yml
entryPoints:
websecure:
address: ":443"
http:
tls:
certResolver: cloudflare-resolver
domains:
- main: "domain1.com"
sans:
- "*.domain1.com"
providers:
file:
filename: "/etc/traefik/dynamic_conf.yml"
watch: true
certificatesResolvers:
cloudflare-resolver:
acme:
email: your-email@example.com
storage: /etc/traefik/acme-cloudflare.json
dnsChallenge:
provider: cloudflare
spaceship-resolver:
acme:
email: your-email@example.com
storage: /etc/traefik/acme-spaceship.json
dnsChallenge:
provider: spaceship # New in lego/traefik 2025
dynamic_config.yml
http:
routers:
# --- CLOUDFLARE DOMAIN (Inherits from Entrypoint) ---
router1:
rule: "Host(`app1.domain1.com`)"
entryPoints: ["websecure"]
service: "service1"
tls: {} # Uses cloudflare-resolver & wildcard automatically
router2:
rule: "Host(`app2.domain1.com`)"
entryPoints: ["websecure"]
service: "service2"
tls: {} # Uses cloudflare-resolver & wildcard automatically
# --- SPACESHIP DOMAIN (Manual Override) ---
router3:
rule: "Host(`app3.domain2.com`)"
entryPoints: ["websecure"]
service: "service3"
tls:
certResolver: "spaceship-resolver"
domains:
- main: "domain2.com"
sans: ["*.domain2.com"] # Triggers wildcard issuance
router4:
rule: "Host(`app4.domain2.com`)"
entryPoints: ["websecure"]
service: "service4"
tls:
certResolver: "spaceship-resolver"
# No domains block needed! It reuses the cert from Router 3
services:
service1:
loadBalancer:
servers: [{ url: "http://172.18.0.11:80" }]
service2:
loadBalancer:
servers: [{ url: "http://172.18.0.12:80" }]
service3:
loadBalancer:
servers: [{ url: "http://172.18.0.13:80" }]
service4:
loadBalancer:
servers: [{ url: "http://172.18.0.14:80" }]
สมัครสมาชิก:
บทความ (Atom)