Pocket announced its shutdown in 2025. Instapaper still exists but is third-handed and feels frozen. Reader-by-Readwise is good but it’s a $10/month subscription. The self-hosted answer is Wallabag — PHP+MySQL, runs on a $5 VPS, has clean iOS / Android apps, exports OPML and JSON. Once it’s set up, you don’t think about it again for years.
This is the install I run, the iOS share-sheet flow that actually works (the official app’s is mediocre), and the catches that will trip you up.
Why Wallabag and not the others
- Wallabag: PHP. MariaDB / Postgres / SQLite for the database. Web UI is functional, mobile apps exist for iOS and Android. The article-extraction quality (using Readability + a curated rule set per domain) is genuinely close to Pocket’s. Default install ~250 MB RAM.
- Shiori: Go binary, lighter. Bookmark-focused rather than read-later-focused; saves articles but the reading view is less polished. Good if you mostly want a bookmark archive.
- Omnivore: shut down in 2024.
- Karakeep / Hoarder: newer, slick, but younger codebase — I’d pick this if I were starting today and willing to bet on it. For “stable for years,” Wallabag still wins.
Install on a $5 VPS
Hetzner CX11 / DO basic / Vultr cheap-tier all work. Docker is the path of least resistance.
# /opt/wallabag/docker-compose.yml
services:
wallabag:
image: wallabag/wallabag:latest
environment:
- SYMFONY__ENV__DATABASE_DRIVER=pdo_mysql
- SYMFONY__ENV__DATABASE_HOST=db
- SYMFONY__ENV__DATABASE_NAME=wallabag
- SYMFONY__ENV__DATABASE_USER=wallabag
- SYMFONY__ENV__DATABASE_PASSWORD=change-me-strong
- SYMFONY__ENV__DOMAIN_NAME=https://wallabag.example.com
- SYMFONY__ENV__MAILER_DSN=null://null
ports:
- "127.0.0.1:8080:80"
volumes:
- ./images:/var/www/wallabag/web/assets/images
depends_on:
- db
db:
image: mariadb:10
environment:
- MYSQL_ROOT_PASSWORD=also-change-me
- MYSQL_DATABASE=wallabag
- MYSQL_USER=wallabag
- MYSQL_PASSWORD=change-me-strong
volumes:
- ./mariadb:/var/lib/mysqlBring it up, then put a real reverse proxy with TLS in front. Caddy does both halves in one config:
# /etc/caddy/Caddyfile
wallabag.example.com {
reverse_proxy 127.0.0.1:8080
}Visit https://wallabag.example.com. Default login: wallabag / wallabag. Change this immediately from Settings → Users → Edit. Then create a real account, log in as that, and disable the default wallabag user.
The iOS share-sheet flow that works
Wallabag’s official iOS app exists and you can install it. But the share-sheet save in the official app has been quirky for years — it sometimes hangs, sometimes silently fails, sometimes saves but doesn’t appear until you force-pull-to-refresh. Don’t use it for the save flow. The setup that’s reliable:
- Get an API client_id and client_secret from Wallabag. Settings → API clients management → Create a new client. Note the values.
- Build a one-action iOS Shortcut that POSTs the URL to
/api/entries.jsonwith bearer-token auth. The whole shortcut is six actions:
1. Receive URLs from Share Sheet
2. Get Contents of URL → POST to https://wallabag.example.com/oauth/v2/token
Body (Form):
grant_type: password
client_id: <your client_id>
client_secret: <your client_secret>
username: you
password: your password
3. Get Dictionary Value "access_token" from response
4. Get Contents of URL → POST to https://wallabag.example.com/api/entries.json
Headers:
Authorization: Bearer <access_token from step 3>
Body (Form):
url: <the URL from step 1>
5. Show Notification "Saved to Wallabag"Now from any iOS app: share button → Save to Wallabag (your custom shortcut). It runs in <2 seconds, shows a notification, and you go back to whatever you were doing. The Wallabag app on iOS becomes pure-reading; saving is via the Shortcut.
The two reading apps worth using
- Reader (the iOS official Wallabag app). Free. Functional. Use it just for reading; saves are unreliable as noted.
- FrenchPress (third-party). $5 one-time. Better typography, swipe-actions, dark theme that doesn’t break on weird article CSS. The reading experience is markedly nicer than the official app.
The catches I learned the hard way
- Disable the default
wallabaguser immediately. Default-credential scanners hit Wallabag instances within hours of going live. Don’t get popped on day one. - Set
MAILER_DSN=null://nullas above unless you actually want password-reset emails. Otherwise Wallabag will try to talk to a SMTP server that doesn’t exist and timeouts will slow down account flows. - Article extraction fails on a small handful of sites with paywalls or aggressive JS rendering — NYTimes, Bloomberg, FT, Substack-with-paywall. Wallabag falls back to a partial save (URL + page title only). The fix per-site is in Settings → Internal settings → Site config; for paywall sites you can paste a YAML-style extraction rule. Or just skip those.
- Backups: dump the MariaDB nightly with
docker exec wallabag-db mysqldump -u root -p$PASS wallabag > backup.sql, plus rsync theimages/directory to your NAS. Restoring from these is well-documented and works. - Don’t expose the API key in the Shortcut if you ever AirDrop the Shortcut to someone else — the iCloud-synced Shortcut will include your password. Use a long random string for the password and don’t share the Shortcut.
The end-state
A small VPS that quietly receives URLs from your iPhone, fetches the article, strips the ads, stores the cleaned text. A reading app that pulls from it for offline-friendly long-form reading on the train or a plane. JSON export at /api/export if you ever want to leave. And no monthly bill arriving for the privilege of saving an article you wanted to read later.
Photo: Coffee mug and smartphone in hand by Mart Production on Pexels.
