====== NewsBlur Installation on Ubuntu Server ======
This article documents the working NewsBlur installation on the Ubuntu server.
It intentionally describes the **final working configuration**, rather than every failed command or troubleshooting attempt made during the original installation.
NewsBlur is running as a collection of Docker containers. The NewsBlur application/source files live on the server's internal Linux filesystem, while the large persistent database and search-engine data directories are stored on the external SSD mounted at:
/mnt/media8
===== Installation Layout =====
The main NewsBlur working directory is:
/home/mike/docker/newsblur
or, when logged in as ''mike'':
~/docker/newsblur
The NewsBlur Docker configuration bind-mounts this directory into the applicable containers as:
/srv/newsblur
This is important because changes made to files under:
/srv/newsblur
inside the NewsBlur containers are actually changes to:
/home/mike/docker/newsblur
on the host.
For example:
/srv/newsblur/utils/feed_fetcher.py
inside ''newsblur_web'' corresponds to:
~/docker/newsblur/utils/feed_fetcher.py
on the Ubuntu host.
This also means local source-code modifications generally survive Docker container recreation.
However, a future Git update to the NewsBlur source can overwrite or conflict with locally modified files.
===== External SSD Storage =====
The NewsBlur source code remains under:
~/docker/newsblur
The persistent database/search data is stored on the external SSD mounted at:
/mnt/media8
NewsBlur-specific persistent data is kept under:
/mnt/media8/docker/newsblur/
The major directories are:
/mnt/media8/docker/newsblur/postgres
/mnt/media8/docker/newsblur/redis
/mnt/media8/docker/newsblur/mongo
/mnt/media8/docker/newsblur/elasticsearch
This keeps large and frequently changing application data off the server's main Linux filesystem.
It also means that **/mnt/media8 must be mounted before NewsBlur is expected to operate normally**.
===== Important Server-Specific Mount Policy =====
External/data drives on this server are configured so that a missing or failed external drive does **not** prevent Ubuntu from booting.
When configuring the mount in ''/etc/fstab'', use the server's normal ''nofail'' policy.
The general philosophy is:
* Ubuntu must remain bootable even if an external drive fails.
* Docker may subsequently have services that fail because their data is unavailable.
* A failed Docker service is preferable to a server that cannot boot.
Do not remove ''nofail'' from external-drive mounts without a specific reason.
===== NewsBlur Data Directory Permissions =====
During installation, the persistent NewsBlur directories required ownership matching the users used inside the respective containers.
The working ownership configuration used during setup was:
sudo chown -R 999:999 /mnt/media8/docker/newsblur/postgres
sudo chown -R 999:999 /mnt/media8/docker/newsblur/redis
sudo chown -R 999:999 /mnt/media8/docker/newsblur/mongo
sudo chown -R 1000:0 /mnt/media8/docker/newsblur/elasticsearch
The directories were also restricted with:
sudo chmod 750 /mnt/media8/docker/newsblur/postgres
sudo chmod 750 /mnt/media8/docker/newsblur/redis
sudo chmod 750 /mnt/media8/docker/newsblur/mongo
sudo chmod 750 /mnt/media8/docker/newsblur/elasticsearch
These permissions are intentionally different from the normal shared-media configuration used elsewhere on the server.
Do **not** automatically change these NewsBlur application-data directories to ''mike:media'' or ''2775'' simply because that convention is used for media storage.
The database containers expect their own UID/GID ownership.
===== Main Docker Services =====
The NewsBlur Docker Compose installation contains several cooperating services.
Important containers include:
* ''newsblur_web'' — main NewsBlur Python/Django application
* ''newsblur_celery'' — background jobs and scheduled feed fetching
* ''newsblur_node'' — NewsBlur Node service
* ''newsblur_nginx'' — internal Nginx frontend
* ''newsblur_db_postgres'' — PostgreSQL database
* ''newsblur_db_redis'' — Redis
* ''newsblur_db_mongo'' — MongoDB
* ''newsblur_db_elasticsearch'' — Elasticsearch
* ''newsblur_imageproxy'' — image proxy
* ''newsblur_mcp'' — NewsBlur MCP service
* HAProxy — internal NewsBlur proxy/load-balancing component
Most services use:
restart: unless-stopped
This allows the NewsBlur stack to return automatically after a normal server or Docker restart.
===== Important Bind Mounts =====
The main NewsBlur source tree is mounted into several containers.
For example:
/home/mike/docker/newsblur -> /srv/newsblur
This is used by at least the web application and the Celery/background-worker infrastructure.
Consequently, when modifying NewsBlur Python code, restarting only ''newsblur_web'' may not be sufficient.
If the changed code is also used for background jobs or feed fetching, restart Celery as well:
docker restart newsblur_web
docker restart newsblur_celery
===== Local Service Ports =====
Several NewsBlur services publish ports only to ''127.0.0.1''.
Examples from the working configuration include:
newsblur_web 127.0.0.1:8000
newsblur_nginx 127.0.0.1:8181
newsblur_node 127.0.0.1:8008
imageproxy 127.0.0.1:8088
PostgreSQL 127.0.0.1:5434
Redis 127.0.0.1:6579
MongoDB 127.0.0.1:29019
Elasticsearch 127.0.0.1:9200 / 9300
HAProxy exposes the NewsBlur HTTP/HTTPS frontend using the ports configured in the Compose stack.
Binding most internal services to ''127.0.0.1'' prevents the database and internal application services from being directly exposed to the LAN or Internet.
===== Starting NewsBlur =====
Go to the NewsBlur directory:
cd ~/docker/newsblur
Start or update the existing containers with:
docker compose start
Check their status with:
docker compose ps
===== Restarting NewsBlur =====
A single service can be restarted without bringing down the entire installation.
For example:
docker restart newsblur_web
For changes affecting background feed processing:
docker restart newsblur_celery
To restart both:
docker restart newsblur_web newsblur_celery
===== Viewing Logs =====
Standard Docker logs can be viewed with:
docker logs newsblur_web
or:
docker logs newsblur_celery
Follow a log live with:
docker logs -f newsblur_web
NewsBlur also maintains its own application log within the bind-mounted source tree:
~/docker/newsblur/logs/newsblur.log
This can be useful for diagnosing individual feed failures.
For example:
grep -i "failed" ~/docker/newsblur/logs/newsblur.log
===== Inspecting the Actual Docker Configuration =====
Because NewsBlur has many services and mounts, ''docker compose config'' is useful for seeing the final configuration after Compose processing.
From:
cd ~/docker/newsblur
run:
docker compose config
To inspect the mounts of an individual container:
docker inspect newsblur_web --format '{{range .Mounts}}{{println .Type "|" .Source "|" .Destination}}{{end}}'
For this installation, this confirms:
bind | /home/mike/docker/newsblur | /srv/newsblur
===== Updating NewsBlur =====
Because this installation uses the NewsBlur source repository directly, remember that local source modifications can appear in Git.
This installation currently has important local modifications to:
docker-compose.yml
utils/feed_fetcher.py
The ''docker-compose.yml'' changes are part of this server's local Docker, networking, port-binding, and storage configuration.
The ''utils/feed_fetcher.py'' change is the local YouTube RSS workaround described below.
Before updating, check for local changes:
cd ~/docker/newsblur
git status
git diff
If ''git diff'' opens in a pager and displays ''(END)'', press:
q
to return to the command prompt.
A ''git pull'' may refuse to proceed or create a conflict if upstream NewsBlur modifies a file that has also been modified locally.
Do **not** blindly discard local changes before determining what they are.
Next, check whether upstream NewsBlur has changed:
git fetch
git status
''git fetch'' checks for upstream changes without modifying the local NewsBlur files.
If Git reports:
Your branch is up to date with 'origin/main'.
there is no NewsBlur source update to install and the source-update procedure can stop here.
==== Check Local Files Against Upstream ====
Before pulling an upstream update, check whether NewsBlur has changed either of the files that are modified locally:
git diff HEAD..origin/main -- docker-compose.yml
git diff HEAD..origin/main -- utils/feed_fetcher.py
If either command produces output, upstream has changed that file since the currently installed version.
Review those changes before proceeding.
Even if no upstream changes are shown for these files, save copies of the local modifications before updating.
==== Save the Local Docker Configuration ====
Save the local ''docker-compose.yml'' changes as a patch:
git diff -- docker-compose.yml > ~/newsblur-docker-compose-local.patch
Also save a complete copy of the current local Compose file:
cp docker-compose.yml ~/newsblur-docker-compose.yml.backup
The complete backup is useful because the Compose file contains important server-specific settings such as local port bindings and database/storage locations.
Optionally review the saved patch:
cat ~/newsblur-docker-compose-local.patch
==== Check and Save the Local YouTube RSS Modification ====
This NewsBlur installation includes a local modification to:
utils/feed_fetcher.py
The modification allows direct YouTube RSS URLs such as:
https://www.youtube.com/feeds/videos.xml?channel_id=...
to bypass NewsBlur's normal YouTube API-based fetcher and instead be handled as regular RSS feeds.
Inspect the current upstream YouTube handling:
git show origin/main:utils/feed_fetcher.py | \
grep -n -A 8 -B 8 'is_youtube_feed_address(address)'
If upstream still contains:
if is_youtube_feed_address(address):
and does not otherwise provide equivalent handling for direct ''/feeds/videos.xml'' URLs, the local workaround is still needed.
Save a copy of the local modification:
git diff -- utils/feed_fetcher.py > ~/newsblur-youtube-rss-fix.patch
Optionally review it:
cat ~/newsblur-youtube-rss-fix.patch
The saved patch should include the important change:
- if is_youtube_feed_address(address):
+ if is_youtube_feed_address(address) and "/feeds/videos.xml" not in address:
==== Temporarily Stash the Local Changes ====
Before pulling the update, temporarily stash both locally modified files:
git stash push -m "Local NewsBlur server modifications" -- docker-compose.yml utils/feed_fetcher.py
git status
Confirm that neither ''docker-compose.yml'' nor ''utils/feed_fetcher.py'' is still listed as modified.
The existing untracked backup files, such as:
docker-compose.yml.original
utils/feed_fetcher.py.bak
may still appear under ''Untracked files''. This is normal and does not prevent the update.
==== Update the NewsBlur Source ====
If Git reports that the local branch is behind the upstream branch and the local modifications have been safely backed up and stashed, update the source with:
git pull --ff-only
''--ff-only'' prevents Git from automatically creating a merge commit if the local and upstream histories have unexpectedly diverged.
==== Review the Updated Files Before Restoring Local Changes ====
After the pull completes, inspect the updated Compose file:
git diff HEAD@{1}..HEAD -- docker-compose.yml
If upstream has substantially changed the Compose configuration, review those changes before restoring the old local version.
Also inspect the updated YouTube handling:
grep -n -A 8 -B 8 'is_youtube_feed_address(address)' utils/feed_fetcher.py
If NewsBlur still sends direct YouTube RSS URLs through its YouTube fetcher, the local YouTube workaround is still needed.
If upstream NewsBlur appears to have fixed the underlying YouTube RSS issue, **do not blindly restore the old YouTube modification**. Review and test the new upstream behavior first.
==== Restore the Local Modifications ====
If the upstream changes do not make the local modifications obsolete or incompatible, restore them with:
git stash pop
Then inspect the result:
git status
git diff
Confirm that the local ''docker-compose.yml'' settings are still correct and that the YouTube change is present:
- if is_youtube_feed_address(address):
+ if is_youtube_feed_address(address) and "/feeds/videos.xml" not in address:
If ''git stash pop'' reports a conflict, **do not discard either version**. Review the conflict and reconcile the upstream changes with the local server configuration before continuing.
The separately saved backup files remain available at:
~/newsblur-docker-compose-local.patch
~/newsblur-docker-compose.yml.backup
~/newsblur-youtube-rss-fix.patch
==== Update Docker Images and Containers ====
After the NewsBlur source and local modifications are in the desired state, update the Docker images and containers:
docker compose pull
docker compose up -d
docker compose ps
Confirm that the expected NewsBlur containers are running normally.
Only prune unused Docker images when desired:
docker image prune
===== Backup Considerations =====
The NewsBlur installation is split between two important locations.
Application/configuration/source:
/home/mike/docker/newsblur
Persistent database/search data:
/mnt/media8/docker/newsblur
A complete NewsBlur backup strategy therefore needs to account for **both locations**.
Backing up only ''~/docker/newsblur'' does not back up the PostgreSQL, Redis, MongoDB, or Elasticsearch data stored on the external SSD.
Likewise, backing up only ''/mnt/media8/docker/newsblur'' does not preserve the Compose configuration and locally modified NewsBlur source tree.
===== Known Local Modification =====
As of September 2026, this NewsBlur installation contains a small local modification that allows official YouTube RSS feeds to bypass NewsBlur's YouTube Data API fetcher.
This was necessary because valid YouTube RSS feeds were returning:
YouTube fetch failed (404)
inside NewsBlur even though the same RSS URLs worked normally in a browser.
See:
[[tech:newsblur_youtube_fix|NewsBlur YouTube RSS Fix]]