20 ธันวาคม 2568

Unifi Network Application docker compose

 name: unifi-network-application
services:
  unifi-db:
    container_name: unifi-db
    image: docker.io/mongo:8.0
    configs:
      - source: init-mongo.js
        target: /docker-entrypoint-initdb.d/init-mongo.js
    environment:
      - PGID=1000
      - PUID=1000
      - TZ=Asia/Bangkok
    restart: unless-stopped
    volumes:
      - type: bind
        source: ./unifi-db
        target: /data/db
    networks:
     - unifi-bridge
    privileged: false
  unifi-network-application:
    container_name: unifi-network-application
    depends_on:
      unifi-db:
        condition: service_started
        required: true
    environment:
      - MONGO_DBNAME=unifi-db
      - MONGO_HOST=unifi-db
      - MONGO_PASS=pass
      - MONGO_PORT=27017
      - MONGO_USER=unifi
      - PGID=1000
      - PUID=1000
      - TZ=Asia/Bangkok
    image: lscr.io/linuxserver/unifi-network-application:latest
    ports:
      - target: 8443
        published: "8443"
        protocol: tcp
      - target: 3478
        published: "3478"
        protocol: udp
      - target: 10001
        published: "10001"
        protocol: udp
      - target: 8080
        published: "8080"
        protocol: tcp
      - target: 1900 #optional
        published: "1900"
        protocol: udp
      - target: 8843 #optional
        published: "8843"
        protocol: tcp
      - target: 8880 #optional
        published: "8880"
        protocol: tcp
      - target: 6789 #optional
        published: "6789"
        protocol: tcp
      - target: 5514 #optional
        published: "5514"
        protocol: udp
    restart: unless-stopped
    volumes:
      - type: bind
        source: ./unifi-network-application
        target: /config
    networks:
     - unifi-bridge
    privileged: false

networks:
  unifi-bridge:
    driver: bridge

configs:
  init-mongo.js:
    content: |
      db.getSiblingDB("unifi-db").createUser({user: "unifi", pwd: "pass", roles: [{role: "dbOwner", db: "unifi-db"}]}); 
      db.getSiblingDB("unifi-db_stat").createUser({user: "unifi", pwd: "pass", roles: [{role: "dbOwner", db: "unifi-db_stat"}]});


P.S. Override inform host with host ip
UniFi Devices -> Device Updates and Settings -> Inform Host Override

14 ธันวาคม 2568

Enable IPv6 in docker compose

sudo tee /etc/sysctl.d/99-docker-ipv6.conf <<EOF
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
EOF

Configure the Docker Daemon
/etc/docker/daemon.json
{
  "ipv6": true,
  "ip6tables": true 
}

Add IPv6 to Docker Compose Files
docker-compose.yml

    cap_add:
      - NET_ADMIN

networks:
  custom_network:
    driver: bridge
    enable_ipv6: true

13 ธันวาคม 2568

Traefik dnsChallenge with RFC2136 (Bind9)

 .env
RFC2136_NAMESERVER=<your_nameserver>
RFC2136_TSIG_KEY=<tsig_key>
RFC2136_TSIG_ALGORITHM=<tsig_algorithm>
RFC2136_TSIG_SECRET=<tsig_secret>

docker-compose.yml
- TRAEFIK_CERTIFICATESRESOLVERS_RFC2136_ACME_DNSCHALLENGE_RFC2136_NAMESERVER=${RFC2136_NAMESERVER}
- TRAEFIK_CERTIFICATESRESOLVERS_RFC2136_ACME_DNSCHALLENGE_RFC2136_TSIG_KEY=${RFC2136_TSIG_KEY}
- TRAEFIK_CERTIFICATESRESOLVERS_RFC2136_ACME_DNSCHALLENGE_RFC2136_TSIG_ALGORITHM=${RFC2136_TSIG_ALGORITHM}
- TRAEFIK_CERTIFICATESRESOLVERS_RFC2136_ACME_DNSCHALLENGE_RFC2136_TSIG_SECRET=${RFC2136_TSIG_SECRET}

traefik_config.yml
certificatesResolvers:
  rfc2136:
    acme:
      dnsChallenge:
        provider: "rfc2136"
      email: "<your_email>"
      storage: "/letsencrypt/rfc2136.json"

ref: https://go-acme.github.io/lego/dns/rfc2136/

HmacSHA1   = "hmac-sha1."
HmacSHA224 = "hmac-sha224."
HmacSHA256 = "hmac-sha256."
HmacSHA384 = "hmac-sha384."
HmacSHA512 = "hmac-sha512."

Traefik dnsChallenge with Spaceship DNS

 .env
SPACESHIP_API_KEY=<your_spaceship_api_key>
SPACESHIP_API_SECRET=<your_spaceship_api_secret>

