From 15137c9e699fa74d163fac2bf7fb4716f042169a Mon Sep 17 00:00:00 2001 From: Mustafa Date: Mon, 13 Apr 2026 01:04:09 +0330 Subject: [PATCH] feat: add Docker support for server deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .dockerignore | 50 +++++++++++++++++ .env.example | 40 ++++++++++++++ .gitignore | 1 + Dockerfile | 58 ++++++++++++++++++++ README-FA.md | 119 +++++++++++++++++++++++++++++++++++++++++ README.md | 119 +++++++++++++++++++++++++++++++++++++++++ configs/channels.txt | 12 +++++ configs/x_accounts.txt | 10 +++- docker-compose.yml | 60 +++++++++++++++++++++ 9 files changed, 468 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2ee3597 --- /dev/null +++ b/.dockerignore @@ -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/ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..630f4c4 --- /dev/null +++ b/.env.example @@ -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 diff --git a/.gitignore b/.gitignore index b0fb512..041b5ca 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ session.json # Environment files .env +.env.local todo todo.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4a0f942 --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/README-FA.md b/README-FA.md index f2eabc9..d6d8cfd 100644 --- a/README-FA.md +++ b/README-FA.md @@ -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 / ویندوز diff --git a/README.md b/README.md index d72d099..f2bd4f9 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/configs/channels.txt b/configs/channels.txt index 5bac1d4..7681de7 100644 --- a/configs/channels.txt +++ b/configs/channels.txt @@ -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 diff --git a/configs/x_accounts.txt b/configs/x_accounts.txt index c1f7b44..d5fcdbc 100644 --- a/configs/x_accounts.txt +++ b/configs/x_accounts.txt @@ -2,4 +2,12 @@ # Lines starting with # are comments PahlaviReza RezaVaisi - +IranIntlbrk +indypersian +IDFFarsi +IranIntl +pouriazeraati +CENTCOMFarsi +IsraelPersian +Vahid +euronews_pe diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..478a254 --- /dev/null +++ b/docker-compose.yml @@ -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}