How to Self-Host Wallabag: Read-Later App (Pocket Alternative) 2026
TL;DR
Wallabag (MIT, ~10K GitHub stars, PHP/Symfony) is the open source Pocket replacement. Save articles from the web for offline reading — browser extensions, mobile apps (iOS/Android), and Kindle delivery. It fetches full article text, stores it on your server, lets you highlight and annotate, and syncs read state across all devices. Pocket Premium costs $44.99/year. Wallabag is free to self-host. Unlike Shiori (bookmark manager), Wallabag is focused purely on read-later with highlights, annotations, and reading progress.
Key Takeaways
- Wallabag: MIT, ~10K stars, PHP — read-later tool, offline article storage with full text
- Highlights and annotations: Select text to highlight in yellow, add personal notes
- Kindle delivery: Send saved articles to your Kindle e-reader
- Mobile apps: Official iOS and Android apps with offline sync
- Browser extensions: Chrome, Firefox, Edge, Opera — save with one click
- Pocket/Instapaper import: Import your reading list from Pocket, Instapaper, or Pinboard
Wallabag vs Pocket vs Shiori
| Feature | Wallabag | Shiori | |
|---|---|---|---|
| License | MIT | Proprietary | MIT |
| Cost | Free (hosting) | Free / $44.99/yr | Free |
| Full-text fetch | Yes | Yes | Yes |
| Highlights | Yes | No (free), Yes (Premium) | No |
| Annotations | Yes | No | No |
| Kindle delivery | Yes | Yes (Premium) | No |
| Tags | Yes | Yes | Yes |
| Archive / Screenshot | No | No | No |
| Reading time estimate | Yes | Yes | No |
| iOS app | Yes (official) | Yes | Via browser |
| Android app | Yes (official) | Yes | Via browser |
| RSS output | Yes | Yes | No |
Part 1: Docker Setup
# docker-compose.yml
services:
wallabag:
image: wallabag/wallabag:latest
container_name: wallabag
restart: unless-stopped
ports:
- "8080:80"
depends_on:
- wallabag_db
- wallabag_redis
volumes:
- wallabag_data:/var/www/wallabag/data
- wallabag_images:/var/www/wallabag/web/assets/images
environment:
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
SYMFONY__ENV__DATABASE_DRIVER: pdo_mysql
SYMFONY__ENV__DATABASE_HOST: wallabag_db
SYMFONY__ENV__DATABASE_PORT: 3306
SYMFONY__ENV__DATABASE_NAME: wallabag
SYMFONY__ENV__DATABASE_USER: wallabag
SYMFONY__ENV__DATABASE_PASSWORD: "${MYSQL_PASSWORD}"
SYMFONY__ENV__MAILER_DSN: "smtp://smtp.yourdomain.com:587?username=noreply@yourdomain.com&password=${SMTP_PASSWORD}"
SYMFONY__ENV__FROM_EMAIL: "noreply@yourdomain.com"
SYMFONY__ENV__DOMAIN_NAME: "https://read.yourdomain.com"
SYMFONY__ENV__SERVER_NAME: "Wallabag"
SYMFONY__ENV__REDIS_HOST: wallabag_redis
SYMFONY__ENV__TWOFACTOR_AUTH: "false"
POPULATE_DATABASE: "true" # Set to false after first run
wallabag_db:
image: mariadb:11
restart: unless-stopped
volumes:
- wallabag_db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
MYSQL_DATABASE: wallabag
MYSQL_USER: wallabag
MYSQL_PASSWORD: "${MYSQL_PASSWORD}"
wallabag_redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
wallabag_data:
wallabag_images:
wallabag_db_data:
# .env
MYSQL_ROOT_PASSWORD=your-root-password
MYSQL_PASSWORD=your-db-password
SMTP_PASSWORD=your-smtp-password
docker compose up -d
Visit http://your-server:8080 — default credentials: wallabag / wallabag. Change immediately.
Part 2: HTTPS with Caddy
read.yourdomain.com {
reverse_proxy localhost:8080
}
Part 3: Initial Setup
- Log in with
wallabag/wallabag - Top-right menu → Config → Settings
- Change your password
- Set your language and timezone
- After first run, set
POPULATE_DATABASE: "false"in docker-compose.yml to prevent re-seeding
Create Additional Users
- Admin panel → Users → Create a user
- Set username, email, password
Or via CLI:
docker exec wallabag php bin/console wallabag:user:create \
--username bob --password secret --email bob@yourdomain.com
Part 4: Browser Extensions
Chrome/Chromium: Install from Chrome Web Store
Firefox: Install from Firefox Add-ons
Configure the extension:
- Wallabag URL:
https://read.yourdomain.com - Username + password
- Click the extension icon on any article page → saves immediately
Part 5: Mobile Apps
iOS App
- Install Wallabag 2 iOS from App Store
- Server:
https://read.yourdomain.com - Username + password
- App downloads all articles for offline reading
Android App
- Install Wallabag 2 from Play Store (or F-Droid)
- Same server URL and credentials
- Articles sync for offline reading
iOS/Android Share Sheet
Once the app is installed:
- In Safari/Chrome → Share → Wallabag
- Article is saved instantly
Part 6: Kindle Delivery
Send your reading list to Kindle for reading on e-ink:
- Config → Kindle → enter your
@kindle.comemail address - Add
noreply@yourdomain.comto your approved Kindle senders (in Amazon settings) - On any article: Actions → Send to Kindle
Wallabag converts the article to a clean Kindle-friendly format and emails it.
Part 7: Highlights and Annotations
Select any text in an article → Highlight or Annotate:
- Highlights: Mark important text in yellow
- Annotations: Add your own notes attached to a text selection
View all your annotations: Annotations in the sidebar.
Export annotations:
# Via API:
curl "https://read.yourdomain.com/api/annotations.json?page=1" \
-H "Authorization: Bearer YOUR_TOKEN"
Part 8: Import from Pocket / Instapaper
From Pocket
- Pocket: Settings → Export → Request export → download
pocket.html - Wallabag: Import → Pocket → upload the HTML file
From Instapaper
- Instapaper: Settings → Export CSV → download CSV
- Wallabag: Import → Instapaper → upload CSV
From Pinboard
- Pinboard: Settings → Backup → JSON
- Wallabag: Import → Pinboard → upload JSON
Part 9: REST API
# Get OAuth token:
TOKEN=$(curl -s -X POST https://read.yourdomain.com/oauth/v2/token \
-d 'grant_type=password&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&username=wallabag&password=wallabag' \
| jq -r .access_token)
# Create OAuth client first:
docker exec wallabag php bin/console wallabag:client:create --name "myapp"
# Save an article:
curl -X POST https://read.yourdomain.com/api/entries.json \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/article","tags":"tech,readlater"}'
# List unread articles:
curl "https://read.yourdomain.com/api/entries.json?archive=0&page=1&perPage=10" \
-H "Authorization: Bearer $TOKEN" | jq '._embedded.items[].title'
# Mark as read:
curl -X PATCH "https://read.yourdomain.com/api/entries/42.json" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"archive":1}'
Part 10: RSS Feeds
Every tag and category in Wallabag has an RSS feed — subscribe in FreshRSS or any reader:
# All unread articles as RSS:
https://read.yourdomain.com/feed/alice/TOKEN/unread
# Tagged "tech":
https://read.yourdomain.com/feed/alice/TOKEN/tags/tech
# Get your RSS token:
Config → RSS → Generate token
Maintenance
# Update Wallabag:
docker compose pull
docker compose up -d
# Run migrations after update:
docker exec wallabag php bin/console doctrine:migrations:migrate --no-interaction
# Backup database:
docker exec wallabag_db mysqldump -u wallabag -p"${MYSQL_PASSWORD}" wallabag \
| gzip > wallabag-db-$(date +%Y%m%d).sql.gz
# Backup images:
tar -czf wallabag-images-$(date +%Y%m%d).tar.gz \
$(docker volume inspect wallabag_wallabag_images --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f wallabag
See all open source read-later and bookmark tools at OSSAlt.com/categories/productivity.