From b6d49549fed5e9a1d74feb3229f36ade46372681 Mon Sep 17 00:00:00 2001 From: auto-ci Date: Sat, 2 May 2026 15:23:53 -0400 Subject: [PATCH] Pin deployment images and refresh docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 73 +-- docker-compose.arm.yml | 57 ++- docker-compose.lock.yml | 939 ++++++++++++++++++++++++------------- docker-compose.yml | 118 +++-- lokinet/Dockerfile | 21 +- scripts/validate-config.sh | 100 ++-- tailscale/Dockerfile | 2 +- 7 files changed, 851 insertions(+), 459 deletions(-) diff --git a/README.md b/README.md index 6ce8e7c..c71246e 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,23 @@ The stack now uses safer defaults for production: * Service admin/web passwords are loaded from Docker secrets instead of inline values. * Admin/monitoring ports are bound to `127.0.0.1` on the host. -* 3proxy SOCKS auth is currently disabled (`auth none`) for trusted/internal use. +* The published SOCKS entrypoint now requires credentials from a Docker secret. +* CoreDNS recursive resolution for the catch-all zone is restricted to trusted/internal networks. * Pi-hole ARP cache parsing is disabled in Docker (`FTLCONF_database_network_parseARPcache=false`) to prevent recurring netlink `neigh`/ARP errors. Before starting in production, set these secret files: ```sh printf 'YOUR_STRONG_PIHOLE_PASSWORD\n' > secrets/pihole_webpassword.txt -printf 'YOUR_STRONG_GRAFANA_PASSWORD\n' > secrets/grafana_admin_password.txt +printf 'proxyuser:REPLACE_WITH_A_LONG_RANDOM_PASSWORD\n' > secrets/3proxy_users.txt +printf 'REPLACE_WITH_A_LONG_RANDOM_NAMECOIN_RPC_PASSWORD\n' > secrets/namecoin_rpc_password.txt ``` SOCKS auth note: -* Current default is `auth none` in `3proxy/first-instanse.cfg`. -* `secrets/3proxy_users.txt` is not used in this mode. -* Only re-add `PROXY_USERS` compose wiring if you intentionally switch back to `auth strong`. +* `dark3proxy` now reads credentials from `secrets/3proxy_users.txt`. +* Each non-comment line in that secret must be `username:password`. +* If you intentionally want an internal-only unauthenticated proxy, set `PROXY_REQUIRE_AUTH=false` for `dark3proxy` and remove the public `2000:1080` port mapping. Pi-hole note: disabling ARP parsing avoids noisy `Failed to read ARP cache` messages in containerized setups where neighbor-table netlink operations are not @@ -44,11 +46,15 @@ dark3proxy - SOCKS5/http proxy with hostname-preserving router ## SOCKS ports on host -Proxy access is exposed on a single host port: +Public proxy access is exposed on a single host port: * `:2000` -> `dark3proxy` SOCKS (`dark3proxy:1080`), externally reachable. - Intended as the single client entrypoint for clearnet, onion, and Ygg/I2P routing rules. +Local admin endpoint: + +* `127.0.0.1:2002` -> 3proxy admin (`dark3proxy:8161`), host-local only. + Router internals for `:2000`: * Front-end process: `3proxy/socks_router.py` (SOCKS5), keeps destination hostnames intact. @@ -57,7 +63,7 @@ Router internals for `:2000`: - `*.i2p` -> i2pd SOCKS (`10.5.0.2:4447`) - `*.ygg`, `*.meshname`, `*.meship`, and `200::/7` -> local Ygg-guarded SOCKS (`127.0.0.1:1085`) - all other targets -> Tor SOCKS (`10.5.0.7:9050`) -* Existing 3proxy primary instance still runs for admin/legacy rules, with SOCKS moved to internal port `1088` to avoid collision. +* The primary 3proxy instance still enforces ACL/parent rules internally, with SOCKS moved to internal port `1088` to avoid collision with the router front-end. Additional non-proxy endpoint: @@ -67,10 +73,10 @@ Quick checks: ```sh # Onion over the only published proxy port -curl --socks5-hostname :2000 -I http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion +curl --proxy-user proxyuser:REPLACE_WITH_A_LONG_RANDOM_PASSWORD --socks5-hostname :2000 -I http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion # Clearnet over the only published proxy port -curl --socks5-hostname :2000 -I https://example.com +curl --proxy-user proxyuser:REPLACE_WITH_A_LONG_RANDOM_PASSWORD --socks5-hostname :2000 -I https://example.com ``` The system offers a DNS that resolves many darknet and clearnet IP's. The @@ -108,10 +114,9 @@ docker run --rm --network darkproxy infoblox/dig dig @10.5.0.4 TXT vitalik.eth docker run --rm --network darkproxy infoblox/dig dig @10.5.0.4 example.bit ``` -> **Note:** the CoreDNS service at `10.5.0.4` no longer enforces an ACL for -> the root zone – it will happily perform recursive lookups for any client. -> Queries from your host should now work without the “refused to do a recursive -> query” error. If you later reintroduce an ACL, update this note accordingly. +> **Note:** the CoreDNS service at `10.5.0.4` enforces an ACL on the root zone. +> Recursive lookups are limited to loopback, RFC1918/private ranges, and the +> Yggdrasil/internal subnets used by this stack. ### Host-side quick tests (no extra images) @@ -174,11 +179,13 @@ compose and DNS configuration: 1. **Local check** – run `scripts/validate-config.sh` (or its PowerShell equivalent). - The script requires `docker` to be installed; it will generate a normalized - manifest and compare it against `docker-compose.lock.yml`. + manifest and compare it against `docker-compose.lock.yml`. - If the baseline file does not exist it will be created; commit the file after - review. - - CoreDNS syntax is also validated using either a local `coredns` binary or a - container. + review. + - CoreDNS syntax is validated with the repo's compiled CoreDNS image so the + custom `meshname` and `meship` plugins are available during the check. + - Unbound syntax is validated with the repo's Unbound image so the chrooted + runtime layout matches the stack. 2. **CI workflow** – `.github/workflows/config-validation.yml` is triggered on pushes or pull requests affecting `docker-compose.yml` or `PopuraDNS/`. @@ -189,8 +196,8 @@ compose and DNS configuration: compose file, regenerate the baseline: ```sh - scripts/validate-config.sh # fails with drift - cp generated.yml docker-compose.lock.yml + docker compose config > docker-compose.lock.yml + scripts/validate-config.sh git add docker-compose.lock.yml ``` @@ -263,8 +270,8 @@ docker exec darkpihole dig @10.5.0.4 A oxen.loki ## Monitoring the proxy -A lightweight Prometheus/Grafana stack is included to expose 3proxy metrics -and give you visibility into traffic volumes, connected sessions, etc. +A lightweight Prometheus stack is included to expose 3proxy metrics and give +you visibility into traffic volumes, connected sessions, etc. ### how it works @@ -272,27 +279,25 @@ and give you visibility into traffic volumes, connected sessions, etc. status socket. Samples look like `PROXY CONNS 12` or `SOCKS IN 345`. * `monitor/exporter.py` polls that socket every few seconds and exports the counters on HTTP port **9100** in Prometheus format. -* The `docker-compose.yml` file now defines three new services: - `3proxy_exporter`, `prometheus` and `grafana`. - Prometheus scrapes the exporter and Grafana points at Prometheus as a data - source. +* The `docker-compose.yml` file defines two monitoring services: + `3proxy_exporter` and `prometheus`. + Prometheus scrapes the exporter and exposes the metrics for inspection or + external dashboarding. ### building & running The exporter lives in `monitor/`; build the image and start the stack: ```sh -# build everything including the new services -docker-compose build 3proxy_exporter prometheus grafana +# build everything including the monitoring services +docker-compose build 3proxy_exporter prometheus docker-compose up -d ``` -Prometheus will be accessible on port **9090**, Grafana on **3000** (admin -password `secret`). Use Grafana to create or import dashboards – a simple -example JSON is provided in `monitor/3proxy-dashboard.json`. You can import -that file directly or build your own panels using metrics such as -`proxy_conns` and `proxy_bytes_in`. +Prometheus will be accessible on port **9090**. If you want dashboards, you +can point any external Grafana or compatible tool at Prometheus and use metrics +such as `proxy_conns` and `proxy_bytes_in`. ### tips @@ -317,7 +322,7 @@ any warnings or errors. The script covers: * Unbound configuration syntax * Presence of required secret files * Simple 3proxy configuration sanity (presence of `socks`/`proxy` rules) -* Detection of `:latest` image tags (pin to fixed versions) +* Detection of mutable `:latest` image tags in deployment compose files * Verification that restart policies exist The GitHub Actions workflow also includes a **smoke test** job that spins up @@ -333,5 +338,3 @@ running `docker run ...` commands to exercise the images, scanning the Run the script locally via `./scripts/validate-config.sh` (or `.scripts/validate-config.ps1` on Windows) and review the output carefully. CI will execute the same validations automatically on pull requests. - - diff --git a/docker-compose.arm.yml b/docker-compose.arm.yml index 4a4ff66..375483c 100644 --- a/docker-compose.arm.yml +++ b/docker-compose.arm.yml @@ -8,15 +8,21 @@ # If an image/build does not support ARM, startup should fail rather than silently # using emulation. -services: - dark3proxy: - platform: linux/arm64 - - i2pd_yggdrasil: - # Build from local ARM context in this repo to avoid read-only upstream mirror constraints. - build: - context: ./i2pd_yggdrasil_arm - dockerfile: Dockerfile +services: + dark3proxy: + platform: linux/arm64 + + 3proxy_exporter: + platform: linux/arm64 + + i2pdns: + platform: linux/arm64 + + i2pd_yggdrasil: + # Build from local ARM context in this repo to avoid read-only upstream mirror constraints. + build: + context: ./i2pd_yggdrasil_arm + dockerfile: Dockerfile platform: linux/arm64 tor_yggdrasil: @@ -45,10 +51,29 @@ services: dockerfile: Dockerfile platform: linux/arm64 - pihole: - platform: linux/arm64 - - emc: - platform: linux/arm64 - -# networks, volumes, and secrets are inherited from the base compose file + pihole: + platform: linux/arm64 + + emc: + platform: linux/arm64 + + ensdns: + platform: linux/arm64 + + lokinet: + platform: linux/arm64 + + namecoind: + image: sevenrats/namecoin-core@sha256:c5275f813f85f5e1b1f43e4ca044b35c8f622457710a87c1dcb51733e42b59d1 + platform: linux/arm64 + + namecoindns: + platform: linux/arm64 + + tailscale: + platform: linux/arm64 + + prometheus: + platform: linux/arm64 + +# networks, volumes, and secrets are inherited from the base compose file diff --git a/docker-compose.lock.yml b/docker-compose.lock.yml index 1355402..ea8571b 100644 --- a/docker-compose.lock.yml +++ b/docker-compose.lock.yml @@ -1,323 +1,616 @@ -services: - dark3proxy: - container_name: dark3proxy - build: - context: ./3proxy/. - platform: linux/amd64 - cap_add: - - NET_ADMIN - devices: - - /dev/net/tun:/dev/net/tun - dns: - - "10.5.0.6" - dns_search: internal.namespace #namespace used in internal DNS - environment: - YGG_CONNECT_WAIT_SECONDS: "8" - ROUTER_I2P_MAP_FILE: /var/lib/i2pdns/map.json - ROUTER_I2P_POOL_CIDR: 172.31.0.0/16 - volumes: - - "./3proxy/first-instanse.cfg:/etc/3proxy/first-instanse.cfg" - - "./3proxy/second-instanse.cfg:/etc/3proxy/second-instanse.cfg" - - "./3proxy/yggdrasil.conf:/etc/yggdrasil/yggdrasil.conf" - - "i2p_dns_map:/var/lib/i2pdns:ro" - restart: unless-stopped - healthcheck: - test: ["CMD", "bash", "-lc", "pgrep -f 'yggdrasil -useconffile' >/dev/null && pgrep -f '3proxy /etc/3proxy/second-instanse.cfg' >/dev/null && pgrep -f '3proxy /etc/3proxy/first-instanse.cfg' >/dev/null && pgrep -f 'python3 /usr/local/bin/socks_router.py' >/dev/null"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 45s - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - ports: - - "2000:1080" # primary host SOCKS via dark3proxy (externally reachable) - - "2002:8161" # 3proxy admin page - networks: - darkproxy: - ipv4_address: 10.5.0.8 - - i2pd_yggdrasil: - container_name: darki2p - build: - context: ./i2pd_yggdrasil_docker/src - dockerfile: Dockerfile - platform: linux/amd64 - privileged: true - cap_add: - - NET_ADMIN - devices: - - /dev/net/tun:/dev/net/tun - volumes: - - "./i2pd_yggdrasil_docker/src/entrypoint.sh:/entrypoint.sh:ro" - ports: - # I2P Service Ports -# - "2827:2827" # BOB Bridge -# - "4444:4444" # HTTP Proxy -# - "4447:4447" # SOCKS Proxy - - "2001:7070" # Webconsole -# - "7650:7650" # I2PControl -# - "7654:7654" # I2CP -# - "7656:7656" # SAM Bridge (TCP) - - "10765:10765" # Main I2P Listener - # i2pd does not expose a DNS listener in this build. - # .i2p DNS is provided by the dedicated i2pdns bridge service (10.5.0.16:53). - # Yggdrasil Ports - - "10654:10654" # Yggdrasil Listener - environment: - tz: /run/secrets/tz - # Lower-intensity peer selection for faster readiness in lock workflow. - YGG_PEER_PARALLEL: "2" - YGG_PEER_PINGS: "3" - YGG_PEER_BEST: "4" - YGG_PEER_MAX_FROM_COUNTRY: "1" - YGG_PEER_PING_INTERVAL: "0.3" - YGG_CONNECT_WAIT_SECONDS: "20" - secrets: - - tz - restart: unless-stopped - healthcheck: - test: ["CMD", "bash", "-c", "pgrep i2pd && pgrep yggdrasil"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 15m - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - mac_address: ce:22:b8:0e:6e:78 - networks: - darkproxy: - ipv4_address: 10.5.0.2 - - i2pdns: - container_name: darki2pdns - build: - context: ./i2pdns - dockerfile: Dockerfile - platform: linux/amd64 - restart: unless-stopped - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - environment: - I2PDNS_LISTEN_HOST: 0.0.0.0 - I2PDNS_LISTEN_PORT: 53 - I2PDNS_TTL: 60 - I2PDNS_POOL_CIDR: 172.31.0.0/16 - I2PDNS_MAP_FILE: /var/lib/i2pdns/map.json - volumes: - - "i2p_dns_map:/var/lib/i2pdns" - networks: - darkproxy: - ipv4_address: 10.5.0.16 - - tor_yggdrasil: - build: - context: ./tor_yggdrasil_docker - dockerfile: Dockerfile - platform: linux/amd64 -# image: tor_yggdrasil:latest -# container_name: tor_over_yggdrasil - container_name: darktor - entrypoint: ["tor"] - command: ["-f", "/etc/tor/torrc"] - # platform removed; image is amd64-only - security_opt: - - no-new-privileges:true # Security enhancement - prevent privilege esca> - volumes: - - "./tor_yggdrasil_docker/torrc:/etc/tor/torrc:ro" - ports: - - "127.0.0.1:2006:9053/udp" # direct Tor DNSPort - restart: unless-stopped # Auto-restart unless manually stopped - dns: - - "10.5.0.6" - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - networks: - darkproxy: - ipv4_address: 10.5.0.7 - - alfis: - image: cofob/alfis - platform: linux/amd64 - # platform removed; image is amd64 only - container_name: darkalfis - volumes: - - darkalfis_data:/storage - restart: unless-stopped - stop_grace_period: 10s - dns: - - "10.5.0.6" - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - networks: - darkproxy: - ipv4_address: 10.5.0.3 - - coredns: -# image: darkdns - build: - context: ./PopuraDNS - dockerfile: Dockerfile - platform: linux/amd64 - container_name: darkdns - restart: unless-stopped - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - logging: - driver: "json-file" - options: - max-size: "10m" # Maximum log file size - max-file: "3" # Maximum of 3 rotating log files - networks: - darkproxy: - ipv4_address: 10.5.0.4 - - unbound: - container_name: darkunbound - image: mvance/unbound:latest - platform: linux/amd64 - # platform removed; image is amd64-only - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - networks: - darkproxy: - ipv4_address: 10.5.0.5 - volumes: - - type: bind - read_only: true - source: ./unbound/unbound.conf - target: /opt/unbound/etc/unbound/unbound.conf - - "./unbound/forward-records.conf:/opt/unbound/etc/unbound/forward-records.conf" - - "./unbound/a-records.conf:/opt/unbound/etc/unbound/a-records.conf" -# ports: -# - "5053:5053/tcp" -# - "5053:5053/udp" -# healthcheck: -# disable: true - restart: unless-stopped - - pihole: - container_name: darkpihole - image: pihole/pihole:latest - platform: linux/amd64 - # For DHCP it is recommended to remove these ports and instead add: network_mode: "host" - ports: - # DNS Ports - - "53:53/tcp" - - "53:53/udp" - # Default HTTP Port -# - "80:80/tcp" - # Default HTTPs Port. FTL will generate a self-signed certificate -# - "443:443/tcp - # Uncomment the line below if you are using Pi-hole as your DHCP server -# - "67:67/udp" - # Uncomment the line below if you are using Pi-hole as your NTP server -# - "123:123/udp" - - "2003:80/tcp" # pihole web port - environment: - # Set the appropriate timezone for your location (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), e.g: - TZ: 'America/Detroit' - # WEBPASSWORD: 'set a secure password here or it will be random' -# FTLCONF_webserver_api_password: 'darkproxy' - # If using Docker's default `bridge` network setting the dns listening mode should be set to 'all' -# FTLCONF_dns_listeningMode: 'all' - PIHOLE_DNS_: 10.5.0.4 - TEMPERATUREUNIT: f - WEBTHEME: lcars - WEBPASSWORD: darkproxy - FTLCONF_dns_upstreams: coredns - # Volumes store your data between container upgrades - volumes: - # For persisting Pi-hole's databases and common configuration file - - './pihole/etc-pihole:/etc/pihole' - # Uncomment the below if you have custom dnsmasq config files that you want to persist. Not needed for most starting fresh with Pi-hole v6. If you're upgrading from v5 you and have used this directory before, you should keep it enabled for the first v6 container start to allow for a complete migration. It can be removed afterwards. Needs environment variable FTLCONF_misc_etc_dnsmasq_d: 'true' - - './pihole/etc-dnsmasq.d:/etc/dnsmasq.d' - cap_add: - # See https://github.com/pi-hole/docker-pi-hole#note-on-capabilities - # Required if you are using Pi-hole as your DHCP server, else not needed - - NET_ADMIN - # Required if you are using Pi-hole as your NTP client to be able to set the host's system time -# - SYS_TIME - # Optional, if Pi-hole should get some more processing time - - SYS_NICE - restart: unless-stopped # Recommended but not required (DHCP needs NET_ADMIN) - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - healthcheck: - test: ["CMD", "dig", "+short", "+norecurse", "+timeout=2", "@127.0.0.1", "google.com"] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - networks: - darkproxy: - ipv4_address: 10.5.0.6 - - geth: - image: ethereum/client-go:latest - platform: linux/amd64 - container_name: darkgeth - command: - - --syncmode=snap - - --http - - --http.addr=0.0.0.0 - - --http.port=8545 - - --http.api=eth,net,web3 - - --cache=256 - networks: - darkproxy: - ipv4_address: 10.5.0.10 - restart: unless-stopped - stop_grace_period: 30s - healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8545"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 120s - sysctls: - - "net.ipv6.conf.all.disable_ipv6=0" - - emc: - image: wg00/emercoin:0.8.4 - platform: linux/amd64 - container_name: darkemer - volumes: - - emc_data:/emc/data - - /etc/localtime:/etc/localtime:ro - command: - - -datadir=/emc/data - - -conf=/emc/emercoin.conf - - -printtoconsole - networks: - darkproxy: - ipv4_address: 10.5.0.9 - restart: unless-stopped - stop_grace_period: 30s - -volumes: - darkalfis_data: - name: darkalfis_data - emc_data: - name: emc_data - tor-data: - driver: local - i2p_dns_map: - name: i2p_dns_map - -networks: - darkproxy: -# name: darkproxy - enable_ipv6: true - driver: bridge - ipam: - config: - - subnet: 10.5.0.0/16 - gateway: 10.5.0.1 - - subnet: 2001:0BC5::/112 - gateway: 2001:0BC5::1 - -secrets: - tz: - file: ./secrets/tz.txt - YGGDRASIL_GENERATE_KEYS: - file: ./secrets/YGGDRASIL_GENERATE_KEYS.txt +name: darkproxy +services: + 3proxy_exporter: + build: + context: /home/blade/darkproxy/monitor + dockerfile: Dockerfile + container_name: dark3proxy-exporter + depends_on: + dark3proxy: + condition: service_started + required: true + image: darkproxy-3proxy-exporter:local + networks: + darkproxy: + ipv4_address: 10.5.0.20 + platform: linux/amd64 + security_opt: + - no-new-privileges:true + alfis: + container_name: darkalfis + dns: + - 10.5.0.6 + image: cofob/alfis + networks: + darkproxy: + ipv4_address: 10.5.0.3 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + stop_grace_period: 10s + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: volume + source: darkalfis_data + target: /storage + volume: {} + coredns: + build: + context: /home/blade/darkproxy/PopuraDNS + dockerfile: Dockerfile + cpus: 1 + container_name: darkdns + logging: + driver: json-file + options: + max-file: "3" + max-size: 10m + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.4 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + dark3proxy: + build: + context: /home/blade/darkproxy/3proxy + dockerfile: Dockerfile + cap_add: + - NET_ADMIN + cpus: 1 + container_name: dark3proxy + devices: + - source: /dev/net/tun + target: /dev/net/tun + permissions: rwm + dns: + - 10.5.0.6 + dns_search: + - internal.namespace + environment: + PROXY_REQUIRE_AUTH: "true" + PROXY_USERS_FILE: /run/secrets/PROXY_USERS + ROUTER_I2P_MAP_FILE: /var/lib/i2pdns/map.json + ROUTER_I2P_POOL_CIDR: 172.31.0.0/16 + ROUTER_NO_AUTH_CIDRS: 192.168.1.0/24 + ROUTER_REQUIRE_AUTH: "true" + ROUTER_USERS_FILE: /run/secrets/PROXY_USERS + YGG_CONNECT_WAIT_SECONDS: "8" + healthcheck: + test: + - CMD + - bash + - -lc + - pgrep -f 'yggdrasil -useconffile' >/dev/null && pgrep -f '3proxy /etc/3proxy/second-instanse.cfg' >/dev/null && pgrep -f '3proxy /etc/3proxy/first-instanse.cfg' >/dev/null && pgrep -f 'python3 /usr/local/bin/socks_router.py' >/dev/null + timeout: 10s + interval: 30s + retries: 3 + start_period: 45s + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.8 + platform: linux/amd64 + ports: + - mode: ingress + target: 1080 + published: "2000" + protocol: tcp + - mode: ingress + host_ip: 127.0.0.1 + target: 8161 + published: "2002" + protocol: tcp + restart: unless-stopped + secrets: + - source: PROXY_USERS + target: /run/secrets/PROXY_USERS + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: bind + source: /home/blade/darkproxy/3proxy/first-instanse.cfg + target: /etc/3proxy/first-instanse.cfg + bind: + create_host_path: true + - type: bind + source: /home/blade/darkproxy/3proxy/second-instanse.cfg + target: /etc/3proxy/second-instanse.cfg + bind: + create_host_path: true + - type: bind + source: /home/blade/darkproxy/3proxy/yggdrasil.conf + target: /etc/yggdrasil/yggdrasil.conf + bind: + create_host_path: true + - type: volume + source: i2p_dns_map + target: /var/lib/i2pdns + read_only: true + volume: {} + emc: + cpus: 1 + command: + - -datadir=/emc/data + - -conf=/emc/emercoin.conf + - -printtoconsole + container_name: darkemer + image: wg00/emercoin:0.8.4 + mem_limit: "1073741824" + mem_reservation: "268435456" + networks: + darkproxy: + ipv4_address: 10.5.0.9 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + stop_grace_period: 30s + volumes: + - type: volume + source: emc_data + target: /emc/data + volume: {} + - type: bind + source: /etc/localtime + target: /etc/localtime + read_only: true + bind: + create_host_path: true + ensdns: + build: + context: /home/blade/darkproxy/ensdns + dockerfile: Dockerfile + cpus: 0.5 + container_name: darkens + environment: + ENS_RPC_URL: https://ethereum-rpc.publicnode.com + ENSDNS_TTL: "60" + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.11 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + i2pd_yggdrasil: + build: + context: /home/blade/darkproxy/i2pd_yggdrasil_docker/src + dockerfile: Dockerfile + cap_add: + - NET_ADMIN + cpus: 4 + container_name: darki2p + devices: + - source: /dev/net/tun + target: /dev/net/tun + permissions: rwm + environment: + tz: /run/secrets/tz + healthcheck: + test: + - CMD + - bash + - -c + - pgrep i2pd && pgrep yggdrasil + timeout: 10s + interval: 30s + retries: 3 + start_period: 15m0s + mem_limit: "2147483648" + mem_reservation: "536870912" + mac_address: ce:22:b8:0e:6e:78 + networks: + darkproxy: + ipv4_address: 10.5.0.2 + platform: linux/amd64 + ports: + - mode: ingress + target: 7070 + published: "2001" + protocol: tcp + - mode: ingress + target: 10765 + published: "10765" + protocol: tcp + - mode: ingress + target: 10654 + published: "10654" + protocol: tcp + privileged: true + restart: unless-stopped + secrets: + - source: tz + target: /run/secrets/tz + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + i2pdns: + build: + context: /home/blade/darkproxy/i2pdns + dockerfile: Dockerfile + cpus: 0.5 + container_name: darki2pdns + environment: + I2PDNS_LISTEN_HOST: 0.0.0.0 + I2PDNS_LISTEN_PORT: "53" + I2PDNS_MAP_FILE: /var/lib/i2pdns/map.json + I2PDNS_POOL_CIDR: 172.31.0.0/16 + I2PDNS_TTL: "60" + mem_limit: "134217728" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.16 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: volume + source: i2p_dns_map + target: /var/lib/i2pdns + volume: {} + lokinet: + build: + context: /home/blade/darkproxy/lokinet + dockerfile: Dockerfile + cap_add: + - NET_ADMIN + - NET_BIND_SERVICE + cpus: 1 + container_name: darklokinet + devices: + - source: /dev/net/tun + target: /dev/net/tun + permissions: rwm + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.14 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + namecoind: + cpus: 2 + container_name: darknamecoind + entrypoint: + - /bin/sh + - -ec + - | + exec /usr/local/bin/namecoind \ + -server=1 \ + -daemon=0 \ + -datadir=/data \ + -rpcbind=0.0.0.0 \ + -rpcallowip=10.5.0.0/16 \ + -rpcuser=namecoinrpc \ + "-rpcpassword=$$(cat /run/secrets/NAMECOIN_RPC_PASSWORD)" \ + -printtoconsole \ + -txindex=1 \ + -dnsseed=1 \ + -addnode=162.212.154.52:8334 \ + -addnode=162.210.196.27:8334 \ + -addnode=23.108.191.178:8334 \ + -addnode=3.228.193.128:8334 \ + -addnode=3.66.245.44:8334 \ + -addnode=212.51.144.42:8334 + image: ukd1/namecoind@sha256:6fdf63f61f687ee639893a8cdcd910bb24c5eb3a3493ff72142c911d7019200b + mem_limit: "2147483648" + mem_reservation: "536870912" + networks: + darkproxy: + ipv4_address: 10.5.0.13 + platform: linux/amd64 + restart: unless-stopped + secrets: + - source: NAMECOIN_RPC_PASSWORD + target: /run/secrets/NAMECOIN_RPC_PASSWORD + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: volume + source: namecoin_data + target: /data + volume: {} + namecoindns: + build: + context: /home/blade/darkproxy/namecoindns + dockerfile: Dockerfile + cpus: 0.5 + container_name: darknamecoin + depends_on: + namecoind: + condition: service_started + required: true + environment: + NAMECOIN_RPC_PASSWORD_FILE: /run/secrets/NAMECOIN_RPC_PASSWORD + NAMECOIN_RPC_TIMEOUT: "8" + NAMECOIN_RPC_URL: http://darknamecoind:8336/ + NAMECOIN_RPC_USER: namecoinrpc + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.12 + platform: linux/amd64 + restart: unless-stopped + secrets: + - source: NAMECOIN_RPC_PASSWORD + target: /run/secrets/NAMECOIN_RPC_PASSWORD + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + pihole: + cap_add: + - NET_ADMIN + - SYS_NICE + cpus: 1.5 + container_name: darkpihole + environment: + FTLCONF_database_network_parseARPcache: "false" + FTLCONF_dns_upstreams: 10.5.0.4#53 + PIHOLE_DNS_: 10.5.0.4 + TEMPERATUREUNIT: f + TZ: America/Detroit + WEBPASSWORD_FILE: /run/secrets/PIHOLE_WEBPASSWORD + WEBTHEME: lcars + healthcheck: + test: + - CMD + - dig + - +short + - +norecurse + - +timeout=2 + - '@127.0.0.1' + - google.com + timeout: 10s + interval: 1m0s + retries: 3 + start_period: 30s + image: pihole/pihole@sha256:1c32c36b862a12762656b6471c854cebc01fe945639ba3a893611337c2c95e99 + mem_limit: "536870912" + mem_reservation: "134217728" + networks: + darkproxy: + ipv4_address: 10.5.0.6 + platform: linux/amd64 + ports: + - mode: ingress + target: 53 + published: "53" + protocol: tcp + - mode: ingress + target: 53 + published: "53" + protocol: udp + - mode: ingress + host_ip: 127.0.0.1 + target: 80 + published: "2003" + protocol: tcp + restart: unless-stopped + secrets: + - source: PIHOLE_WEBPASSWORD + target: /run/secrets/PIHOLE_WEBPASSWORD + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: bind + source: /home/blade/darkproxy/pihole/etc-pihole + target: /etc/pihole + bind: + create_host_path: true + - type: bind + source: /home/blade/darkproxy/pihole/etc-dnsmasq.d + target: /etc/dnsmasq.d + bind: + create_host_path: true + prometheus: + container_name: darkprom + image: prom/prometheus@sha256:e4254400b85610324913f0dc4acf92603d9984e7519414c5a12811aa6146acc3 + networks: + darkproxy: + ipv4_address: 10.5.0.21 + platform: linux/amd64 + ports: + - mode: ingress + host_ip: 127.0.0.1 + target: 9090 + published: "9090" + protocol: tcp + security_opt: + - no-new-privileges:true + volumes: + - type: bind + source: /home/blade/darkproxy/monitor/prometheus.yml + target: /etc/prometheus/prometheus.yml + read_only: true + bind: + create_host_path: true + tailscale: + build: + context: /home/blade/darkproxy/tailscale + dockerfile: Dockerfile + cap_add: + - NET_ADMIN + - SYS_MODULE + container_name: darkscale + devices: + - source: /dev/net/tun + target: /dev/net/tun + permissions: rwm + environment: + TS_AUTHKEY: tskey-YOUR-AUTH-KEY-HERE + TS_EXTRA_ARGS: --accept-dns=false --advertise-exit-node + TS_STATE_DIR: /var/lib/tailscale + hostname: darkproxy-exit + networks: + darkproxy: + ipv4_address: 10.5.0.10 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv4.ip_forward: "1" + net.ipv6.conf.all.forwarding: "1" + volumes: + - type: volume + source: tailscale_data + target: /var/lib/tailscale + volume: {} + tor_yggdrasil: + build: + context: /home/blade/darkproxy/tor_yggdrasil_docker + dockerfile: Dockerfile + cpus: 2 + command: + - -f + - /etc/tor/torrc + container_name: darktor + dns: + - 10.5.0.6 + entrypoint: + - tor + mem_limit: "1073741824" + mem_reservation: "268435456" + networks: + darkproxy: + ipv4_address: 10.5.0.7 + platform: linux/amd64 + ports: + - mode: ingress + host_ip: 127.0.0.1 + target: 9053 + published: "2006" + protocol: udp + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: bind + source: /home/blade/darkproxy/tor_yggdrasil_docker/torrc + target: /etc/tor/torrc + read_only: true + bind: + create_host_path: true + unbound: + cpus: 4 + container_name: darkunbound + image: mvance/unbound@sha256:76906da36d1806f3387338f15dcf8b357c51ce6897fb6450d6ce010460927e90 + mem_limit: "805306368" + mem_reservation: "268435456" + networks: + darkproxy: + ipv4_address: 10.5.0.5 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" + volumes: + - type: bind + source: /home/blade/darkproxy/unbound/unbound.conf + target: /opt/unbound/etc/unbound/unbound.conf + read_only: true + - type: bind + source: /home/blade/darkproxy/unbound/forward-records.conf + target: /opt/unbound/etc/unbound/forward-records.conf + bind: + create_host_path: true + - type: bind + source: /home/blade/darkproxy/unbound/a-records.conf + target: /opt/unbound/etc/unbound/a-records.conf + bind: + create_host_path: true + - type: bind + source: /home/blade/darkproxy/unbound/srv-records.conf + target: /opt/unbound/etc/unbound/srv-records.conf + bind: + create_host_path: true + zildns: + build: + context: /home/blade/darkproxy/zildns + dockerfile: Dockerfile + cpus: 0.5 + container_name: darkzil + environment: + ZILDNS_CACHE_SECONDS: "300" + ZILDNS_PREWARM_DOMAIN: brad.zil + ZILDNS_TTL: "120" + ZILDNS_ZNS_NETWORK: mainnet + ZILDNS_ZNS_URL: https://api.zilliqa.com + mem_limit: "268435456" + mem_reservation: "67108864" + networks: + darkproxy: + ipv4_address: 10.5.0.15 + platform: linux/amd64 + restart: unless-stopped + security_opt: + - no-new-privileges:true + sysctls: + net.ipv6.conf.all.disable_ipv6: "0" +networks: + darkproxy: + name: darkproxy_darkproxy + driver: bridge + ipam: + config: + - subnet: 10.5.0.0/16 + gateway: 10.5.0.1 + - subnet: 2001:0BC5::/112 + gateway: 2001:0BC5::1 + enable_ipv6: true +volumes: + darkalfis_data: + name: darkalfis_data + emc_data: + name: emc_data + i2p_dns_map: + name: i2p_dns_map + namecoin_data: + name: namecoin_data + tailscale_data: + name: tailscale_data +secrets: + NAMECOIN_RPC_PASSWORD: + name: darkproxy_NAMECOIN_RPC_PASSWORD + file: /home/blade/darkproxy/secrets/namecoin_rpc_password.txt + PIHOLE_WEBPASSWORD: + name: darkproxy_PIHOLE_WEBPASSWORD + file: /home/blade/darkproxy/secrets/pihole_webpassword.txt + PROXY_USERS: + name: darkproxy_PROXY_USERS + file: /home/blade/darkproxy/secrets/3proxy_users.txt + tz: + name: darkproxy_tz + file: /home/blade/darkproxy/secrets/tz.txt diff --git a/docker-compose.yml b/docker-compose.yml index e3dc474..05f7211 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,8 +13,17 @@ services: dns_search: internal.namespace #namespace used in internal DNS environment: YGG_CONNECT_WAIT_SECONDS: "8" + PROXY_REQUIRE_AUTH: "true" + PROXY_USERS_FILE: /run/secrets/PROXY_USERS + ROUTER_REQUIRE_AUTH: "true" + ROUTER_NO_AUTH_CIDRS: 192.168.1.0/24 + ROUTER_USERS_FILE: /run/secrets/PROXY_USERS ROUTER_I2P_MAP_FILE: /var/lib/i2pdns/map.json ROUTER_I2P_POOL_CIDR: 172.31.0.0/16 + security_opt: + - no-new-privileges:true + secrets: + - PROXY_USERS volumes: - "./3proxy/first-instanse.cfg:/etc/3proxy/first-instanse.cfg" - "./3proxy/second-instanse.cfg:/etc/3proxy/second-instanse.cfg" @@ -34,7 +43,7 @@ services: - "net.ipv6.conf.all.disable_ipv6=0" ports: - "2000:1080" # primary host SOCKS via dark3proxy (externally reachable) - - "2002:8161" # 3proxy admin page + - "127.0.0.1:2002:8161" # 3proxy admin page (host-local only) networks: darkproxy: ipv4_address: 10.5.0.8 @@ -95,6 +104,8 @@ services: context: ./i2pdns dockerfile: Dockerfile platform: linux/amd64 + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "0.5" mem_reservation: 64m @@ -146,6 +157,8 @@ services: platform: linux/amd64 # platform removed; image is amd64 only container_name: darkalfis + security_opt: + - no-new-privileges:true volumes: - darkalfis_data:/storage restart: unless-stopped @@ -164,6 +177,8 @@ services: dockerfile: Dockerfile platform: linux/amd64 container_name: darkdns + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "1.0" mem_reservation: 64m @@ -181,9 +196,11 @@ services: unbound: container_name: darkunbound - image: mvance/unbound:latest + image: mvance/unbound@sha256:76906da36d1806f3387338f15dcf8b357c51ce6897fb6450d6ce010460927e90 platform: linux/amd64 # platform removed; image is amd64-only + security_opt: + - no-new-privileges:true sysctls: - "net.ipv6.conf.all.disable_ipv6=0" networks: @@ -209,8 +226,10 @@ services: pihole: container_name: darkpihole - image: pihole/pihole:latest + image: pihole/pihole@sha256:1c32c36b862a12762656b6471c854cebc01fe945639ba3a893611337c2c95e99 platform: linux/amd64 + security_opt: + - no-new-privileges:true # For DHCP it is recommended to remove these ports and instead add: network_mode: "host" ports: # DNS Ports @@ -275,6 +294,8 @@ services: image: wg00/emercoin:0.8.4 platform: linux/amd64 container_name: darkemer + security_opt: + - no-new-privileges:true volumes: - emc_data:/emc/data - /etc/localtime:/etc/localtime:ro @@ -297,6 +318,8 @@ services: dockerfile: Dockerfile platform: linux/amd64 container_name: darkens + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "0.5" mem_reservation: 64m @@ -316,6 +339,8 @@ services: dockerfile: Dockerfile platform: linux/amd64 container_name: darkzil + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "0.5" mem_reservation: 64m @@ -338,6 +363,8 @@ services: dockerfile: Dockerfile platform: linux/amd64 container_name: darklokinet + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "1.0" mem_reservation: 64m @@ -354,30 +381,40 @@ services: ipv4_address: 10.5.0.14 namecoind: - image: ukd1/namecoind:latest + image: ukd1/namecoind@sha256:6fdf63f61f687ee639893a8cdcd910bb24c5eb3a3493ff72142c911d7019200b platform: linux/amd64 container_name: darknamecoind + entrypoint: + - /bin/sh + - -ec + - | + exec /usr/local/bin/namecoind \ + -server=1 \ + -daemon=0 \ + -datadir=/data \ + -rpcbind=0.0.0.0 \ + -rpcallowip=10.5.0.0/16 \ + -rpcuser=namecoinrpc \ + "-rpcpassword=$(cat /run/secrets/NAMECOIN_RPC_PASSWORD)" \ + -printtoconsole \ + -txindex=1 \ + -dnsseed=1 \ + -addnode=162.212.154.52:8334 \ + -addnode=162.210.196.27:8334 \ + -addnode=23.108.191.178:8334 \ + -addnode=3.228.193.128:8334 \ + -addnode=3.66.245.44:8334 \ + -addnode=212.51.144.42:8334 + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "2.0" mem_reservation: 512m mem_limit: 2g - command: - - "-server=1" - - "-rpcbind=0.0.0.0" - - "-rpcallowip=10.5.0.0/16" - - "-rpcuser=namecoinrpc" - - "-rpcpassword=CHANGE_ME_NAMECOIN_RPC_PASSWORD" - - "-printtoconsole" - - "-txindex=1" - - "-dnsseed=1" - - "-addnode=162.212.154.52:8334" - - "-addnode=162.210.196.27:8334" - - "-addnode=23.108.191.178:8334" - - "-addnode=3.228.193.128:8334" - - "-addnode=3.66.245.44:8334" - - "-addnode=212.51.144.42:8334" + secrets: + - NAMECOIN_RPC_PASSWORD volumes: - - namecoin_data:/namecoin + - namecoin_data:/data sysctls: - "net.ipv6.conf.all.disable_ipv6=0" networks: @@ -390,6 +427,8 @@ services: dockerfile: Dockerfile platform: linux/amd64 container_name: darknamecoin + security_opt: + - no-new-privileges:true restart: unless-stopped cpus: "0.5" mem_reservation: 64m @@ -399,8 +438,10 @@ services: environment: NAMECOIN_RPC_URL: http://darknamecoind:8336/ NAMECOIN_RPC_USER: namecoinrpc - NAMECOIN_RPC_PASSWORD: CHANGE_ME_NAMECOIN_RPC_PASSWORD + NAMECOIN_RPC_PASSWORD_FILE: /run/secrets/NAMECOIN_RPC_PASSWORD NAMECOIN_RPC_TIMEOUT: 8 + secrets: + - NAMECOIN_RPC_PASSWORD sysctls: - "net.ipv6.conf.all.disable_ipv6=0" networks: @@ -414,6 +455,8 @@ services: platform: linux/amd64 container_name: darkscale hostname: darkproxy-exit + security_opt: + - no-new-privileges:true cap_add: - NET_ADMIN - SYS_MODULE @@ -439,8 +482,10 @@ services: container_name: dark3proxy-exporter build: context: ./monitor - image: darkproxy-3proxy-exporter:latest + image: darkproxy-3proxy-exporter:local platform: linux/amd64 + security_opt: + - no-new-privileges:true depends_on: - dark3proxy networks: @@ -448,9 +493,11 @@ services: ipv4_address: 10.5.0.20 prometheus: - image: prom/prometheus:latest + image: prom/prometheus@sha256:e4254400b85610324913f0dc4acf92603d9984e7519414c5a12811aa6146acc3 container_name: darkprom platform: linux/amd64 + security_opt: + - no-new-privileges:true volumes: - ./monitor/prometheus.yml:/etc/prometheus/prometheus.yml:ro ports: @@ -459,22 +506,6 @@ services: darkproxy: ipv4_address: 10.5.0.21 - grafana: - image: grafana/grafana:latest - container_name: darkgraf - platform: linux/amd64 - ports: - - "127.0.0.1:2005:3000" - environment: - - GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/GRAFANA_ADMIN_PASSWORD - secrets: - - GRAFANA_ADMIN_PASSWORD - volumes: - - grafana-data:/var/lib/grafana - networks: - darkproxy: - ipv4_address: 10.5.0.22 - volumes: darkalfis_data: name: darkalfis_data @@ -486,8 +517,6 @@ volumes: driver: local tailscale_data: name: tailscale_data - grafana-data: - name: grafana-data i2p_dns_map: name: i2p_dns_map @@ -510,6 +539,7 @@ secrets: file: ./secrets/YGGDRASIL_GENERATE_KEYS.txt PIHOLE_WEBPASSWORD: file: ./secrets/pihole_webpassword.txt - GRAFANA_ADMIN_PASSWORD: - file: ./secrets/grafana_admin_password.txt - + PROXY_USERS: + file: ./secrets/3proxy_users.txt + NAMECOIN_RPC_PASSWORD: + file: ./secrets/namecoin_rpc_password.txt diff --git a/lokinet/Dockerfile b/lokinet/Dockerfile index fdc8bd8..82dcb54 100644 --- a/lokinet/Dockerfile +++ b/lokinet/Dockerfile @@ -1,20 +1,15 @@ FROM debian:bookworm-slim -ARG LOKINET_VERSION=v0.9.14 - RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates curl xz-utils iproute2 iptables \ + && apt-get install -y --no-install-recommends ca-certificates curl gnupg iproute2 iptables \ + && mkdir -p /usr/share/keyrings \ + && curl -fsSL https://deb.session.foundation/pub.gpg -o /usr/share/keyrings/session-foundation.gpg \ + && printf 'Types: deb\nURIs: https://deb.session.foundation\nSuites: bookworm\nComponents: main\nSigned-By: /usr/share/keyrings/session-foundation.gpg\n' > /etc/apt/sources.list.d/session.sources \ + && apt-get update \ + && apt-get install -y --no-install-recommends lokinet-bin \ + && mkdir -p /etc/lokinet /var/lib/lokinet \ && rm -rf /var/lib/apt/lists/* -RUN set -eux; \ - curl -fsSL -o /tmp/lokinet.tar.xz "https://github.com/oxen-io/lokinet/releases/download/${LOKINET_VERSION}/lokinet-linux-amd64-${LOKINET_VERSION}.tar.xz"; \ - tar -xJf /tmp/lokinet.tar.xz -C /tmp; \ - mv "/tmp/lokinet-linux-amd64-${LOKINET_VERSION}/lokinet" /usr/local/bin/lokinet; \ - chmod +x /usr/local/bin/lokinet; \ - mkdir -p /etc/lokinet /var/lib/lokinet; \ - mv "/tmp/lokinet-linux-amd64-${LOKINET_VERSION}/bootstrap.signed" /etc/lokinet/bootstrap.signed; \ - rm -rf /tmp/lokinet.tar.xz "/tmp/lokinet-linux-amd64-${LOKINET_VERSION}" - COPY lokinet.ini /etc/lokinet/lokinet.ini -CMD ["/usr/local/bin/lokinet", "--config", "/etc/lokinet/lokinet.ini"] +CMD ["/usr/bin/lokinet", "--config", "/etc/lokinet/lokinet.ini"] diff --git a/scripts/validate-config.sh b/scripts/validate-config.sh index 9a09b16..40688ed 100644 --- a/scripts/validate-config.sh +++ b/scripts/validate-config.sh @@ -29,16 +29,36 @@ else echo "[validate-config] docker binary not found; skipping compose validation" fi -# CoreDNS syntax check (use local binary or container fallback) -if command -v coredns >/dev/null 2>&1; then - echo "[validate-config] checking PopuraDNS/Corefile with local coredns" - coredns -conf PopuraDNS/Corefile -dns.port=0 -elif command -v docker >/dev/null 2>&1; then - echo "[validate-config] checking PopuraDNS/Corefile with container" - docker run --rm -v "${PWD}/PopuraDNS/Corefile:/etc/coredns/Corefile:ro" \ - coredns/coredns:latest -conf /etc/coredns/Corefile -dns.port=0 +# CoreDNS syntax check must use the compiled image because the Corefile relies +# on custom plugins (meshname/meship) that are not present in the stock binary. +if command -v docker >/dev/null 2>&1; then + echo "[validate-config] checking PopuraDNS/Corefile with compiled coredns image" + docker compose build coredns >/dev/null + COREDNS_IMAGE="$(docker compose images -q coredns | head -n1)" + if [ -z "$COREDNS_IMAGE" ]; then + echo "[validate-config] error: failed to resolve compiled coredns image" >&2 + exit 1 + fi + set +e + timeout 8s docker run --rm "$COREDNS_IMAGE" -conf /Corefile -dns.port=0 + COREDNS_STATUS=$? + set -e + if [ "$COREDNS_STATUS" -ne 0 ] && [ "$COREDNS_STATUS" -ne 124 ]; then + echo "[validate-config] error: compiled coredns failed to load PopuraDNS/Corefile" >&2 + exit "$COREDNS_STATUS" + fi +elif command -v coredns >/dev/null 2>&1 && coredns -plugins 2>/dev/null | grep -q '^meshname$'; then + echo "[validate-config] checking PopuraDNS/Corefile with local compiled coredns" + set +e + timeout 8s coredns -conf PopuraDNS/Corefile -dns.port=0 + COREDNS_STATUS=$? + set -e + if [ "$COREDNS_STATUS" -ne 0 ] && [ "$COREDNS_STATUS" -ne 124 ]; then + echo "[validate-config] error: local compiled coredns failed to load PopuraDNS/Corefile" >&2 + exit "$COREDNS_STATUS" + fi else - echo "[validate-config] cannot check Corefile syntax (no coredns or docker)" + echo "[validate-config] cannot check Corefile syntax (need docker or a compiled local coredns with meshname plugin)" fi # ensure onion and i2p zones are present in Corefile @@ -49,13 +69,18 @@ for zone in "onion.:53" "i2p.:53" "eth.:53" "bit.:53" "alt.:53" "loki.:53" "zil. fi done -# verify i2pd DNS server is enabled in its config -if grep -q "\[dns\]" i2pd_yggdrasil_docker/src/i2pd.conf; then - if ! awk '/\[dns\]/,/\[/{if($0~/enabled/ && $0~/true/) ok=1} END{exit !ok}' i2pd_yggdrasil_docker/src/i2pd.conf; then - echo "[validate-config] warning: i2pd DNS section present but not enabled" +if ! grep -A6 '^\.:53 {' PopuraDNS/Corefile | grep -q 'acl {'; then + echo "[validate-config] error: Corefile catch-all zone must include an ACL to avoid open recursion" >&2 + exit 1 +fi + +# verify the current .i2p DNS architecture is documented in config +if grep -q '^\[dns\]' i2pd_yggdrasil_docker/src/i2pd.conf; then + if ! awk '/^\[dns\]/,/^\[/{if($0~/enabled/ && $0~/true/) ok=1} END{exit !ok}' i2pd_yggdrasil_docker/src/i2pd.conf; then + echo "[validate-config] warning: i2pd [dns] section exists but is disabled; the stack currently expects the separate i2pdns bridge service" fi -else - echo "[validate-config] warning: i2pd.conf missing [dns] section" +elif ! grep -qE 'i2pdns bridge|local i2pdns bridge service' i2pd_yggdrasil_docker/src/i2pd.conf; then + echo "[validate-config] warning: i2pd.conf should document that .i2p DNS is served by the separate i2pdns bridge service" fi # tor configuration should expose DNSPort for onion resolution @@ -78,14 +103,19 @@ if command -v dig >/dev/null 2>&1; then fi # ensure referenced secrets exist -for s in ./secrets/tz.txt ./secrets/YGGDRASIL_GENERATE_KEYS.txt; do +for s in \ + ./secrets/tz.txt \ + ./secrets/YGGDRASIL_GENERATE_KEYS.txt \ + ./secrets/pihole_webpassword.txt \ + ./secrets/3proxy_users.txt \ + ./secrets/namecoin_rpc_password.txt; do if [ ! -f "$s" ]; then echo "[validate-config] error: secret file $s is missing" >&2 exit 1 fi done -# check for :latest tags (discouraged in prod) +# check for mutable :latest tags in deployment compose files if grep -qE 'image: .*:latest' docker-compose.yml; then echo "[validate-config] warning: some services use the ':latest' image tag;" \ "pin to a specific version before deploying to production." @@ -96,10 +126,6 @@ if ! grep -q 'healthcheck:' docker-compose.yml; then echo "[validate-config] warning: no healthcheck definitions found in docker-compose.yml" fi - echo "[validate-config] warning: some services use the ':latest' image tag;" \ - "pin to a specific version before deploying to production." -fi - # verify every service has a restart policy if ! grep -q "restart:" docker-compose.yml; then echo "[validate-config] warning: some services lack a restart policy." @@ -112,13 +138,19 @@ if [ -n "$(echo "$ports" | uniq -d)" ]; then fi # unbound configuration syntax check -if command -v unbound-checkconf >/dev/null 2>&1; then +if command -v docker >/dev/null 2>&1; then + echo "[validate-config] checking unbound configuration in compiled repo image" + UNBOUND_IMAGE="$(docker build -q -f unbound_arm/Dockerfile unbound_arm | tail -n1)" + docker run --rm --entrypoint /bin/sh \ + -v "${PWD}/unbound/unbound.conf:/opt/unbound/etc/unbound/unbound.conf:ro" \ + -v "${PWD}/unbound/forward-records.conf:/opt/unbound/etc/unbound/forward-records.conf:ro" \ + -v "${PWD}/unbound/a-records.conf:/opt/unbound/etc/unbound/a-records.conf:ro" \ + -v "${PWD}/unbound/srv-records.conf:/opt/unbound/etc/unbound/srv-records.conf:ro" \ + "$UNBOUND_IMAGE" -lc \ + 'getent passwd _unbound >/dev/null || useradd -r -s /usr/sbin/nologin _unbound; unbound-checkconf /opt/unbound/etc/unbound/unbound.conf' +elif command -v unbound-checkconf >/dev/null 2>&1; then echo "[validate-config] checking unbound configuration locally" - unbound-checkconf -c unbound/unbound.conf -elif command -v docker >/dev/null 2>&1; then - echo "[validate-config] checking unbound configuration in container" - docker run --rm -v "${PWD}/unbound/unbound.conf:/etc/unbound/unbound.conf:ro" \ - mvance/unbound:latest unbound-checkconf -c /etc/unbound/unbound.conf + unbound-checkconf unbound/unbound.conf else echo "[validate-config] cannot check unbound config (no unbound-checkconf or docker)" fi @@ -134,6 +166,20 @@ for cfg in 3proxy/first-instanse.cfg 3proxy/second-instanse.cfg; do fi done +if grep -q '^auth none$' 3proxy/first-instanse.cfg; then + echo "[validate-config] error: dark3proxy must not expose a public proxy with 'auth none'" >&2 + exit 1 +fi + +if grep -q 'CHANGE_ME_NAMECOIN_RPC_PASSWORD' docker-compose.yml; then + echo "[validate-config] error: replace inline Namecoin RPC password placeholders with Docker secrets" >&2 + exit 1 +fi + +if grep -q 'tskey-YOUR-AUTH-KEY-HERE' docker-compose.yml; then + echo "[validate-config] warning: tailscale is still configured with the placeholder auth key" +fi + # simple sanity checks if grep -q "container_name: darkproxy" docker-compose.yml; then echo "[validate-config] warning: 'container_name: darkproxy' appears in compose;" \ diff --git a/tailscale/Dockerfile b/tailscale/Dockerfile index 71ffcb2..0962583 100644 --- a/tailscale/Dockerfile +++ b/tailscale/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 -FROM tailscale/tailscale:latest +FROM tailscale/tailscale@sha256:dbeff02d2337344b351afac203427218c4d0a06c43fc10a865184063498472a6 RUN apk add --no-cache \ iptables \