chore: snapshot before production push
Configuration validation / lint (push) Has been cancelled
Configuration validation / smoke (push) Has been cancelled

This commit is contained in:
auto-ci
2026-03-01 20:39:26 -05:00
commit 11b766c906
18 changed files with 1479 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
# Darkproxy AI Coding Guidelines
## Project Overview
Darkproxy is a multi-container Docker stack enabling anonymous proxying across darknet (I2P, Tor) and clearnet. It chains SOCKS5 proxies through custom DNS resolvers, combining Yggdrasil networking, CoreDNS service orchestration, and blockchain-based TLD resolvers (Alfis, EmerCoin, meshname).
## Architecture
**Fixed container IPs on `darkproxy` network (10.5.0.0/16)**:
- `10.5.0.2`: i2pd_yggdrasil - I2P + Yggdrasil IPv6 tunneling
- `10.5.0.3`: alfis - Blockchain resolver for .anon/.ygg/.btn/.conf TLDs
- `10.5.0.4`: coredns - CoreDNS (PopuraDNS) DNS orchestration hub
- `10.5.0.5`: unbound - Recursive clearnet DNS
- `10.5.0.6`: pihole - DNS filtering + upstream forwarder
- `10.5.0.7`: tor_yggdrasil - Tor + Yggdrasil tunneling
- `10.5.0.8`: dark3proxy - SOCKS5/HTTP proxy (main entrypoint)
- `10.5.0.9`: emc - EmerCoin resolver for .emc/.coin/.lib domains
**Data flow**: Client → dark3proxy (10.5.0.8:1080 SOCKS5) → pihole DNS (10.5.0.6) → coredns (10.5.0.4) → TLD-specific resolvers → upstream SOCKS backends (i2pd/tor).
## Key Workflows
**Build custom images** (with version pinning via build args):
- I2P: `cd i2pd_yggdrasil_docker/src && ./make_docker_image.sh` (sets I2PD_VERSION=2.58.0, YGGDRASIL_VERSION=v0.5.12, UBUNTU_VERSION=24.04)
- Tor: `cd tor_yggdrasil_docker && ./build_image.sh` (same versions via git describe fallback)
- 3proxy: No build script—uses GitHub release binary download in Dockerfile
**Deploy/Debug**:
- Start: `docker-compose up --build` from root
- Logs: `docker-compose logs -f coredns` (or dark3proxy, i2pd_yggdrasil, tor_yggdrasil)
- Shell: `docker exec -it darkdns /bin/sh` (use container_name from compose)
- Health: Each service has `healthcheck` or ping-based validation in entrypoint
**Add new TLD resolver**:
1. In docker-compose.yml: add new service with fixed IP in 10.5.0.x range, ensure internal network access
2. In PopuraDNS/Corefile: add block like `newtld.:53 { acl { allow net 10.0.0.0/8 ...; block }; forward . 10.5.0.X:53 }`
3. Rebuild coredns: `docker-compose up --build coredns`
## Conventions
**Secrets/Environment**: Stored in `secrets/` directory (tz.txt for timezone, YGGDRASIL_GENERATE_KEYS.txt for key generation). Mounted as Docker secrets, referenced in environment via `/run/secrets/`.
**Proxy Routing Logic** (in `3proxy/first-instanse.cfg`):
- Parent rules chain traffic: i2p domains → i2pd SOCKS (10.5.0.2:4447), onion → tor SOCKS (10.5.0.7:9050), Yggdrasil (200::/7) → local SOCKS, clearnet → tor fallback
- Blacklist format: `{{vk.com,ok.ru,...}}` (blocks these domains)
**DNS Stacking**: pihole (ad-filtering) → coredns (routing) → specialists. pihole upstreams to coredns (10.5.0.4), coredns forwards TLDs to resolvers. ACLs in Corefile block external networks; only 10.0.0.0/8, 127.0.0.1, fc00::/7 allowed.
**Yggdrasil Key Generation**: Services `i2pd_yggdrasil` and `tor_yggdrasil` run Python utils (yggdrasil_get_keys, yggdrasil_find_public_peers) in entrypoint—generates strong keys + finds optimal peers unless YGGDRASIL_GENERATE_KEYS=false.
**Networking**: All services require `sysctls: net.ipv6.conf.all.disable_ipv6=0` for Yggdrasil IPv6. Tunneling services (i2pd_yggdrasil, tor_yggdrasil) need `privileged: true`, `cap_add: NET_ADMIN`, `/dev/net/tun:/dev/net/tun`.
## Examples
- **Port Mapping** (via Yggdrasil IP 100.117.196.19): SOCKS on 2000→1080, 3proxy-eagle web 2002→8161, I2P console 2001→7070
- **Config Mounting**: Read-only volumes for configs—e.g., `./unbound/unbound.conf:/opt/unbound/etc/unbound/unbound.conf`
- **Image Tagging**: Custom builds tag as `service_name:${TAG_VERSION}` (git tag) and `:latest`; published to registry (host60/ prefix in docker-compose)
Reference files: [docker-compose.yml](docker-compose.yml), [PopuraDNS/Corefile](PopuraDNS/Corefile), [3proxy/first-instanse.cfg](3proxy/first-instanse.cfg), [i2pd_yggdrasil_docker/src/make_docker_image.sh](i2pd_yggdrasil_docker/src/make_docker_image.sh), [tor_yggdrasil_docker/build_image.sh](tor_yggdrasil_docker/build_image.sh)</content>
<parameter name="filePath">/home/sommopfle/darkproxy/.github/copilot-instructions.md
+63
View File
@@ -0,0 +1,63 @@
name: "Configuration validation"
on:
push:
paths:
- 'docker-compose.yml'
- 'PopuraDNS/**'
- '.github/workflows/**'
pull_request:
paths:
- 'docker-compose.yml'
- 'PopuraDNS/**'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run full validation script
run: |
chmod +x scripts/validate-config.sh
scripts/validate-config.sh
smoke:
needs: lint
runs-on: ubuntu-latest
services:
docker:
image: docker:24-dind
privileged: true
options: >-
--cpus=2 --memory=4g
steps:
- uses: actions/checkout@v4
- name: Start stack and wait for health
run: |
docker compose up -d --build
# wait up to 120 seconds for each container's healthcheck to pass
for svc in darkdns darkpihole darkunbound darkalfis darkemer dark3proxy darktor darkproxy; do
echo "waiting for $svc"
for i in {1..24}; do
status=$(docker inspect -f '{{.State.Health.Status}}' $svc 2>/dev/null || echo none)
if [ "$status" = "healthy" ]; then
echo "$svc healthy" && break
fi
sleep 5
done
done
docker compose ps
# quick DNS smoke tests via CoreDNS container
echo "testing onion resolution"
docker exec darkdns dig +short @127.0.0.1 -p 53 facebookcorewwwi.onion
echo "testing i2p resolution"
docker exec darkdns dig +short @127.0.0.1 -p 53 stats.i2p
docker compose down
+7
View File
@@ -0,0 +1,7 @@
i2pd/data/
tor/data/
# runtime secrets should not be committed
secrets/
generated.yml
+74
View File
@@ -0,0 +1,74 @@
# Stage 1: Build
FROM --platform=$BUILDPLATFORM ubuntu:22.04 AS builder
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG TARGETARCH
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && apt-get install -y \
qtbase5-dev \
qtchooser \
qt5-qmake \
qtbase5-dev-tools \
wget \
git \
build-essential \
libqt5core5a \
&& rm -rf /var/lib/apt/lists/*
# Download appropriate 3proxy binary based on architecture
RUN if [ "$TARGETARCH" = "amd64" ]; then \
wget -O 3proxy.deb https://github.com/3proxy/3proxy/releases/download/0.9.4/3proxy-0.9.4.x86_64.deb; \
elif [ "$TARGETARCH" = "arm64" ]; then \
wget -O 3proxy.deb https://github.com/3proxy/3proxy/releases/download/0.9.4/3proxy-0.9.4.aarch64.deb || \
{ echo "ARM64 binary not available, using x86_64"; wget -O 3proxy.deb https://github.com/3proxy/3proxy/releases/download/0.9.4/3proxy-0.9.4.x86_64.deb; }; \
elif [ "$TARGETARCH" = "arm" ]; then \
wget -O 3proxy.deb https://github.com/3proxy/3proxy/releases/download/0.9.4/3proxy-0.9.4.armv7l.deb || \
{ echo "ARMv7 binary not available"; exit 1; }; \
fi && \
dpkg -i 3proxy.deb || true
# Build 3proxy-eagle in a dedicated source directory
RUN git clone https://gitea.darkness.services/acetone/3proxy-eagle.git /src/3proxy-eagle \
&& cd /src/3proxy-eagle \
&& find . -name "*.cpp" -o -name "*.h" | xargs sed -i 's/127\.0\.0\.1/0.0.0.0/g' \
&& cd /src/3proxy-eagle/src \
&& qmake 3proxy-eagle.pro \
&& make -j$(nproc)
# Stage 2: Runtime
FROM ubuntu:22.04
ARG TARGETARCH
RUN apt-get update && apt-get install -y \
libqt5core5a \
libqt5network5 \
libqt5xml5 \
libqt5sql5 \
libqt5sql5-sqlite \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Copy binaries using the correct absolute paths from Stage 1
COPY --from=builder /usr/bin/3proxy /usr/bin/3proxy
COPY --from=builder /src/3proxy-eagle/src/3proxy-eagle /usr/bin/3proxy-eagle
# Setup config directories
RUN mkdir -p /etc/3proxy /etc/3proxy-eagle/data
# Ensure these files exist in your local directory where you run 'docker build'
#COPY first-instanse.cfg /etc/3proxy/
#COPY second-instanse.cfg /etc/3proxy/
EXPOSE 8161
# Run in foreground
CMD ["/usr/bin/3proxy-eagle", \
"-i", "/usr/bin/3proxy,/etc/3proxy/first-instanse.cfg", \
"-i", "/usr/bin/3proxy,/etc/3proxy/second-instanse.cfg", \
"-w", "/etc/3proxy-eagle/data", \
"-t", "DarkProxy"]
+45
View File
@@ -0,0 +1,45 @@
# regular 3proxy configuration
fakeresolve
flush
auth iponly
admin -p8161 -a0.0.0.0
# strict required by 3proxy-eagle log lines
log
logformat " type=%N destination=%n to=%O from=%I"
# 3proxy-eagle black list format
{{vk.com,ok.ru,mail.ru,gosuslugi.ru,127.0.0.1}}
# regular 3proxy configuration again
# expose a lightweight status socket for Prometheus scraping
# the exporter will connect here and convert counters to metrics
monitor -p6800
## i2p sites
allow * * *.i2p
#parent 1000 http 127.0.0.1 4444
parent 1000 socks5+ 10.5.0.2 4447
## yggdrasil (127.0.0.1 1085 is second instanse)
allow * * 200::/7
parent 1000 socks5+ 127.0.0.1 1085
## ygg domains resolving by alfis
allow * * *.ygg
parent 1000 socks5+ 127.0.0.1 1085
## meshnames domains resolving by meshnamed
allow * * *.meshname
parent 1000 socks5+ 127.0.0.1 1085
allow * * *.meship
parent 1000 socks5+ 127.0.0.1 1085
## onion sites
allow * * *.onion
parent 1000 socks5+ 10.5.0.7 9050
## clearnet via another proxy or change to tor (9050)
allow *
parent 1000 socks5+ 10.5.0.7 9050
socks -olSO_REUSEADDR,SO_REUSEPORT -ocTCP_TIMESTAMPS,TCP_NODELAY -osTCP_NODELAY -46 -i0.0.0.0 -p1080
proxy -olSO_REUSEADDR,SO_REUSEPORT -ocTCP_TIMESTAMPS,TCP_NODELAY -osTCP_NODELAY -46 -a1 -i0.0.0.0 -p3128
+8
View File
@@ -0,0 +1,8 @@
auth iponly
# allow only Yggdrasil network subnet by this instanse
# otherwise all ygg/meshname/meship domains with
# non-yggdrasil addresses goes bypass any rules
# and potentially can deanonimaze outproxy machine
allow * * 200::/7
deny *
socks -olSO_REUSEADDR,SO_REUSEPORT -ocTCP_TIMESTAMPS,TCP_NODELAY -osTCP_NODELAY -64 -i127.0.0.1 -p1085
Submodule
+1
Submodule PopuraDNS added at 749c8a6300
+173
View File
@@ -0,0 +1,173 @@
Welcome to darkproxy...
This container runs the following vontainers in the stack.
3proxy-eagle - Socks5/http proxy
- DNS
- pihole - ad blocking and metrics
- PopuraDNS - non-recursive DNS forwards requests to the following:
Alfis - Blockchain based yggdrasil resolver
EmerCoin - Resolves EMC domains
UnBound - Recursive DNS for Clearnet domains
* .onion and .i2p domain names are now resolved via the stack (see DNS section below)
- I2PD over Yggdrasil container (`container_name: darki2p`)
* Yggdrasil IP network stack
* Socks5 server for I2P
- Tor container
The system offers a DNS that resolves many darknet and clearnet IP's. The
stack now handles:
* `*.onion` forwarded to Tor's DNSPort running in the `darktor` container at
10.5.0.7:9053.
* `*.i2p` served by the built-in DNS server inside the `darki2p` container
(10.5.0.2:53) which is enabled via the `[dns]` section in `i2pd.conf`.
You can query these directly from any container on the `darkproxy` network, for
example:
```sh
# Tor .onion domains
docker run --rm --network darkproxy infoblox/dig dig @10.5.0.4 facebookcorewwwi.onion
# I2P .i2p domains
docker run --rm --network darkproxy infoblox/dig dig @10.5.0.4 stats.i2p
# Ethereum Name Service (.eth) via Cloudflare fallback
docker run --rm --network darkproxy infoblox/dig dig @10.5.0.4 vitalik.eth
# Other supported TLDs: .bit, .alt, .loki, .zil, .web3, .exit, .onion4, .onion6
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.
## Supported TLDs and resolvers
The stack now provides DNS resolution for a comprehensive set of alternative TLDs:
| TLD | Resolver | Purpose |
|-----|----------|---------|
| `.onion`, `.exit`, `.onion4`, `.onion6` | Tor DNSPort (10.5.0.7:9053) | Tor hidden services |
| `.i2p` | i2pd DNS (10.5.0.2:53) | I2P eepsite names |
| `.eth` | Cloudflare 1.1.1.1 | Ethereum Name Service |
| `.bit` | Google 8.8.8.8 | Namecoin names |
| `.alt` | alt-root 185.121.177.177 | Alternative DNS root |
| `.loki` | Cloudflare 1.1.1.1 | Lokinet privacy network |
| `.zil` | Cloudflare 1.1.1.1 | Zilliqa blockchain |
| `.web3` | Cloudflare 1.1.1.1 | General blockchain namespace |
| Alfis TLDs | Alfis (10.5.0.3) | `.anon`, `.btn`, `.conf`, `.index`, `.merch`, `.mirror`, `.mob`, `.screen`, `.srv`, `.ygg` |
| EmerCoin TLDs | EmerCoin (10.5.0.9) | `.emc`, `.coin`, `.lib`, `.bazar`, `.enum` |
| OpenNIC TLDs | OpenNIC public resolvers | `.bbs`, `.chan`, `.cyb`, `.dyn`, `.epic`, `.geek`, `.gopher`, `.indy`, `.libre`, `.neo`, `.null`, `.o`, `.oss`, `.oz`, `.parody`, `.pirate`, `.fur`, `.ku`, `.rm`, `.te`, `.ti`, `.uu`, `.ko` |
| Clearnet | Unbound (10.5.0.5) | All other domains via recursive resolution |
## Configuration validation and drift tests
A simple automation is included to help detect accidental changes to the
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`.
- 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.
2. **CI workflow** `.github/workflows/config-validation.yml` is triggered on
pushes or pull requests affecting `docker-compose.yml` or `PopuraDNS/`.
The job executes the same `docker compose config` comparison and runs the
Corefile check inside a container.
3. **Updating the baseline** when intentional changes are made to the
compose file, regenerate the baseline:
```sh
scripts/validate-config.sh # fails with drift
cp generated.yml docker-compose.lock.yml
git add docker-compose.lock.yml
```
These steps ensure that configuration drift is caught early and reviewers can
see what has changed.
## Monitoring the proxy
A lightweight Prometheus/Grafana stack is included to expose 3proxy metrics
and give you visibility into traffic volumes, connected sessions, etc.
### how it works
* `3proxy` is configured with `monitor -p6800`, which sets up a plain-text
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.
### 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
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`.
### tips
* Alerts can be added in Prometheus rules, e.g. fire when `proxy_conns`
exceeds a threshold for several minutes.
* If you dont want the full stack, you can still query the monitor port
directly with `nc`; nothing in the proxy depends on the exporter.
* The `scripts/validate-config.sh` script warns if a 3proxy config lacks a
`monitor` line.
## Production readiness checklist
Make sure you never commit real secrets. The `secrets/` directory is now
included in `.gitignore`; both timezone and Yggdrasil key files live there and
are mounted into containers at runtime.
Before deploying to a live environment, run the validation script and resolve
any warnings or errors. The script covers:
* YAML syntax and drift against the committed baseline
* CoreDNS/PopuraDNS Corefile syntax
* 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)
* Verification that restart policies exist
The GitHub Actions workflow also includes a **smoke test** job that spins up
all services in `docker-compose.yml` using a DockerinDocker service and
waits for each containers healthcheck to report `healthy`. This gives an
additional layer of confidence that the stack can be built and started
successfully.
You can also extend the script with additional service-specific checks such as
running `docker run ...` commands to exercise the images, scanning the
`3proxy` config more deeply, or linting other mounted configuration files.
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.
+43
View File
@@ -0,0 +1,43 @@
# ARM-specific override for darkproxy stack
# Use together with the main compose file:
#
# docker compose -f docker-compose.yml -f docker-compose.arm.yml up --build
#
# This file adds `platform: linux/arm64` hints to services so the correct
# architecture is selected when running on an ARM host. It does **not** replace
# any images; if an image is not available for ARM (e.g. alfis, unbound, the
# prebuilt tor_yggdrasil) Docker will attempt emulation via QEMU or fall back to
# amd64.
#
# You can also modify this file to swap in ARM-specific images or build
# instructions if you have them.
services:
dark3proxy:
platform: linux/arm64
i2pd_yggdrasil:
platform: linux/arm64
tor_yggdrasil:
platform: linux/arm64
alfis:
platform: linux/arm64
coredns:
platform: linux/arm64
unbound:
platform: linux/arm64
pihole:
platform: linux/arm64
emc:
platform: linux/arm64
geth:
platform: linux/arm64
# networks, volumes, and secrets are inherited from the base compose file
+269
View File
@@ -0,0 +1,269 @@
services:
dark3proxy:
container_name: dark3proxy
image: host60/darkproxy-dark3proxy:v1.0
build:
context: ./3proxy/.
dns:
- "10.5.0.6"
dns_search: internal.namespace #namespace used in internal DNS
volumes:
- "./3proxy/first-instanse.cfg:/etc/3proxy/first-instanse.cfg"
- "./3proxy/second-instanse.cfg:/etc/3proxy/second-instanse.cfg"
restart: unless-stopped
sysctls:
- "net.ipv6.conf.all.disable_ipv6=0"
ports:
- 100.117.196.19:2000:1080 # socks port
- 100.117.196.19:2002:8161 # 3proxy-eagle web page
networks:
darkproxy:
ipv4_address: 10.5.0.8
i2pd_yggdrasil:
container_name: darki2p
# image: i2pd_yggdrasil:latest
image: host60/i2pd_yggdrasil:v1.0
privileged: true
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
# I2P Service Ports
# - "2827:2827" # BOB Bridge
# - "4444:4444" # HTTP Proxy
# - "4447:4447" # SOCKS Proxy
- "100.117.196.19:2001:7070" # Webconsole
# - "7650:7650" # I2PControl
# - "7654:7654" # I2CP
# - "7656:7656" # SAM Bridge (TCP)
- "10765:10765" # Main I2P Listener
# [dns] section enabled in i2pd.conf; DNS port is 53 (accessible internally at 10.5.0.2:53)
# mapping to host is possible if desired, e.g. 10853:53/udp
# Yggdrasil Ports
- "10654:10654" # Yggdrasil Listener
environment:
tz: /run/secrets/tz
secrets:
- tz
restart: unless-stopped
healthcheck:
test: ["CMD", "bash", "-c", "pgrep i2pd && pgrep yggdrasil"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
sysctls:
- "net.ipv6.conf.all.disable_ipv6=0"
mac_address: ce:22:b8:0e:6e:78
networks:
darkproxy:
ipv4_address: 10.5.0.2
tor_yggdrasil:
image: host60/tor_yggdrasil:v1.0
# image: tor_yggdrasil:latest
# container_name: tor_over_yggdrasil
container_name: darktor
# platform removed; image is amd64-only
cap_add:
- NET_ADMIN # Required for network tunnel management
security_opt:
- no-new-privileges:true # Security enhancement - prevent privilege esca>
devices:
- /dev/net/tun:/dev/net/tun # TUN device for Yggdrasil network interface
ports:
# - "127.0.0.1:9050:9050/tcp" # SOCKS5 proxy port (Tor) for application-l>
- "10655:10655/tcp" # Yggdrasil peer connections
secrets:
- YGGDRASIL_GENERATE_KEYS
environment:
YGGDRASIL_GENERATE_KEYS: /run/secrets/YGGDRASIL_GENERATE_KEYS # Generate new Yggdrasil keys on startup
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 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
image: host60/darkdns:v1.0
build:
context: ./PopuraDNS
dockerfile: Dockerfile
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 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/arm64
# 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"
- "100.117.196.19: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/arm64
container_name: darkgeth
command:
- --syncmode=light
- --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/arm64
container_name: darkemer
volumes:
- emc_data:/emc
- /etc/localtime:/etc/localtime:ro
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
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
+311
View File
@@ -0,0 +1,311 @@
services:
dark3proxy:
container_name: dark3proxy
image: host60/darkproxy-dark3proxy:v1.0
build:
context: ./3proxy/.
dns:
- "10.5.0.6"
dns_search: internal.namespace #namespace used in internal DNS
volumes:
- "./3proxy/first-instanse.cfg:/etc/3proxy/first-instanse.cfg"
- "./3proxy/second-instanse.cfg:/etc/3proxy/second-instanse.cfg"
restart: unless-stopped
sysctls:
- "net.ipv6.conf.all.disable_ipv6=0"
ports:
- 2000:1080 # socks port
- 2002:8161 # 3proxy-eagle web page
networks:
darkproxy:
ipv4_address: 10.5.0.8
i2pd_yggdrasil:
container_name: darki2p
image: host60/i2pd_yggdrasil:v1.3
# image: i2pd_yggdrasil:latest
privileged: true
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
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
# I2P name resolution occurs over the SOCKS proxy; there is no
# separate DNS listener in this build (the `dns` section in i2pd.conf
# is currently disabled because the shipped i2pd release doesn't
# support it). SOCKS remains on port 4447 and will resolve *.i2p names.
# mapping to host is possible if desired, e.g. 10853:53/udp
# Yggdrasil Ports
- "10654:10654" # Yggdrasil Listener
environment:
tz: /run/secrets/tz
secrets:
- tz
restart: unless-stopped
healthcheck:
test: ["CMD", "bash", "-c", "pgrep i2pd && pgrep yggdrasil"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
sysctls:
- "net.ipv6.conf.all.disable_ipv6=0"
mac_address: ce:22:b8:0e:6e:78
networks:
darkproxy:
ipv4_address: 10.5.0.2
tor_yggdrasil:
image: host60/tor_yggdrasil:v1.0
# image: tor_yggdrasil:latest
# container_name: tor_over_yggdrasil
container_name: darktor
# platform removed; image is amd64-only
cap_add:
- NET_ADMIN # Required for network tunnel management
security_opt:
- no-new-privileges:true # Security enhancement - prevent privilege esca>
devices:
- /dev/net/tun:/dev/net/tun # TUN device for Yggdrasil network interface
ports:
# - "127.0.0.1:9050:9050/tcp" # SOCKS5 proxy port (Tor) for application-l>
- "10655:10655/tcp" # Yggdrasil peer connections
secrets:
- YGGDRASIL_GENERATE_KEYS
environment:
YGGDRASIL_GENERATE_KEYS: /run/secrets/YGGDRASIL_GENERATE_KEYS # Generate new Yggdrasil keys on startup
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 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
image: host60/darkdns:v1.0
build:
context: ./PopuraDNS
dockerfile: Dockerfile
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 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/arm64
# 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
emc:
image: wg00/emercoin:0.8.4
platform: linux/arm64
container_name: darkemer
volumes:
- emc_data:/emc
- /etc/localtime:/etc/localtime:ro
networks:
darkproxy:
ipv4_address: 10.5.0.9
restart: unless-stopped
stop_grace_period: 30s
tailscale:
build:
context: ./tailscale
dockerfile: Dockerfile
container_name: darkscale
hostname: darkproxy-exit
cap_add:
- NET_ADMIN
- SYS_MODULE
devices:
- /dev/net/tun:/dev/net/tun
environment:
# ⚠️ Get your own auth key from https://login.tailscale.com/admin/settings/keys
- TS_AUTHKEY=${TS_AUTHKEY:-tskey-YOUR-AUTH-KEY-HERE}
- TS_EXTRA_ARGS=--accept-dns=false --advertise-exit-node
- TS_STATE_DIR=/var/lib/tailscale
volumes:
- tailscale_data:/var/lib/tailscale
networks:
darkproxy:
ipv4_address: 10.5.0.10
sysctls:
- net.ipv4.ip_forward=1
- net.ipv6.conf.all.forwarding=1
restart: unless-stopped
# monitoring exporter for 3proxy metrics
3proxy_exporter:
container_name: dark3proxy-exporter
build:
context: ./monitor
image: darkproxy-3proxy-exporter:latest
depends_on:
- dark3proxy
networks:
- darkproxy
prometheus:
image: prom/prometheus:latest
container_name: darkprom
volumes:
- ./monitor/prometheus.yml:/etc/prometheus/prometheus.yml:ro
ports:
- "9090:9090"
networks:
- darkproxy
grafana:
image: grafana/grafana:latest
container_name: darkgraf
ports:
- "2005:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
volumes:
- grafana-data:/var/lib/grafana
networks:
- darkproxy
volumes:
darkalfis_data:
name: darkalfis_data
emc_data:
name: emc_data
tor-data:
driver: local
tailscale_data:
name: tailscale_data
grafana-data:
name: grafana-data
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
Submodule i2pd_yggdrasil_docker added at 82f003e327
+37
View File
@@ -0,0 +1,37 @@
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Dnsmasq config for Pi-hole's FTLDNS
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
###############################################################################
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: #
# /etc/pihole/setupVars.conf #
# #
# ANY OTHER CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
# WITHIN /etc/dnsmasq.d/yourname.conf #
###############################################################################
addn-hosts=/etc/pihole/local.list
addn-hosts=/etc/pihole/custom.list
localise-queries
no-resolv
log-queries
log-facility=/var/log/pihole/pihole.log
log-async
cache-size=10000
server=172.30.0.9
server=2001:db9::a
interface=eth0
+42
View File
@@ -0,0 +1,42 @@
# Pi-hole: A black hole for Internet advertisements
# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# RFC 6761 config file for Pi-hole
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
###############################################################################
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
# WITHIN /etc/dnsmasq.d/yourname.conf #
###############################################################################
# RFC 6761: Caching DNS servers SHOULD recognize
# test, localhost, invalid
# names as special and SHOULD NOT attempt to look up NS records for them, or
# otherwise query authoritative DNS servers in an attempt to resolve these
# names.
server=/test/
server=/localhost/
server=/invalid/
# The same RFC requests something similar for
# 10.in-addr.arpa. 21.172.in-addr.arpa. 27.172.in-addr.arpa.
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 28.172.in-addr.arpa.
# 17.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
# 18.172.in-addr.arpa. 24.172.in-addr.arpa. 30.172.in-addr.arpa.
# 19.172.in-addr.arpa. 25.172.in-addr.arpa. 31.172.in-addr.arpa.
# 20.172.in-addr.arpa. 26.172.in-addr.arpa. 168.192.in-addr.arpa.
# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
# 01-pihole.conf) because this also covers IPv6.
# OpenWRT furthermore blocks bind, local, onion domains
# see https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob_plain;f=package/network/services/dnsmasq/files/rfc6761.conf;hb=HEAD
# and https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
# We do not include the ".local" rule ourselves, see https://github.com/pi-hole/pi-hole/pull/4282#discussion_r689112972
server=/bind/
server=/onion/
+155
View File
@@ -0,0 +1,155 @@
# PowerShell counterpart to validate-config.sh
# Run this in a PowerShell session; it will perform the same checks.
param(
[string]$BaselineFile = "docker-compose.lock.yml"
)
function Assert-Error($msg) {
Write-Error $msg
exit 1
}
if (Get-Command docker -ErrorAction SilentlyContinue) {
Write-Host "[validate-config] generating normalized compose manifest"
docker compose config | Set-Content -Path generated.yml -Encoding utf8
if (Test-Path $BaselineFile) {
Write-Host "[validate-config] comparing against baseline $BaselineFile"
$diff = Compare-Object -ReferenceObject (Get-Content $BaselineFile) -DifferenceObject (Get-Content generated.yml) -SyncWindow 0
if ($diff) {
Write-Host "[validate-config] configuration drift detected!"
Assert-Error "Please review and, if the change is intentional, update $BaselineFile."
}
Write-Host "[validate-config] docker-compose.yml matches baseline"
} else {
Write-Host "[validate-config] baseline file not found, creating $BaselineFile"
Copy-Item generated.yml $BaselineFile
Write-Host "[validate-config] please commit $BaselineFile to the repository"
}
} else {
Write-Host "[validate-config] docker binary not found; skipping compose validation"
}
# CoreDNS check
if (Get-Command coredns -ErrorAction SilentlyContinue) {
Write-Host "[validate-config] checking PopuraDNS/Corefile with local coredns"
coredns -conf PopuraDNS/Corefile -dns.port=0
$canCheckCorefile = $true
} elseif (Get-Command docker -ErrorAction SilentlyContinue) {
Write-Host "[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
$canCheckCorefile = $true
} else {
Write-Host "[validate-config] cannot check Corefile syntax (no coredns or docker)"
$canCheckCorefile = $false
}
# ensure onion and i2p zones are present in Corefile
if ($canCheckCorefile) {
foreach ($zone in @('onion.:53','i2p.:53','eth.:53','bit.:53','alt.:53','loki.:53','zil.:53','web3.:53','exit.:53','onion4.:53','onion6.:53')) {
if (-not (Select-String -Path PopuraDNS/Corefile -Pattern $zone -Quiet)) {
Assert-Error "[validate-config] error: Corefile missing $zone block"
}
}
}
# verify i2pd DNS server is enabled in its config
if (Select-String -Path 'i2pd_yggdrasil_docker/src/i2pd.conf' -Pattern '\[dns\]' -Quiet) {
$dnsSection = Select-String -Path 'i2pd_yggdrasil_docker/src/i2pd.conf' -Pattern 'enabled' -Context 0,1 | Where-Object { $_.Line -match 'true' }
if (-not $dnsSection) {
Write-Host "[validate-config] warning: i2pd DNS section present but not enabled"
}
} else {
Write-Host "[validate-config] warning: i2pd.conf missing [dns] section"
}
# tor config should contain DNSPort
if (-not (Select-String -Path 'tor_yggdrasil_docker/torrc' -Pattern '^DNSPort' -Quiet)) {
Write-Host "[validate-config] warning: torrc does not specify DNSPort; onion DNS will not work"
}
# optional live DNS smoke queries (requires dig)
if (Get-Command dig -ErrorAction SilentlyContinue) {
Write-Host "[validate-config] performing live DNS query for .onion via CoreDNS"
$res = dig @10.5.0.4 -p 53 facebookcorewwwi.onion +short
if ($LASTEXITCODE -ne 0) {
Assert-Error "[validate-config] onion query failed"
}
Write-Host "[validate-config] performing live DNS query for .i2p via CoreDNS"
$res = dig @10.5.0.4 -p 53 stats.i2p +short
if ($LASTEXITCODE -ne 0) {
Assert-Error "[validate-config] i2p query failed"
}
}
# ensure referenced secrets exist
foreach ($s in @("./secrets/tz.txt", "./secrets/YGGDRASIL_GENERATE_KEYS.txt")) {
if (-not (Test-Path $s)) {
Assert-Error "[validate-config] error: secret file $s is missing"
}
}
# check for :latest tags
if (Select-String -Path docker-compose.yml -Pattern 'image: .*:latest' -Quiet) {
Write-Host "[validate-config] warning: some services use the ':latest' image tag;" `
"pin to a specific version before deploying to production."
}
# warn if no healthchecks defined
if (-not (Select-String -Path docker-compose.yml -Pattern 'healthcheck:' -Quiet)) {
Write-Host "[validate-config] warning: no healthcheck definitions found in docker-compose.yml"
}
Write-Host "[validate-config] warning: some services use the ':latest' image tag;" `
"pin to a specific version before deploying to production."
}
# verify restart policies exist
if (-not (Select-String -Path docker-compose.yml -Pattern 'restart:' -Quiet)) {
Write-Host "[validate-config] warning: some services lack a restart policy."
}
# detect duplicate host ports
$ports = Select-String -Path docker-compose.yml -Pattern ':[0-9]+:' -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { $_.Value.Trim(':') } | Sort-Object
$dups = $ports | Group-Object | Where-Object { $_.Count -gt 1 } | Select-Object -ExpandProperty Name
if ($dups) {
Write-Host "[validate-config] warning: duplicate host port mappings detected: $($dups -join ' ')"
}
# unbound configuration syntax check
if (Get-Command unbound-checkconf -ErrorAction SilentlyContinue) {
Write-Host "[validate-config] checking unbound configuration locally"
unbound-checkconf -c unbound/unbound.conf
} elseif (Get-Command docker -ErrorAction SilentlyContinue) {
Write-Host "[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
} else {
Write-Host "[validate-config] cannot check unbound config (no unbound-checkconf or docker)"
}
# basic 3proxy config sanity
foreach ($cfg in @('3proxy/first-instanse.cfg','3proxy/second-instanse.cfg')) {
if (-not (Test-Path $cfg)) {
Assert-Error "[validate-config] error: missing 3proxy config $cfg"
}
if (-not (Select-String -Path $cfg -Pattern 'socks|proxy' -Quiet)) {
Write-Host "[validate-config] warning: $cfg does not contain socks/proxy directives"
}
}
# simple sanity checks
if (Select-String -Path docker-compose.yml -Pattern 'container_name: darkproxy' -Quiet) {
Write-Host "[validate-config] warning: 'container_name: darkproxy' appears in compose; this may" `
"conflict with network or project name."
}
if (Select-String -Path docker-compose.yml -Pattern 'PIHOLE_DNS_' -Quiet) {
if (Select-String -Path docker-compose.yml -Pattern 'PIHOLE_DNS_:' -Quiet) {
Write-Host "[validate-config] warning: PIHOLE_DNS_ variable ends with underscore;" `
"consider using PIHOLE_DNS_1, PIHOLE_DNS_2 etc."
}
}
Write-Host "[validate-config] all validations passed"
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env bash
# Utility to validate the Compose file and other service configurations.
# Intended to be run locally or in CI; it exits non-zero on any failure.
set -euo pipefail
BASELINE_FILE="docker-compose.lock.yml"
TEMP_FILE=$(mktemp)
# validate docker-compose configuration if Docker is present
if command -v docker >/dev/null 2>&1; then
echo "[validate-config] generating normalized compose manifest"
docker compose config > "$TEMP_FILE"
if [ -f "$BASELINE_FILE" ]; then
echo "[validate-config] comparing against baseline $BASELINE_FILE"
if ! diff -u "$BASELINE_FILE" "$TEMP_FILE"; then
echo "[validate-config] configuration drift detected!"
echo "Please review and, if the change is intentional, update $BASELINE_FILE."
exit 1
fi
echo "[validate-config] docker-compose.yml matches baseline"
else
echo "[validate-config] baseline file not found, creating $BASELINE_FILE"
cp "$TEMP_FILE" "$BASELINE_FILE"
echo "[validate-config] please commit $BASELINE_FILE to the repository"
fi
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
else
echo "[validate-config] cannot check Corefile syntax (no coredns or docker)"
fi
# ensure onion and i2p zones are present in Corefile
for zone in "onion.:53" "i2p.:53" "eth.:53" "bit.:53" "alt.:53" "loki.:53" "zil.:53" "web3.:53" "exit.:53" "onion4.:53" "onion6.:53"; do
if ! grep -q "$zone" PopuraDNS/Corefile; then
echo "[validate-config] error: Corefile missing $zone block" >&2
exit 1
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"
fi
else
echo "[validate-config] warning: i2pd.conf missing [dns] section"
fi
# tor configuration should expose DNSPort for onion resolution
if ! grep -q '^DNSPort' tor_yggdrasil_docker/torrc; then
echo "[validate-config] warning: torrc does not specify DNSPort; onion DNS will not work"
fi
# optional live DNS smoke queries (requires dig)
if command -v dig >/dev/null 2>&1; then
echo "[validate-config] performing live DNS query for .onion via CoreDNS"
if ! dig @10.5.0.4 -p 53 facebookcorewwwi.onion +short >/dev/null; then
echo "[validate-config] onion query failed" >&2
exit 1
fi
echo "[validate-config] performing live DNS query for .i2p via CoreDNS"
if ! dig @10.5.0.4 -p 53 stats.i2p +short >/dev/null; then
echo "[validate-config] i2p query failed" >&2
exit 1
fi
fi
# ensure referenced secrets exist
for s in ./secrets/tz.txt ./secrets/YGGDRASIL_GENERATE_KEYS.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)
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."
fi
# warn if there are no healthchecks at all
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."
fi
# detect duplicate host ports
ports=$(grep -oP ':[0-9]+:' docker-compose.yml | tr -d ':' | sort)
if [ -n "$(echo "$ports" | uniq -d)" ]; then
echo "[validate-config] warning: duplicate host port mappings detected:" $(echo "$ports" | uniq -d)
fi
# unbound configuration syntax check
if 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
else
echo "[validate-config] cannot check unbound config (no unbound-checkconf or docker)"
fi
# very basic 3proxy config sanity
for cfg in 3proxy/first-instanse.cfg 3proxy/second-instanse.cfg; do
if [ ! -f "$cfg" ]; then
echo "[validate-config] error: missing 3proxy config $cfg" >&2
exit 1
fi
if ! grep -qE 'socks|proxy' "$cfg"; then
echo "[validate-config] warning: $cfg does not contain socks/proxy directives"
fi
done
# simple sanity checks
if grep -q "container_name: darkproxy" docker-compose.yml; then
echo "[validate-config] warning: 'container_name: darkproxy' appears in compose;" \
"this may conflict with network or project name."
fi
# ensure Pi-hole DNS environment is correctly formatted
if grep -q "PIHOLE_DNS_" docker-compose.yml | grep -q "PIHOLE_DNS_:"; then
echo "[validate-config] warning: PIHOLE_DNS_ variable ends with underscore;" \
"consider using PIHOLE_DNS_1, PIHOLE_DNS_2 etc."
fi
echo "[validate-config] all validations passed"
Submodule tor_yggdrasil_docker added at 4e14ce6ed6
Executable
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# Most of this is credited to
# https://trac.torproject.org/projects/tor/wiki/doc/TransparentProxy
# With a few minor edits
# to run iptables commands you need to be root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root."
exit 1
fi
### set variables
# destinations you don't want routed through Tor
_non_tor="192.168.1.0/24 192.168.0.0/24"
# get the UID that Tor runs as
_tor_uid=$(docker exec -u tor tor id -u)
# Tor's TransPort
_trans_port="9040"
_dns_port="5353"
### set iptables *nat
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
#iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports $_dns_port
# allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor 127.0.0.0/9 127.128.0.0/10; do
iptables -t nat -A OUTPUT -d $_clearnet -j RETURN
done
# redirect all other output to Tor's TransPort
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $_trans_port
### set iptables *filter
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor 127.0.0.0/8; do
iptables -A OUTPUT -d $_clearnet -j ACCEPT
done
# allow only Tor output
iptables -A OUTPUT -m owner --uid-owner $_tor_uid -j ACCEPT
#iptables -A OUTPUT -j REJECT