- RUN.md: start/stop/inspect/smoke-test commands for the hardened DeerFlow stack on data-nuc, including the docker compose -f overlay invocation and a copy-paste smoke test that verifies allow + block destinations from inside the container. - scripts/deerflow-firewall.sh: status now uses iptables -nvL so the input-interface column is included, and the awk filter shows the header plus all rules matching br-deerflow. The previous version used -nL which omits the interface column entirely, so the grep found nothing even when the rules were correctly installed.
3.7 KiB
Running the hardened DeerFlow
Quick reference for starting, stopping, and inspecting the hardened DeerFlow stack on data-nuc. For the full security rationale see HARDENING.md.
Prerequisites (one-time, already done on data-nuc)
docker+docker composeavailable/etc/nixos/configuration.niximportsscripts/deerflow-firewall.nix(verify:grep deerflow-firewall /etc/nixos/configuration.nix)- After config change:
sudo nixos-rebuild switch systemctl status deerflow-firewallshowsactive (exited).envexists in the repo root with a realOLLAMA_CLOUD_API_KEY(template:.env.example)
Start
cd /home/data/deerflow-factory
docker compose \
-f deer-flow/docker/docker-compose.yaml \
-f docker/docker-compose.override.yaml \
up -d
The override file pins the upstream deer-flow Docker network to a
stable Linux bridge name br-deerflow so the host firewall can
reference it. The firewall rules already in DOCKER-USER will activate
the moment the bridge appears — no manual action needed.
Stop
cd /home/data/deerflow-factory
docker compose \
-f deer-flow/docker/docker-compose.yaml \
-f docker/docker-compose.override.yaml \
down
The firewall rules stay in place but become inert (no traffic
matches -i br-deerflow once the bridge is gone). They re-activate the
next time you bring the stack up.
Inspect
| What | Command |
|---|---|
| Compose status | docker compose -f deer-flow/docker/docker-compose.yaml -f docker/docker-compose.override.yaml ps |
| Container logs | docker compose -f deer-flow/docker/docker-compose.yaml -f docker/docker-compose.override.yaml logs -f <service> |
| Firewall service | systemctl status deerflow-firewall |
| Firewall rules | sudo scripts/deerflow-firewall.sh status |
| Bridge present? | ip link show br-deerflow |
Smoke-test the egress firewall
After the first up, verify the container's egress is correctly
constrained. Replace <svc> with the name of any DeerFlow container
that has curl available (try frontend, langgraph, or provisioner):
docker compose -f deer-flow/docker/docker-compose.yaml \
-f docker/docker-compose.override.yaml \
exec <svc> sh -c '
set -e
echo "[+] Searx (allow):"
curl -s -o /dev/null -w " %{http_code}\n" --max-time 5 http://10.67.67.1:8888/ || echo " fail"
echo "[+] Internet (allow):"
curl -s -o /dev/null -w " %{http_code}\n" --max-time 5 https://api.cloudflare.com/ || echo " fail"
echo "[-] Home LAN gateway (block):"
curl -s -o /dev/null -w " %{http_code}\n" --max-time 5 http://192.168.3.1/ || echo " blocked"
echo "[-] Other Wireguard host (block):"
curl -s -o /dev/null -w " %{http_code}\n" --max-time 5 http://10.67.67.16/ || echo " blocked"
'
Expected:
[+] Searx (allow):
200
[+] Internet (allow):
200 (or 4xx — anything that is not "fail" means egress worked)
[-] Home LAN gateway (block):
blocked (curl exits non-zero with "host prohibited")
[-] Other Wireguard host (block):
blocked
If a "block" line returns an HTTP code instead of "blocked", the
firewall is not constraining that destination — stop the container and
check sudo scripts/deerflow-firewall.sh status.
Reset firewall after changes to the script
If you edit scripts/deerflow-firewall.sh:
sudo systemctl restart deerflow-firewall
sudo scripts/deerflow-firewall.sh status
Disable the egress firewall (not recommended)
sudo systemctl stop deerflow-firewall # rules removed
sudo systemctl disable deerflow-firewall # no auto-start at boot
To remove permanently: delete the imports entry from
/etc/nixos/configuration.nix and sudo nixos-rebuild switch.