Artifact ef6fdf224d0afc1650dd38fe4c0c898f7f61f400b36aafcf1706b74436524de3:
- File README.md — part of check-in [4bdfd11d9f] at 2026-10-30 03:06:19 on branch trunk — Update README.md (user: rpdillon size: 7137)
PiFeed
PiFeed is a single-file microblogging server and RSS aggregator built with Python, Bottle, and SQLite. The entire application (routes, templates, static rendering, database models, and background feed processing) lives in pifeed.py.
Features
- Microblogging and Threading: Markdown-style formatting, threaded replies, emoji reactions, user mentions (
@user), and customizable greeting cards with photo attachments. - Circles: Group and topic feeds where posts can be directed to specific circles or kept on the main timeline.
- Feed Aggregation: Subscribe to external RSS and Atom feeds. Items appear in dedicated feed views or merged into your timeline, complete with embeds for YouTube, XKCD, and asciinema.
- Media and Document Lightbox: Attach images, PDFs, and HTML archives. Media files open in a responsive lightbox, and uploaded HTML archives are served in an isolated iframe sandbox.
- Podcasts: Enclosure detection, inline audio streaming, and local episode downloading.
- Full RSS Compatibility: Every timeline (public, user profile, circle, and private home feed) generates standard Atom XML feeds for RSS readers.
- Flexible Access: Admin-controlled user creation and single-token invite links with conflict detection and one-time password generation.
- No Build Pipelines: Vanilla JavaScript, pure CSS toggles, and zero frontend toolchains.
Architecture and Runtime Modes
PiFeed stores everything in a local SQLite database (pifeed.db) and local directories for file uploads and static cache.
It supports two operational modes:
- Standalone Server: Run directly from the terminal or managed by systemd/supervisor. In server mode, PiFeed uses a multithreaded WSGI server and starts an internal background thread that refreshes external feeds every 15 minutes.
- CGI Application: Run behind Apache, lighttpd, or BusyBox httpd. When
GATEWAY_INTERFACEis present in the environment, PiFeed processes the incoming request and exits immediately. Feed fetches in CGI mode are scheduled via cron.
Building
PiFeed can run straight from pifeed.py with dependencies installed, or packaged into a deployment artifact using ./deps.sh.
Prerequisites: Python 3 and uv.
Run ./deps.sh to run tests and compile artifacts:
./deps.sh # Runs audit, check, test, zipapp, and nuitka
Option 1: Python Zipapp (pifeed.pyz)
A standalone zipapp bundles application code and locked dependencies into an executable zip archive that runs on any system with a compatible Python 3 interpreter:
./deps.sh zipapp
This generates pifeed.pyz.
Option 2: Native Compiled Binary (pifeed.bin)
Using Nuitka, PiFeed compiles into a self-contained ELF executable with an embedded Python interpreter. This eliminates interpreter startup overhead, making it well-suited for CGI environments:
./deps.sh nuitka
This generates pifeed.bin. Compile on the same OS family and architecture as your deployment server.
Deployment
Standalone Server
To run directly on port 3141:
# Using source
python3 pifeed.py
# Using the zipapp
python3 pifeed.pyz
# Using the compiled binary
./pifeed.bin
When started for the first time, PiFeed creates pifeed.db, initializes tables, generates an admin user, and outputs a one-time password to standard error:
*** BOOTSTRAP: Admin user created. Username: 'admin' | Password: '<generated-password>' ***
To run behind a reverse proxy like Nginx or Caddy, proxy traffic to http://127.0.0.1:3141.
CGI Application (Apache)
CGI mode hosts PiFeed on shared hosting or Apache without running a persistent daemon process.
Installation
Copy either pifeed.pyz or pifeed.bin to your web root, rename it to index.cgi, and grant execution permissions:
cp pifeed.bin /var/www/html/index.cgi
chmod +x /var/www/html/index.cgi
Web Server Configuration (.htaccess)
Place an .htaccess file in your document root to route requests into index.cgi, protect the database file, and optionally serve static cache files directly:
Options +ExecCGI -Indexes
AddHandler cgi-script .cgi
DirectoryIndex index.cgi
RewriteEngine On
RewriteBase /
# Static cache shortcuts (serve public feeds directly from disk if cached)
RewriteCond %{HTTP_COOKIE} !session= [NC]
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{DOCUMENT_ROOT}/cache/public.html -f
RewriteRule ^public/?$ cache/public.html [L]
RewriteCond %{HTTP_COOKIE} !session= [NC]
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{DOCUMENT_ROOT}/cache/public.xml -f
RewriteRule ^public\.xml$ cache/public.xml [L]
# Route all non-file requests into index.cgi
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.cgi/$1 [L,QSA]
# Block direct web downloads of the SQLite database
<Files "pifeed.db">
Require all denied
</Files>
<Files "index.cgi">
Require all granted
</Files>
Scheduled Feed Polling (Cron)
Because CGI processes terminate after responding, background threads do not run. Schedule external feed fetching and cache culling every 15 minutes using cron:
*/15 * * * * /var/www/html/index.cgi --task-fetch >/dev/null 2>&1
Subdirectory Hosting
When served from a subdirectory (such as /cgi-bin/pifeed.cgi), PiFeed detects SCRIPT_NAME and rewrites links and redirects automatically. To override detection for reverse-proxy setups, set the PIFEED_BASE_PATH environment variable:
export PIFEED_BASE_PATH=/my-prefix
Configuration
PiFeed is configured through environment variables and the web admin UI:
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
PORT |
3141 |
Server listen port |
PIFEED_DB |
./pifeed.db |
SQLite database file location |
PIFEED_UPLOADS |
./uploads |
Directory for image, PDF, and HTML uploads |
PIFEED_CACHE |
./cache |
Directory for generated static feed caches |
PIFEED_PODCASTS |
./podcasts |
Directory for downloaded podcast episodes |
PIFEED_BASE_PATH |
(detected) | URL prefix override when running behind a prefix proxy |
PIFEED_ALLOW_LOCAL_REQS |
0 |
Set to 1 to allow RSS fetching from private or loopback IP ranges |
Admin Interface
Log in as admin and visit /admin to configure instance settings:
- Toggle public timelines, circles, and RSS aggregation.
- Adjust session durations and feed retention culling rules.
- Set instance-wide themes and visitor Message of the Day (MOTD).
- Generate, copy, regenerate, or delete private registration invite links.
- Reset user passwords and rotate RSS security tokens.
If you ever lose the admin password, run:
python3 pifeed.py --reset-admin
This outputs a new temporary password directly to the console.
Development and Testing
Run unit and integration tests using pytest:
pytest test_pifeed.py pifeed_tests.py
Tests run against isolated temporary SQLite databases and mock upload directories without modifying your production data.