π£ VM: CyberIntel (VMID 118)
π£ IP Address: 192.168.5.175
π£ Web UI: cyberintel.kalymoon.com
π£ Last Updated: March 2026
| π£ Property | π£ Value |
|---|---|
| Hostname | CyberIntel |
| LAN IP | 192.168.5.175 |
| OS | Ubuntu 24.04 LTS |
| CPU | 4 cores |
| RAM | 8GB |
| Disk | 120GB (expanded from 59GB) |
| Proxmox Host | jen-server |
| Public Domain | cyberintel.kalymoon.com |
| Reverse Proxy | Nginx Proxy Manager on VM 100 |
| NPM Config | Scheme: http Β· Forward: 192.168.5.175:5050 Β· SSL: Let's Encrypt |
| Flask Port | 5050 |
| Service User | jen |
π£ SSH access: ssh jen@192.168.5.175
| π£ Component | π£ Purpose | π£ Status |
|---|---|---|
| Python 3.12 | Runtime for all scripts | β Active |
| Flask | Web app framework | β Active |
| Playwright + Chromium | Full JS article scraping | β Active |
| SQLite3 | Article + book database | β Active |
| micro | Terminal text editor (replaces nano) | β Active |
| cyberintel.service | Systemd service running Flask on port 5050 | β Running |
| Anthropic API | Claude Sonnet β AI article summaries + daily brief | π΅ Configured |
| π£ File | π£ Purpose |
|---|---|
app.py |
Main Flask web app β news feed, article reader, AI summarize endpoint |
books.py |
Book library blueprint β upload, read, download, user auth, invites |
fetch.py |
RSS aggregator β pulls Google News + 60+ direct feeds, scrapes articles |
brief.py |
Daily intelligence brief generator β calls Claude API, writes HTML |
bulk_import.py |
One-time bulk book importer with PDF metadata extraction |
| π£ Path | π£ Contents |
|---|---|
/opt/cyberintel/ |
Main install directory |
/opt/cyberintel/app.py |
Flask web app |
/opt/cyberintel/books.py |
Book library blueprint |
/opt/cyberintel/fetch.py |
RSS fetch + scrape script |
/opt/cyberintel/brief.py |
Daily brief generator |
/opt/cyberintel/bulk_import.py |
Bulk book importer |
/opt/cyberintel/archive.db |
SQLite database β articles, books, users, invites |
/opt/cyberintel/books/ |
Uploaded book files (PDF, EPUB etc) |
/opt/cyberintel/brief/ |
Generated daily briefs (HTML) |
/opt/cyberintel/brief/archive/ |
Briefs older than 30 days |
/opt/cyberintel/fetch.log |
RSS fetch log |
/opt/cyberintel/.secret_key |
Flask session secret key |
/etc/systemd/system/cyberintel.service |
Systemd service definition |
~/files/ |
Staging area for deploying updated files |
~/book_import/ |
Drop zone for bulk book imports |
# Article counts by category
sqlite3 /opt/cyberintel/archive.db \
"SELECT category, COUNT(*) FROM articles GROUP BY category ORDER BY COUNT(*) DESC;"
# Total articles + full text rate
sqlite3 /opt/cyberintel/archive.db \
"SELECT COUNT(*), SUM(body_ok) FROM articles;"
# Book count
sqlite3 /opt/cyberintel/archive.db "SELECT COUNT(*) FROM books;"
# Edit crontab
crontab -e
# Current entries:
0 */4 * * * /usr/bin/python3 /opt/cyberintel/fetch.py >> /opt/cyberintel/fetch.log 2>&1
0 6 * * * ANTHROPIC_API_KEY=sk-ant-... /usr/bin/python3 /opt/cyberintel/brief.py >> /opt/cyberintel/brief.log 2>&1
# Run fetch manually (watch output live)
python3 /opt/cyberintel/fetch.py
# Watch fetch log
tail -f /opt/cyberintel/fetch.log
# Generate brief manually
ANTHROPIC_API_KEY=sk-ant-... python3 /opt/cyberintel/brief.py
# Check service status
sudo systemctl status cyberintel
All feeds are defined in the DIRECT_FEEDS list in fetch.py. Each entry is a dict with url, category, and source.
# 1. Open fetch.py
micro /opt/cyberintel/fetch.py
# 2. Find DIRECT_FEEDS list and add your feed in this format:
{"url": "https://example.com/feed.rss", "category": "Threat Intelligence", "source": "Example Blog"},
# 3. Save and run a fetch to test it
python3 /opt/cyberintel/fetch.py
π£ Tip: Most sites publish RSS at /feed/, /rss.xml, or /atom.xml. Try appending /feed to any site URL.
Keyword-based queries are in the QUERIES list at the top of fetch.py. Uses standard boolean syntax: OR, AND, "quoted phrases".
π£ Note: The book library (Cyber Reads) requires login. The news feed is public.
Go to https://cyberintel.kalymoon.com/library/admin and sign in with your admin account.
β οΈ Important: Invite links always use https:// β do not strip the protocol before sending.
The admin panel shows all generated invite links with their status (Pending / Used) and who used them.
The daily brief is auto-generated at 06:00 every morning via cron and published to:
https://cyberintel.kalymoon.com/brief/ β archive indexhttps://cyberintel.kalymoon.com/brief/today.html β always the latest briefANTHROPIC_API_KEY=sk-ant-... python3 /opt/cyberintel/brief.py
/opt/cyberintel/brief/brief/archive//etc/systemd/system/cyberintel.servicefetch.py first if neededπ£ Note: The API key is also required for the β¦ Summarize button on individual articles. Summaries are cached in the DB after first generation β no repeat API cost.
# 1. Download updated files from Claude chat to your local machine
# 2. SCP to CyberIntel staging folder
scp fetch.py app.py books.py brief.py jen@192.168.5.175:~/files/
# 3. Copy from staging to install dir
sudo cp ~/files/fetch.py ~/files/app.py ~/files/books.py ~/files/brief.py /opt/cyberintel/
# 4. Restart the service
sudo systemctl restart cyberintel
# 5. Verify it's running
sudo systemctl status cyberintel
# Check the error
sudo journalctl -u cyberintel -n 30 --no-pager
# Common fixes:
# - Missing module: sudo pip3 install flask --break-system-packages
# - Bad service file: sudo systemctl cat cyberintel (check for missing ExecStart)
# - Permission error: sudo chown -R jen:jen /opt/cyberintel/
sudo systemctl daemon-reload
sudo systemctl restart cyberintel
du -sh /opt/cyberintel/
du -sh /opt/cyberintel/books/
du -sh /opt/cyberintel/archive.db
df -h /
π£ Tags: cyberintel β’ flask β’ python β’ rss β’ threat-intel β’ claude-api β’ self-hosted β’ security β’ calibre β’ daily-brief