
Programming
Video Portal for the Municipality of Old Sącz
A community video platform for the municipality on PeerTube: a consistent theme aligned with the portal and WCAG compliant, updating PeerTube and PostgreSQL without losing recordings or cache, and caching that eliminated stuttering during council session broadcasts.
11/10/2026
The municipality of Stary Sącz has its own video service at video.starysacz.um.gov.pl. It features recordings and live streams of Town Council sessions, event films, and promotional materials. The municipal channel already has over 140 videos.
The portal operates on PeerTube, an open-source alternative to YouTube, hosted on the municipality's servers. It is ad-free, without algorithms suggesting external videos, and does not share viewer data with external platforms.
My task was threefold: to upgrade the outdated version of the system, resolve issues with live broadcasts, and align the appearance with the new municipal portal.

Theme consistent with the municipal portal
The video portal looked like any other PeerTube instance. I prepared my own theme that takes fonts, shapes, and neutral colors from the municipal portal. The accent color is carmine, from the crown in the coat of arms, so it's immediately clear that this is a separate service for the same municipality.
- self-hosted Atkinson Hyperlegible Next and Bricolage Grotesque fonts, with Polish characters,
- light and dark mode based on system settings, as well as a high contrast variant,
- all text and background contrast ratios of at least 4.5:1, form field outlines 3:1,
- clear keyboard focus and indication of the current menu position,
- video descriptions and captions in 16 pixels instead of 14.
The theme is a separate package with its own version number. The built-in PeerTube theme remains in place, so if there are any issues, you can simply switch back to it from the dashboard.

Update Without Losing Recordings
The portal was running on PeerTube 7.2 and PostgreSQL 13. Both had already been succeeded by newer versions, and PostgreSQL 13 was nearing the end of its support period. I carried out the update in two steps, each with a script and full backup:
- PeerTube 7.2 to 8.2 with database migrations,
- PostgreSQL versions 13 to 17 and PeerTube version 8.3,
- an update to yt-dlp, which PeerTube uses for importing videos,
- the old containers were halted but not removed until it was confirmed that everything worked.
In the process, a bug was discovered that no one had noticed: the container had been reporting as 'unhealthy' for six days because the health check used a tool that wasn't present in the new image. Now the check simply queries the PeerTube API.
Smooth live sessions broadcasts
The most noticeable problem was live streaming. With 30-40 viewers watching the council sessions, some people would receive timeouts errors. Each viewer was downloading the same large chunks of the video directly from the PeerTube server.
The solution is caching in a reverse proxy. nginx cuts video segments into 1 MB pieces and keeps them in cache for two hours. The playlist refreshes every 5 seconds, so the live stream continues to work.

The second fix was less visible but important. PeerTube saw every viewer as a proxy server address, which caused the view counters to be underestimated and made it impossible for password-guessing protection to work. After adjusting the trusted proxies configuration, the portal now sees real addresses.
Protecting the entire proxy
Since I was already working with a proxy server, I deployed CrowdSec on it. It analyzes the logs of all websites that pass through it and blocks addresses at the firewall level. It also uses a shared list of addresses reported by other users.
I wrote a simple internal dashboard to monitor blocks and alerts, which refreshes every 30 seconds.
Legally required content
The municipal video portal is also a public service. It was equipped with an accessibility declaration, information on personal data protection, and a separate clause for live sessions, modeled after the municipality's portal. Outgoing mail operates through the town hall's mail server.
The session broadcast sometimes has dozens of viewers, sometimes hundreds. For each of them, it's the only way to see how the councilors vote. It just has to work.
- Aleksander Kowal
Stack
- PeerTube 8.3 on Docker, PostgreSQL 17,
- a custom PeerTube theme with versioning and CI on OneDev,
- nginx (Nginx Proxy Manager) with HLS caching in the slice module,
- CrowdSec with a bouncer at the dam.
