Pin deployment images and refresh docs
Configuration validation / lint (push) Has been cancelled
Configuration validation / smoke (push) Has been cancelled

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
auto-ci
2026-05-02 15:23:53 -04:00
parent ec4aff6cfe
commit b6d49549fe
7 changed files with 851 additions and 459 deletions
+38 -35
View File
@@ -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:
* `<host-ip>: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 <host-ip>:2000 -I http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion
curl --proxy-user proxyuser:REPLACE_WITH_A_LONG_RANDOM_PASSWORD --socks5-hostname <host-ip>:2000 -I http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion
# Clearnet over the only published proxy port
curl --socks5-hostname <host-ip>:2000 -I https://example.com
curl --proxy-user proxyuser:REPLACE_WITH_A_LONG_RANDOM_PASSWORD --socks5-hostname <host-ip>: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.
+41 -16
View File
@@ -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
+616 -323
View File
@@ -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
+74 -44
View File
@@ -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
+8 -13
View File
@@ -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"]
+73 -27
View File
@@ -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;" \
+1 -1
View File
@@ -1,5 +1,5 @@
#syntax=docker/dockerfile:1
FROM tailscale/tailscale:latest
FROM tailscale/tailscale@sha256:dbeff02d2337344b351afac203427218c4d0a06c43fc10a865184063498472a6
RUN apk add --no-cache \
iptables \