feat: add Docker support for server deployment

Add Docker deployment option for the server with multi-stage build.

Changes:
- Dockerfile: multi-stage build (golang:1.26-alpine → alpine:3.21, ~23MB)
- docker-compose.yml: server service on port 5300/udp with iptables redirect
- .env.example: documented environment variables template
- .dockerignore: optimized build context
- README.md & README-FA.md: Docker deployment guide, port 53 safety checks,
  and troubleshooting instructions (both EN and FA)
- configs: added more Telegram channels and X accounts

The container listens on port 5300 to avoid conflict with systemd-resolved.
External DNS traffic (port 53) is redirected via iptables PREROUTING.
No changes to existing Go source code.
This commit is contained in:
Mustafa
2026-04-13 01:04:09 +03:30
parent 90254f9d93
commit 15137c9e69
9 changed files with 468 additions and 1 deletions
+50
View File
@@ -0,0 +1,50 @@
# Build outputs
build/
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Git
.git/
.gitignore
# Data (user-specific, mounted as volume)
data/
thefeeddata/
.thefeed/
# Environment secrets
.env
# Session data
session.json
# Agent config
.agent/
# Temporary
tmp/
todo
todo.md
# Documentation (not needed in image)
README.md
README-FA.md
LICENSE
docs/
# Android (not relevant for server)
android/
# Tests (not needed in production image)
test/
# Scripts (not needed in image)
scripts/
+40
View File
@@ -0,0 +1,40 @@
# ============================================================
# thefeed-server — Docker Environment Variables
# ============================================================
# Copy this file to .env and fill in your values:
# cp .env.example .env
# ============================================================
# ----- Required -----
# Your DNS domain (e.g., t.example.com)
THEFEED_DOMAIN=t.example.com
# Encryption passphrase (shared between server and client)
THEFEED_KEY=your-secret-passphrase
# ----- Telegram Mode -----
# Default: --no-telegram (public channels only, no login needed)
# To use Telegram API, uncomment these AND remove --no-telegram from compose:
#TELEGRAM_API_ID=12345
#TELEGRAM_API_HASH=your-api-hash
#TELEGRAM_PHONE=+1234567890
#TELEGRAM_PASSWORD=your-2fa-password
# ----- Optional Settings -----
# Max messages per channel (default: 15)
#THEFEED_MSG_LIMIT=15
# Allow remote channel management via DNS (default: disabled)
#THEFEED_ALLOW_MANAGE=0
# Nitter RSS instances for X/Twitter (comma-separated)
#THEFEED_X_RSS_INSTANCES=http://nitter.net,https://nitter.net
# Max random padding bytes in DNS responses (anti-DPI, default: 32)
#THEFEED_PADDING=32
# Log every decoded DNS query (default: disabled)
#THEFEED_DEBUG=0
+1
View File
@@ -23,6 +23,7 @@ session.json
# Environment files
.env
.env.local
todo
todo.md
+58
View File
@@ -0,0 +1,58 @@
# ============================================================
# thefeed-server — Multi-stage Docker build
# ============================================================
# Build: docker compose build
# Run: docker compose up -d
# Login: docker compose run -it --rm server --login-only \
# --data-dir /data --domain $THEFEED_DOMAIN \
# --key $THEFEED_KEY --api-id $TELEGRAM_API_ID \
# --api-hash $TELEGRAM_API_HASH --phone $TELEGRAM_PHONE
# ============================================================
# ---- Stage 1: Build ----
FROM golang:1.26-alpine AS builder
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Build-time version info (overridable via --build-arg)
ARG VERSION=docker
ARG COMMIT=unknown
ARG DATE=unknown
RUN CGO_ENABLED=0 go build -trimpath \
-ldflags="-s -w \
-X github.com/sartoopjj/thefeed/internal/version.Version=${VERSION} \
-X github.com/sartoopjj/thefeed/internal/version.Commit=${COMMIT} \
-X github.com/sartoopjj/thefeed/internal/version.Date=${DATE}" \
-o /thefeed-server ./cmd/server
# ---- Stage 2: Runtime ----
FROM alpine:3.21
# Copy ca-certificates and tzdata from builder (avoids second apk fetch
# which can fail on restricted networks).
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# Non-root user for security
RUN adduser -D -u 1000 -h /data thefeed
COPY --from=builder /thefeed-server /usr/local/bin/thefeed-server
# Data directory: channels.txt, x_accounts.txt, session.json, cache
VOLUME /data
# DNS listen port (mapped to host:53 via docker-compose)
EXPOSE 5300/udp
USER thefeed
WORKDIR /data
ENTRYPOINT ["thefeed-server"]
CMD ["--data-dir", "/data", "--listen", ":5300"]
+119
View File
@@ -107,6 +107,125 @@ sudo bash install.sh --login
sudo bash install.sh --uninstall
```
## 🐳 نصب با Docker (سرور)
اجرای سرور با Docker — بدون نیاز به نصب Go.
### شروع سریع (کانال‌های عمومی، بدون لاگین تلگرام)
```bash
# ۱. تنظیم محیط
cp .env.example .env
nano .env # مقادیر THEFEED_DOMAIN و THEFEED_KEY را وارد کنید
# ۲. آماده‌سازی دایرکتوری داده
mkdir -p data
cp configs/channels.txt data/
cp configs/x_accounts.txt data/ # اختیاری
# ۳. ساخت و اجرا
docker compose up -d
# ۴. هدایت ترافیک DNS خارجی به کانتینر
# نام اینترفیس شبکه خود را با ip a پیدا کنید و eth0 را جایگزین کنید
sudo iptables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
sudo iptables -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
sudo ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT
# ماندگار کردن قوانین iptables بعد از ریبوت
sudo apt install -y iptables-persistent
sudo netfilter-persistent save
# ۵. مشاهده لاگ‌ها
docker compose logs -f
```
> **توجه:** کانتینر روی پورت 5300 listen می‌کند (نه 53) تا با `systemd-resolved` تداخل نداشته باشد.
> قانون `iptables PREROUTING` فقط ترافیک DNS **خارجی** (پورت 53) را به کانتینر هدایت می‌کند
> و DNS محلی سرور بدون مشکل کار می‌کند.
### با تلگرام (لاگین یکباره)
```bash
# ۱. تنظیم محیط (متغیرهای تلگرام را در .env از حالت کامنت خارج کنید)
cp .env.example .env
nano .env
# ۲. لاگین یکباره (تعاملی — کد تأیید را وارد کنید)
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
# ۳. در docker-compose.yml فلگ --no-telegram را حذف و فلگ‌های تلگرام را اضافه کنید
# ۴. اجرای سرور
docker compose up -d
# ۵. تنظیم iptables redirect (مشابه قدم ۴ در شروع سریع)
```
### جزئیات Docker
| مورد | مقدار |
|------|-------|
| ایمیج پایه | `alpine:3.21` (حدود ۲۳ مگابایت) |
| ساخت | دو مرحله‌ای (`golang:1.26-alpine``alpine`) |
| کاربر | `thefeed` (UID 1000، غیر root) |
| پورت کانتینر | `:5300/udp` (هاست `:5300/udp` + iptables redirect از `:53`) |
| داده | ولوم `./data` (کانال‌ها، session، کش) |
| تنظیمات | فایل `.env` (در git ذخیره نمی‌شود) |
```bash
# ساخت مجدد بعد از تغییرات کد
docker compose build
# توقف
docker compose down
```
### ایمنی پورت ۵۳ و سرویس‌ها
کانتینر روی پورت **5300** (نه 53) listen می‌کند تا با `systemd-resolved` یا سرویس‌های DNS دیگر سرور تداخل نداشته باشد. ترافیک DNS خارجی توسط `iptables PREROUTING` هدایت می‌شود که **فقط** بسته‌های ورودی از اینترفیس شبکه خارجی را تحت تأثیر قرار می‌دهد — DNS محلی سرور **دست‌نخورده** باقی می‌ماند.
**قبل از راه‌اندازی — بررسی پورت ۵۳:**
```bash
# چه سرویسی از پورت 53 استفاده می‌کند؟
ss -ulnp | grep ':53 '
# نتیجه مورد انتظار: فقط systemd-resolved روی 127.0.0.53 (بی‌خطر)
# UNCONN 127.0.0.53%lo:53 users:(("systemd-resolve",...))
```
**بعد از راه‌اندازی — بررسی سلامت سرویس‌ها:**
```bash
# ۱. DNS محلی سرور هنوز کار می‌کند
dig +short google.com @127.0.0.53
# ۲. کانتینر thefeed در حال اجراست
docker ps --filter name=thefeed
# ۳. کانال‌ها در حال دریافت هستند
docker logs thefeed-server --tail 5
# ۴. قانون iptables فعال است
iptables -t nat -L PREROUTING -n | grep 5300
# ۵. بقیه کانتینرها سالم هستند
docker ps --format 'table {{.Names}}\t{{.Status}}' | head -10
```
**اگر مشکلی پیش آمد — حذف فوری redirect:**
```bash
# حذف قانون iptables (بازگشت به حالت اولیه)
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
```
## 🖥️ نصب کلاینت
### لینوکس / macOS / ویندوز
+119
View File
@@ -80,6 +80,125 @@ sudo bash -c "$(curl -Ls https://raw.githubusercontent.com/sartoopjj/thefeed/mai
Re-login: `curl -Ls https://raw.githubusercontent.com/sartoopjj/thefeed/main/scripts/install.sh | sudo bash -s -- --login`
Uninstall: `curl -Ls https://raw.githubusercontent.com/sartoopjj/thefeed/main/scripts/install.sh | sudo bash -s -- --uninstall`
## Docker Deployment (Server)
Run the server with Docker — no Go toolchain needed.
### Quick Start (public channels, no Telegram login)
```bash
# 1. Configure environment
cp .env.example .env
nano .env # set THEFEED_DOMAIN and THEFEED_KEY
# 2. Prepare data directory with your channels
mkdir -p data
cp configs/channels.txt data/
cp configs/x_accounts.txt data/ # optional
# 3. Build and run
docker compose up -d
# 4. Redirect external DNS traffic to the container
# Replace eth0 with your network interface (check with: ip a)
sudo iptables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
sudo iptables -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
sudo ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT
# Make iptables rules persistent across reboots
sudo apt install -y iptables-persistent
sudo netfilter-persistent save
# 5. View logs
docker compose logs -f
```
> **Note:** The container listens on port 5300 (not 53) to avoid conflict with `systemd-resolved`.
> The `iptables PREROUTING` rule redirects only **external** DNS traffic (port 53) to the container,
> while local DNS resolution on the server continues to work normally.
### With Telegram (one-time interactive login)
```bash
# 1. Configure environment (uncomment Telegram vars in .env)
cp .env.example .env
nano .env
# 2. One-time login (interactive — enter auth code when prompted)
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
# 3. Edit docker-compose.yml: remove --no-telegram and add Telegram flags
# 4. Start the server
docker compose up -d
# 5. Set up iptables redirect (same as Quick Start step 4)
```
### Docker Details
| Item | Value |
|------|-------|
| Base image | `alpine:3.21` (~23 MB total) |
| Build | Multi-stage (`golang:1.26-alpine``alpine`) |
| User | `thefeed` (UID 1000, non-root) |
| Container port | `:5300/udp` (host `:5300/udp` + iptables redirect from `:53`) |
| Data | `./data` volume (channels, session, cache) |
| Config | `.env` file (gitignored) |
```bash
# Rebuild after code changes
docker compose build
# Stop
docker compose down
```
### Port 53 & Service Safety
The container listens on port **5300** (not 53) to avoid conflicts with `systemd-resolved` or other DNS services on the host. External DNS traffic is redirected via `iptables PREROUTING` which only affects packets arriving on the external network interface — local DNS resolution is **not** affected.
**Before setup — check what uses port 53:**
```bash
# Check if port 53 is in use
ss -ulnp | grep ':53 '
# Expected: systemd-resolved on 127.0.0.53 only (safe)
# UNCONN 127.0.0.53%lo:53 users:(("systemd-resolve",...))
```
**After setup — verify nothing is broken:**
```bash
# 1. Local DNS still works (server can resolve domains)
dig +short google.com @127.0.0.53
# 2. thefeed container is running
docker ps --filter name=thefeed
# 3. thefeed is fetching channels
docker logs thefeed-server --tail 5
# 4. iptables rule is active
iptables -t nat -L PREROUTING -n | grep 5300
# 5. Other containers are healthy
docker ps --format 'table {{.Names}}\t{{.Status}}' | head -10
```
**If something goes wrong — remove the redirect instantly:**
```bash
# Remove the iptables rule (restores original behavior)
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
```
## Manual Setup
### Prerequisites
+12
View File
@@ -1,4 +1,16 @@
# Telegram channel usernames (one per line, with or without @)
# Channel numbers are assigned in order: first = channel 1, second = channel 2, etc.
# Lines starting with # are comments
@networkt
@thefeedconfig
@VahidOnline
@ThMahiar
@Media_HB
@rastadco
@Indypersian
@bbcpersian
@radiofarda
@IraneAzad_News
@farsivoa
@IranintlTV
@jangaavaran1390
+9 -1
View File
@@ -2,4 +2,12 @@
# Lines starting with # are comments
PahlaviReza
RezaVaisi
IranIntlbrk
indypersian
IDFFarsi
IranIntl
pouriazeraati
CENTCOMFarsi
IsraelPersian
Vahid
euronews_pe
+60
View File
@@ -0,0 +1,60 @@
# ============================================================
# thefeed-server — Docker Compose
# ============================================================
#
# Quick start (public channels, no Telegram login):
# 1. cp .env.example .env (edit with your domain & key)
# 2. mkdir -p data && cp configs/channels.txt data/
# 3. docker compose up -d
# 4. Set up iptables to redirect external port 53 to 5300:
# sudo iptables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300
# sudo iptables -I INPUT -p udp --dport 5300 -j ACCEPT
# (replace eth0 with your network interface — check with: ip a)
#
# With Telegram (one-time login first):
# 1. cp .env.example .env (uncomment Telegram vars)
# 2. docker compose run -it --rm server \
# --login-only --data-dir /data \
# --domain ${THEFEED_DOMAIN} --key ${THEFEED_KEY} \
# --api-id ${TELEGRAM_API_ID} --api-hash ${TELEGRAM_API_HASH} \
# --phone ${TELEGRAM_PHONE}
# 3. Remove --no-telegram from the command below
# 4. docker compose up -d
#
# Logs: docker compose logs -f
# Stop: docker compose down
# ============================================================
services:
server:
build:
context: .
args:
VERSION: ${VERSION:-docker}
COMMIT: ${COMMIT:-unknown}
DATE: ${DATE:-unknown}
container_name: thefeed-server
restart: unless-stopped
ports:
- "5300:5300/udp"
volumes:
- ./data:/data
env_file:
- .env
command: >-
--data-dir /data
--listen :5300
--domain ${THEFEED_DOMAIN}
--key ${THEFEED_KEY}
--no-telegram
# To enable Telegram mode:
# 1. Run login-only first (see instructions above)
# 2. Replace the command above with:
# command: >-
# --data-dir /data
# --listen :5300
# --domain ${THEFEED_DOMAIN}
# --key ${THEFEED_KEY}
# --api-id ${TELEGRAM_API_ID}
# --api-hash ${TELEGRAM_API_HASH}
# --phone ${TELEGRAM_PHONE}