Jellystat
Overview
Jellystat is a popular open source, self-hosted statistics and analytics dashboard for a Jellyfin media server. It records playback activity and presents your libraries, users, full and grouped watch history, most active content and live now-playing sessions in a clean, modern interface with charts and drill-downs.
This SecureAnyCloud image builds Jellystat 1.1.11 from source under /opt/jellystat and fronts it with nginx on port 80. It is secure by default: the image ships uninitialised, with no administrator and no shared secret. Your first visit opens a setup wizard where you create your own administrator and add your Jellyfin server.
Two per-VM secrets, a JWT signing secret and the PostgreSQL role password, are generated on first boot and never shared between instances. The jellystat-firstboot.service oneshot rotates those secrets, ensures the empty database exists, resolves the instance URL and starts the stack, then disables itself.
What you get:
- Jellystat 1.1.11 (MIT) under
/opt/jellystat - Local PostgreSQL 16 database
jfstat, bound to loopback (127.0.0.1:5432) jellystat.servicerunning as the dedicatedjellystatsystem user, bound to loopback at127.0.0.1:3000- nginx reverse proxy on port 80, configured for the Socket.io WebSocket traffic that the live now-playing view relies on, and ready for your TLS certificate
jellystat-firstboot.servicefor per-VM secret rotation and stack start- Node.js 22 LTS runtime
- Ubuntu 24.04 LTS base, patched at build time
- 24/7 SecureAnyCloud support, 24h response SLA
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet.
The recommended VM size is Standard_B2s. Jellystat is lightweight, and 4 GB of RAM is comfortable.
You also need a reachable Jellyfin server and a Jellyfin API key, so that Jellystat can read playback data during setup.
Deploy from the Azure Portal
Search the Azure Marketplace for Jellystat on Ubuntu 24.04 and choose your VM size.
Attach a network security group (NSG) that allows TCP 22 (SSH) from your management network and TCP 80 / 443 (the web app) from the networks that need it. In production, put TLS in front of port 80 (see Step 10).
Deploy from the Azure CLI
RG="jellystat-prod"; LOCATION="eastus"; VM_NAME="jellystat-01" IMAGE_URN="sac1647283583153:jellystat-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name js-vnet --address-prefix 10.90.0.0/16 --subnet-name js-subnet --subnet-prefix 10.90.1.0/24 az network nsg create -g "$RG" --name js-nsg az network nsg rule create -g "$RG" --nsg-name js-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name js-nsg --name allow-web --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 443 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:jellystat-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name js-vnet --subnet js-subnet --nsg js-nsg --public-ip-sku StandardConnect over SSH
ssh azureuser@<vm-ip>Verify the services are running
Run the commands below to check the stack. PostgreSQL and Jellystat listen on loopback only. nginx serves the web app on port 80 and proxies its Socket.io WebSocket traffic.
sudo systemctl is-active postgresql jellystat nginx ss -tln | grep -E ':80 |127.0.0.1:3000|127.0.0.1:5432' curl -s -o /dev/null -w 'GET /auth/isconfigured -> HTTP %{http_code}\n' http://127.0.0.1/auth/isconfiguredAll three services report active. PostgreSQL is bound to 127.0.0.1:5432, the Node server to 127.0.0.1:3000 and nginx to :80. The configuration API returns HTTP 200 through nginx.
Confirm the secure defaults
Nothing sensitive ships in the image. The application reports state:0, so every instance starts at the create-admin wizard. The per-VM credentials note in /root is root-only.
The JWT signing secret and the PostgreSQL password are generated on first boot. The command below masks them.
curl -s http://127.0.0.1/auth/isconfigured
sudo stat -c '%n perms=%a owner=%U:%G' /root/jellystat-credentials.txt
sudo sed -E 's/^(JWT_SECRET|POSTGRES_PASSWORD)=.*/\1=**** (per-VM, first boot)/' /root/jellystat-credentials.txt | grep -E '^JELLYSTAT_URL|^POSTGRES_USER|^POSTGRES_DB|^NOTE'
curl -s -o /dev/null -w 'GET /api/getLibraries (no token) -> HTTP %{http_code}\n' http://127.0.0.1/api/getLibrariesThe app reports state:0 (create-admin wizard) and the credentials note is 600 root:root. The two secrets are unique to this VM. A protected API endpoint returns HTTP 401 without an auth token.
Complete the first-run setup wizard
Open http://<vm-ip>/ in your browser. Because no administrator ships with the image, Jellystat shows First Time Setup Step 1 of 2. Choose your own admin username and password, then click Create User.
Step 2 of 2 asks for your Jellyfin server URL and an API key, so that Jellystat can read playback data. Create the key in Jellyfin under Dashboard, API Keys. Enter the URL and the key, then click Save Jellyfin Details.
Sign in and explore the dashboard
After setup, Jellystat requires authentication. Sign in with the admin username and password you just created.
The dashboard shows live now-playing sessions, recently added media, watch statistics over a configurable window, and a library overview. The left navigation gives you Libraries, Users, Activity, Statistics and Settings.
The runtime stack
node -v nginx -v sudo runuser -u postgres -- psql -tAc 'show server_version' jq -r .version /opt/jellystat/package.jsonNode.js 22 LTS runs the server, nginx 1.24 fronts it and PostgreSQL 16 stores the data. The pinned Jellystat release is 1.1.11.
Data and persistence
All statistics live in the local PostgreSQL database jfstat, which is captured into the image and carried onto every instance. The application creates its own schema on first connect.
sudo runuser -u postgres -- psql -tAc "SELECT datname FROM pg_database WHERE datname='jfstat'" systemctl is-enabled jellystat-firstboot.service apt-mark showholdThe jfstat database is present. The first-boot service has run and disabled itself for this instance. No packages are held, so the OS security baseline is intact.
Enable HTTPS
nginx already fronts Jellystat on port 80 and is ready for TLS. Point a DNS record at your VM, then obtain a certificate with certbot.
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain> --agree-tos -m <your-email> --redirectcertbot installs the certificate, rewrites the nginx server block for TLS and sets up automatic renewal. Your analytics portal is then served over HTTPS.
Managing the service
sudo systemctl status jellystat --no-pager sudo systemctl restart jellystat
sudo journalctl -u jellystat -n 20 --no-pagerThe Node server logs to the journal. nginx logs are under /var/log/nginx/, and the PostgreSQL data lives under /var/lib/postgresql.
To back up the instance, snapshot the OS disk or use Jellystat's own scheduled backup feature under Settings.
Support
SecureAnyCloud provides 24/7 support for this image by email and live chat. Support covers deployment, nginx TLS termination, upgrades, Jellyfin integration and API keys, and PostgreSQL tuning and backups. Email sales@secureanycloud.com.
This is a repackaged open source software product, with additional charges for SecureAnyCloud support services. Jellystat and Jellyfin are trademarks of their respective owners. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on Azure
Launch Jellystat on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Jellystat is an open source, self-hosted statistics and analytics dashboard for a Jellyfin media server. It records playback activity and presents your libraries, users, watch history, most-active content and live now-playing sessions in a clean, modern interface with charts and drill-downs.
This SecureAnyCloud image runs Jellystat as a Node.js server, built from source, with its data in a local PostgreSQL database bound to the loopback interface. The server listens on 127.0.0.1:3000 and is reached through nginx as a reverse proxy on port 80 (and 443 once you add TLS).
What you get:
- nginx pre-configured to proxy the Socket.io WebSocket channel that powers live now-playing session monitoring
- No administrator account and no static secret baked into the image: it boots to a first-run setup wizard where you create your own administrator
- A fresh per-instance JWT signing secret and PostgreSQL password, generated automatically on the first boot of every deployed instance
- No shared passwords or pre-seeded database rows
Prerequisites
Before you deploy this image, make sure you have:
- An AWS account subscribed to this product on AWS Marketplace.
- A running Jellyfin media server that you administer, and the ability to generate an API key on it (Jellyfin: Dashboard, API Keys). Jellystat connects to your Jellyfin server to gather statistics. It does not replace Jellyfin.
- An EC2 key pair in your target region for SSH access.
- A security group that allows inbound TCP 22 (SSH) from your IP, and TCP 80 (and 443 if you add TLS) from the clients that will use the dashboard.
The recommended instance type is m5.large. Jellystat is lightweight, so a smaller instance also works, and you can resize later.
Connecting to your instance
Connect over SSH as the default login user of your operating system variant. This listing currently ships the following variant:
OS variant SSH login user
Ubuntu 24.04 LTS ubuntu
ssh ubuntu@<public-ip>First boot: create your administrator
On your first visit, Jellystat presents a two-step setup wizard. There is no default account, so you start by creating your own administrator.
Open http://<public-ip>/ in a browser. On First Time Setup Step 1 of 2, choose an administrator username and password, then select Create User.
Connect your Jellyfin server
On First Time Setup Step 2 of 2, enter the URL of your Jellyfin server and an API key generated on it. In Jellyfin, open Dashboard, API Keys and add a key, for example one named Jellystat.
Select Save Jellyfin Details. Jellystat validates the connection before saving.
The dashboard
Once your Jellyfin server is connected and Jellystat has completed its first sync, the Home dashboard shows live sessions, recently added items, watch statistics and a library overview.
Jellystat keeps its own history, so your statistics accumulate over time independently of Jellyfin.
Statistics and reporting
The Statistics view charts daily play counts and durations per library over a configurable time range. The Activity and Users views break playback down by title and by user.
Use the range selector to switch between the last 20, 30 or more days.
Checking the services
Three systemd services run this image: PostgreSQL, the Jellystat Node server and nginx. Confirm that they are active:
sudo systemctl is-active postgresql jellystat nginxExpected output:
active active activeThe application answers a health endpoint through nginx. Before you complete the setup wizard, it reports state:0, which means no administrator has been created yet:
curl -s http://127.0.0.1/auth/isconfigured{"state":0,"version":"1.1.11"}The Node server and PostgreSQL bind to the loopback interface only. Only nginx (port 80) is exposed:
sudo ss -tlnp | grep -E ':80 |:3000 |:5432 'Per-instance secrets
The Jellystat administrator is the one you create in the setup wizard, so there is no admin password to retrieve from the instance. For recovery and administration, the two per-instance secrets that first boot generated (the JWT signing secret and the PostgreSQL role password) are recorded in a root-only file:
sudo cat /root/jellystat-credentials.txtThe file (mode 0600, root only) contains, with the secret values unique to your instance:
JELLYSTAT_URL=http://REDACTED_HOST/ SETUP_WIZARD=http://REDACTED_HOST/ JWT_SECRET=<set-at-first-boot> POSTGRES_PASSWORD=<set-at-first-boot> POSTGRES_USER=jellystat POSTGRES_DB=jfstatYou do not normally need these values; keep the file private.
Enabling HTTPS
nginx serves the dashboard on port 80 and is ready for a TLS certificate on port 443. To obtain a free certificate from Let's Encrypt, point a domain at the instance and open port 443 in the security group. Then run certbot for nginx:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.comcertbot edits the nginx site to add the port 443 server block and sets up automatic renewal.
Backups
Jellystat keeps its history in the local PostgreSQL database jfstat. For a full point-in-time backup, snapshot the EC2 instance's EBS volume. Alternatively, take a logical dump of the database:
sudo -u postgres pg_dump jfstat > /tmp/jfstat-backup.sqlJellystat also has a built-in backup feature under Settings. It writes to its own backup directory, which you can then copy to Amazon S3.
Support
This image includes 24/7 SecureAnyCloud support by email and live chat. Contact sales@secureanycloud.com for help with deployment, upgrades, connecting Jellystat to your Jellyfin server, TLS termination, PostgreSQL maintenance or troubleshooting.
Jellystat and Jellyfin are trademarks of their respective owners. This is a repackaged open source software product, with additional charges for SecureAnyCloud support services.
Deploy on AWS
Launch Jellystat on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com