How to Install Wallabag (A Self-Hosted Read-It-Later That Keeps the Article)

Linkding (tutorial 113) saves the link. Wallabag saves the article: it fetches the page, strips the adverts and navigation, and stores the readable text and images on your server, so it's there offline, after the site paywalls it, and after the site is gone. A phone app, a browser extension, tags, search, and an export to EPUB or straight to a Kindle. It's what Pocket was before it closed.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/wallabag/compose.yaml |
| Web | http://server-ip:8082 |
| Default login | wallabag / wallabag — change it |
| Browser | the wallabagger extension (Firefox, Chrome) |
| Phone | Wallabag (Android, iOS) with your server URL and API client |
| Import | Import → Pocket / Instapaper / HTML / RSS |
1. The compose file
mkdir -p ~/docker/wallabag && cd ~/docker/wallabag
nano compose.yaml
services:
wallabag:
image: wallabag/wallabag:latest
container_name: wallabag
ports:
- "8082:80"
environment:
SYMFONY__ENV__DOMAIN_NAME: http://192.168.1.50:8082
SYMFONY__ENV__DATABASE_DRIVER: pdo_pgsql
SYMFONY__ENV__DATABASE_HOST: db
SYMFONY__ENV__DATABASE_PORT: 5432
SYMFONY__ENV__DATABASE_NAME: wallabag
SYMFONY__ENV__DATABASE_USER: wallabag
SYMFONY__ENV__DATABASE_PASSWORD: ${DB_PASSWORD}
SYMFONY__ENV__SECRET: ${APP_SECRET}
SYMFONY__ENV__FOSUSER_REGISTRATION: "false"
SYMFONY__ENV__LOCALE: en
POPULATE_DATABASE: "true"
volumes:
- ./images:/var/www/wallabag/web/assets/images
- ./data:/var/www/wallabag/data
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: wallabag
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: wallabag
volumes:
- ./db:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:alpine
restart: unless-stopped
.env with DB_PASSWORD and APP_SECRET. DOMAIN_NAME must be the address you'll use — change it to https://read.example.com once it's behind the proxy, then up -d.
docker compose up -d
docker compose logs -f wallabag # wait for "Database populated"
2. First login
http://192.168.1.50:8082, wallabag / wallabag. Config → User information to change the password (and username). Registration is off, so add family under Config → Users if they want their own.
3. Save things
- Browser: the wallabagger extension → options → your Wallabag URL, then create an API client in Wallabag (Config → API clients → Create) and paste the client ID and secret. One click saves the page.
- Phone: the Wallabag app → server URL + the same API client + your login. Share any page to it; read offline.
- Web: the + button and paste a URL.
- Email / RSS: every feed in FreshRSS (tutorial 89) has a "save to Wallabag" share action.
4. Read
Articles open as clean text with the images kept, adjustable font and dark mode, a reading-progress bar, and an estimated time. Tag them (#long, #recipes), star favourites, mark read. Search covers the full text. Rules (Config → Tagging rules) tag automatically: readingTime > 20 → long.
5. Send to a Kindle, or export
Any article → Export → EPUB / PDF / MOBI. For a weekly Kindle digest, the wallabag-kindle script or Calibre-Web (tutorial 86) with the EPUBs works. Everything can be exported in bulk from Config, so you're never stuck.
6. Import
Import → Pocket (upload the CSV from your Pocket export), Instapaper, Readability, a browser's HTML bookmarks, or a Wallabag JSON from another instance. Imports fetch each article's text as they go, which takes a while for thousands.
Troubleshooting
Saved an article but the text is empty. The site blocks fetching or needs a login. The extension can save the page as rendered instead; or paste the text manually.
Images missing after moving behind the proxy. DOMAIN_NAME still points at the old address.
App can't connect. API client missing, or the URL has a trailing slash problem — use https://read.example.com with no slash.
Slow imports. Redis handles the queue; docker compose logs redis should be quiet. Patience.
Wrapping up
Three containers, change the default login, create an API client, install the extension and the app. Every article you mean to read is on your server as clean text, readable on the train with no signal, and still there in ten years.