docker-compose.yml
- TRAEFIK_CERTIFICATESRESOLVERS_SPACESHIP_ACME_DNSCHALLENGE_SPACESHIP_API_KEY=${SPACESHIP_API_KEY}
- TRAEFIK_CERTIFICATESRESOLVERS_SPACESHIP_ACME_DNSCHALLENGE_SPACESHIP_API_SECRET=$(SPACESHIP_API_SECRET)

traefik_config.yml
certificatesResolvers:
  spaceship:
    acme:
      dnsChallenge:
        provider: "spaceship"
      email: "<your_email>"
      storage: "letsencrypt/spaceship.json"

ref: https://go-acme.github.io/lego/dns/spaceship/

Traefik dnsChallenge with Clouflare DNS

 .env
LETSENCRYPT_TOKEN=<your_cloudflare_api_token>

docker-compose.yml
- TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_DNSCHALLENGE_CLOUDFLARE_DNS_API_TOKEN=${LETSENCRYPT_TOKEN}

traefik_config.yml
certificatesResolvers:
  cloudflare:
    acme:
      dnsChallenge:
        provider: "cloudflare"
      email: "<your_email>"
      storage: "/letsencrypt/cloudflare.json"

ref: https://go-acme.github.io/lego/dns/cloudflare/

04 ธันวาคม 2568

SSL script with Certbot and RFC2136

 #!/bin/bash

# Certificate management script with Certbot and RFC2136

DOMAIN='*.example.com'  # Replace with your domain
EMAIL='your-email@example.com' # Replace with your email for notifications
DNS_SERVER='10.0.0.1' # Replace with your DNS server IP
KEY_NAME='your-key-name'  # Must match the key name on your DNS server
KEY_SECRET='your-base64-secret'  # Base64 encoded secret
KEY_ALGORITHM='HMAC-SHA512'  # or HMAC-MD5, HMAC-SHA1, HMAC-SHA256, HMAC-SHA384
PROPAGATION_SECONDS=20  # Time to wait for DNS propagation

# Create temporary rfc2136 credentials file on host
TMP_CREDS=$(mktemp)
cat > "$TMP_CREDS" <<EOF
dns_rfc2136_server = $DNS_SERVER
dns_rfc2136_name = $KEY_NAME
dns_rfc2136_secret = $KEY_SECRET
dns_rfc2136_algorithm = $KEY_ALGORITHM
EOF
chmod 600 "$TMP_CREDS"

echo "Created temporary credentials file: $TMP_CREDS"
echo "Issuing new certificate for $DOMAIN with Certbot (RFC2136)..."

docker run --rm -it \
    -v ./letsencrypt:/etc/letsencrypt \
    -v "$TMP_CREDS:/tmp/rfc2136.ini:ro" \
    certbot/dns-rfc2136 \
    certonly \
    --dns-rfc2136 \
    --dns-rfc2136-credentials /tmp/rfc2136.ini \
    --dns-rfc2136-propagation-seconds $PROPAGATION_SECONDS \
    --email "$EMAIL" \
    --agree-tos \
    --non-interactive \
    -d "$DOMAIN"

# Clean up temporary file
rm -f "$TMP_CREDS"
echo "Cleaned up temporary credentials file"
echo "Done!"

SSL script with acme.sh and RFC2136

 #!/bin/bash

# Certificate management script with acme.sh and RFC2136

NSUPDATE_SERVER='10.0.0.1' # Replace with your DNS server IP
NSUPDATE_ZONE='example.com' # Replace with your DNS zone
DOMAIN='*.example.com'  # Replace with your domain
KEY_NAME='your-key-name' # Must match the key name on your DNS server
KEY_SECRET='your-base64-secret' # Base64 encoded secret
KEY_ALGORITHM='hmac-sha512' # or hmac-md5, hmac-sha1, hmac-sha256, hmac-sha384

# Create nsupdate key content
NSUPDATE_KEY_CONTENT="key \"$KEY_NAME\" {
    algorithm $KEY_ALGORITHM;
    secret \"$KEY_SECRET\";
};"

echo "Issuing new certificate for $DOMAIN with acme.sh (RFC2136)..."
docker run --rm -it \
    -e NSUPDATE_SERVER="$NSUPDATE_SERVER" \
    -e NSUPDATE_KEY='/tmp/nsupdate.key' \
    -e NSUPDATE_ZONE="$NSUPDATE_ZONE" \
    -v ./acme.sh:/acme.sh \
    neilpang/acme.sh \
    sh -c "echo '$NSUPDATE_KEY_CONTENT' > /tmp/nsupdate.key && acme.sh --issue --server letsencrypt -k ec-256 --dns dns_nsupdate -d $DOMAIN"

echo "Done!"