Thefeed
DNS-based feed reader and lite messenger for environments where only DNS queries work. Read Telegram channels and public X accounts, and exchange end-to-end-encrypted messages with other users — all over DNS.
Install / Use
npx skills add sartoopjj/thefeedInstalls into whichever agent you are using.
README
thefeed
DNS-based feed reader and lite messenger for networks where only DNS gets through. Read Telegram channels and public X accounts, and exchange end-to-end-encrypted messages with other users — all over plain DNS.
English · فارسی · 简体中文 · Русский
Contents: Install the app · Run a server · Messenger · How it works · Security · Build from source · Reference · Links
Screenshots
<table align="center"> <tr> <td align="center"><img src="docs/screenshots/mainfeed.jpg" width="170" alt="Main feed"><br><sub>Main feed</sub></td> <td align="center"><img src="docs/screenshots/feed-post.jpg" width="170" alt="Reading a post"><br><sub>Reading a post</sub></td> <td align="center"><img src="docs/screenshots/telemirror.jpg" width="170" alt="Telemirror"><br><sub>Telemirror</sub></td> <td align="center"><img src="docs/screenshots/chat.jpg" width="170" alt="Messenger"><br><sub>Messenger</sub></td> </tr> <tr> <td align="center"><img src="docs/screenshots/chat-list.jpg" width="170" alt="Chats"><br><sub>Chats</sub></td> <td align="center"><img src="docs/screenshots/scanner.jpg" width="170" alt="Resolver scanner"><br><sub>Resolver scanner</sub></td> <td align="center"><img src="docs/screenshots/resolver-bank.jpg" width="170" alt="Resolver bank"><br><sub>Resolver bank</sub></td> <td align="center"><img src="docs/screenshots/settings.jpg" width="170" alt="Settings"><br><sub>Settings</sub></td> </tr> </table>Install the app
For anyone who just wants to read feeds and chat — you don't need a server, just import a config into the client.
Download the client for your platform from the latest release — pick the mirror that's reachable for you: GitHub · GitLab.
| Platform | Notes |
|----------|-------|
| Android (7.0+) | Easiest: Google Play — installs and updates itself. Otherwise the APK. Pick arm64-v8a (phones since ~2017) or armeabi-v7a (older 32-bit only). Installing the wrong ABI installs but won't run. |
| iOS (13+) | Install via TestFlight. App Store build is planned; you can also build from source under ios/ — see Build from source. |
| Windows (10/11) | The .exe is unsigned, so SmartScreen shows "Windows protected your PC" and Defender may quarantine it — a known false positive for DNS-tunneling tools, not malware. Click More info → Run anyway; restore from Defender → Protection history if removed; verify the SHA-256 from the release page if unsure. |
| macOS | Universal .dmg (Intel + Apple Silicon), drag-installs Thefeed.app. Unsigned, so on first launch either right-click → Open, or run xattr -dr com.apple.quarantine /Applications/Thefeed.app. |
| Linux / Termux | thefeed-client binary — run it and open http://127.0.0.1:8080. |
Then open Settings → Configs and import a config (or paste your domain + passphrase). DNS resolvers are managed in the Resolver tab — a shared Bank used by all configs, plus a Scanner to find more.
Public configs to try: @thefeedconfig.
Run a server
For operators who host feeds for others. The server runs outside the censored network, pulls from Telegram / X, and answers encrypted DNS queries. Setup is two steps: (1) DNS records, then (2) install.
1. DNS records
You need one A record and one NS delegation. Example: your server IP is 203.0.113.10 and your domain is example.com.
| # | Type | Name | Value | Purpose |
|---|------|------|-------|---------|
| 1 | A | ns.example.com | 203.0.113.10 | Point a hostname at your server |
| 2 | NS | t.example.com | ns.example.com | Delegate the feed subdomain to your server |
| 3 (optional) | NS | c.example.com | ns.example.com | Delegate a messenger subdomain — only if you enable chat |
Records 1–2 are required for the feed. Record 3 is only needed for the optional messenger, which must use a separate subdomain from the feed (e.g. c.example.com).
2. Install the server
With DNS in place, install with the script or with Docker.
Option A — install script (Linux + systemd)
The one-liner auto-detects a reachable mirror (GitHub first, then GitLab); pass --gitlab to force GitLab.
# GitHub mirror
sudo bash -c "$(curl -Ls https://raw.githubusercontent.com/sartoopjj/thefeed/main/scripts/install.sh)"
# GitLab mirror (use while the GitHub account is unavailable)
sudo bash -c "$(curl -Ls https://gitlab.com/sartoopjj/thefeed/-/raw/main/scripts/install.sh)" -- --gitlab
The script downloads the latest binary, asks for your domain / passphrase / channels / X accounts, asks whether to use Telegram login (recommended: No — public channels work without it), and sets up a systemd service. Re-run it any time to update.
Other actions (pipe the script to sudo bash -s -- <flag>):
| Flag | Action |
|------|--------|
| --version v0.9.2 (or -v) | Install a specific tag (rollback) |
| --pre | Install the newest pre-release (beta / rc) |
| --list | List recent releases |
| --login | Re-run Telegram login |
| --config | Print the import URI (domain, key, sk= server key, bootstrap resolvers) |
| --uninstall | Remove the service |
Option B — Docker
No Go toolchain needed. Base image alpine:3.21 (~23 MB), runs as non-root thefeed (UID 1000).
# 1. Configure — set THEFEED_DOMAIN and THEFEED_KEY (uncomment Telegram vars if you need private channels)
cp .env.example .env && nano .env
# 2. Add your channels
mkdir -p data
cp configs/channels.txt data/
cp configs/x_accounts.txt data/ # optional
# 3. Build and run (listens on :5300/udp inside the container)
docker compose up -d
docker compose logs -f
# 4. Print the client import config (the thefeed:// URI — domain, key, server key sk=,
# resolvers) to hand to your users, just like the script prints at the end:
docker compose run --rm server --print-config --data-dir /data --domain YOUR_DOMAIN --key YOUR_KEY
Then set up the port 53 redirect below. For private channels, do a one-time interactive login first:
docker compose run -it --rm server --login-only --data-dir /data \
--domain YOUR_DOMAIN --key YOUR_KEY \
--api-id YOUR_API_ID --api-hash YOUR_HASH --phone YOUR_PHONE
# then remove --no-telegram from docker-compose.yml, add the Telegram flags, and `docker compose up -d`
Port 53
The server must receive external DNS on UDP 53, but binding :53 directly conflicts with systemd-resolved. So it listens on an unprivileged port (:5300) and you redirect external :53 to it with iptables. Local DNS on the host keeps working — only packets arriving on the external interface are redirected.
# Replace eth0 with your interface (check: ip a)
sudo iptables -I INPUT -p udp --dport 5300 -j ACCEPT
sudo iptables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
sudo ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT
sudo ip6tables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
# Persist across reboots (Debian/Ubuntu)
sudo apt install -y iptables-persistent && sudo netfilter-persistent save
Undo instantly if anything breaks:
sudo iptables -t nat -D PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
sudo iptables -D INPUT -p udp --dport 5300 -j ACCEPT
sudo netfilter-persistent save
Quick sanity checks: ss -ulnp | grep ':53 ' (expect only systemd-resolved on 127.0.0.53), dig +short google.com @127.0.0.53 (local DNS still works), iptables -t nat -L PREROUTING -n | grep 5300 (redirect active).
Managing the service
systemctl status thefeed-server
systemctl restart thefeed-server
journalctl -u thefeed-server -f
sudo vi /opt/thefeed/data/channels.txt # edit channels, then:
sudo systemctl restart thefeed-server
The server also renders a terminal dashboard from its hourly reports (<data-dir>/dns_hourly.jsonl) — serves nothing on the network, just reads the data dir:
thefeed-server --data-dir /srv/thefeed --report # snapshot
thefeed-server --data-dir /srv/thefeed --report --report-refresh 5s # live
It shows total / channel-fetch / metadata / media / chat query counts, per-channel and per-domain aggregates, and chat stats.
Server flags
Key flags (also settable via env vars, e.g. THEFEED_DOMAIN, THEFEED_KEY, THEFEED_ALLOW_MANAGE):
| Flag | Default | Description |
|------|---------|-------------|
| --data-dir | ./data | Data directory (channels, session, cache, config) |
| --domain | | DNS feed domain (required) |
| --key | | Encryption passphrase (required) |
| --extra-domains | | Comma-separated extra feed sub-domains (load spread + resilience) |
| --chat-domains | | Enable the messenger on these sub-domains (separate from feed) |
| --no-telegram | false | Run w
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
blender-python-addon
40.5kBlender Python add-on rules for operators, panels, properties, registration, testing, and API-safe scripting
flutter-development-guidelines-cursorrules-prompt-file
40.5kCursor rules for Flutter development with MVVM architecture, Riverpod state management, Material widgets, and Dart style guidelines.
commit-push-pr
140.7kCommit, push, and open a PR
