Self-hosted music streaming without barriers.
ResoNode is a self-hosted music streaming platform designed to provide full control over a personal music library. It serves as an alternative to commercial streaming services, allowing users to host their own server and access their music remotely without subscriptions, ads, or data tracking.
Unlike other media servers like Plex or Jellyfin, ResoNode is built with a specific focus on resilience and connection simplicity for users with dynamic IPs.
- Data Sovereignty: You host the MP3 files. The library is not subject to licensing agreements or removals.
- Connection Mechanism: Removes the need for static IPs, dynamic DNS (DDNS), or complex VPN configurations (like WireGuard/Tailscale). It uses a secure discovery system based on Cloudflare Tunnels and AES-Encrypted GitHub Gists to locate the server automatically.
- Hybrid Playback:
- Streaming: Plays directly from the server when an internet connection is available, using chunked streaming for fast loading.
- Offline Mode: Downloads playlists to local storage. The app manages the local database transparently, switching modes automatically when network connectivity is lost.
- The Vault: An automated file system that organizes uploads by Artist, Album, and Track based on metadata.
- Legacy Support: Designed with a lightweight interface and a custom TLS 1.2 implementation, ensuring smooth performance even on older hardware (Android 4.4+) used as dedicated media players.
The project is structured into three main directories:
/server(Python/FastAPI): Runs on the host machine. Manages the file system, user authentication, URL updating, and streaming logic./user(Python Tools): Helper scripts (deploy.pyandmusic_uploader.py) to manage your server remotely./app(Android Client): A native application optimized for low-latency streaming and offline synchronization.
To bypass carrier-grade NAT (CGNAT) and dynamic IPs without user intervention:
- Tunneling: A secure Cloudflare Tunnel (
cloudflared) assigns a temporary, random public URL to the server. - Broadcasting: Upon startup, the backend (
api_musica.py) triggers a background script (update_url.py) that encrypts the new URL using AES-256 and patches a private GitHub Gist. - Discovery: When the Android app launches (or loses connection), it fetches the GitHub Gist, decrypts the payload locally using the shared secret key, and updates its target URL.
- Handshake: The app establishes a direct, secure connection to the server seamlessly.
An integrated, privacy-focused analytics engine designed to track listening habits without third-party data mining. Built with a local-first philosophy.
- Offline-Persistent Tracking: Playback history (duration and track counts) is recorded into an internal SQLite database.
- Smart Synchronization: The app detects when internet connectivity is restored and automatically pushes unsynced local logs to the server.
- Privacy & Community: Strictly opt-in via Settings:
- OFF (Default): The app does not record any data.
- Private Mode: Statistics are strictly for personal viewing.
- Public Mode: Opt-in to a server-wide leaderboard to compare listening times with other instance members.
- Python 3.8 or higher.
- Cloudflared: The Cloudflare tunnel daemon must be installed and running.
- GitHub Account: A Personal Access Token (Classic) with
gistpermissions to update the dynamic URL.
-
Install Dependencies:
pip install fastapi uvicorn python-multipart mutagen requests cryptography
-
Configuration:
- Navigate to the
server/directory. - Rename
server_config_template.pytoserver_config.py(this file is git-ignored to prevent credential leakage). - Edit the file with your credentials:
API_SECRET_KEY = "YOUR_SECURE_KEY" # Used for app access and URL AES encryption ADMIN_SECRET_KEY = "YOUR_ADMIN_KEY" # Used for remote APK/Music uploads GITHUB_TOKEN = "ghp_your_personal_access_token" GIST_ID = "your_gist_id" PORT = 5000
- Navigate to the
-
Run the Server: Execute the main API script. It will automatically start the background URL updater.
cd server python api_musica.py
For security reasons, user registration is strictly tied to server-side directory allocation. Before a user can create an account and log in via the Android app, the administrator must manually create a dedicated folder for them in the server's root directory (e.g., mkdir Alemany).
If this physical folder does not exist, the API will automatically reject any registration attempt to prevent unauthorized access.
You can install the ResoNode client either by downloading the pre-compiled application or by building it manually from the source code.
- Navigate to the Releases page of this repository.
- Download the latest
.apkfile to your Android device. - Open the file and install it (you may need to enable "Install from Unknown Sources" in your device settings).
- Upon launching the app, enter your server credentials as prompted.
- Open the project in Android Studio.
- Build: Compile the APK (
Build > Generate Signed Bundle / APK) and install it on the target device.
ResoNode includes user-friendly helper scripts in the /user folder to manage your server without SSH access.
- Navigate to the
user/directory. - Run the uploader script:
python music_uploader.py
- Follow the interactive wizard:
- Drag and drop your local music folder containing
.mp3files. - Choose whether you are at home (Local IP) or away (fetches URL via Gist).
- Select a target playlist or send it directly to the Vault.
- Drag and drop your local music folder containing
The script filters for MP3s, zips them, and uses your ADMIN_SECRET_KEY to securely push them to the server for automatic ID3 extraction and sorting.
ResoNode includes a built-in Over-The-Air update mechanism. You can deploy new code to your server remotely, and client apps will prompt users to download the update automatically.
- Build: Generate a Signed/Debug APK in Android Studio.
- Navigate to the
user/directory and run:python deploy.py
- Follow the wizard:
- It detects the latest compiled APK from the
app/build/folder. - Enter the new Version Code and a Changelog.
- Deploy via Local Network (SSH/SCP) or Remote Network (HTTP POST via Cloudflare using your
ADMIN_SECRET_KEY).
- It detects the latest compiled APK from the






