Browse docs
Installation
Requirements
| Requirement | Purpose |
|---|---|
| FiveM server with OneSync enabled | Shared club state, routing buckets and server-side position checks |
ESX with RunStaticPlayerMethod support | Player access and framework integration |
ox_lib | Callbacks and shared utilities |
sky_base with a working database connection | Framework bridge, interactions and automatic SQL persistence |
Optional ox_target | Target interaction when selected in Sky Base |
Use the database provider already configured for Sky Base, such as oxmysql or mysql-async. Sky DJ includes its audio engine; a separate sound resource and sky_jobs_base are not required.
The standard resource installation does not require external Node.js, Python or FFmpeg. The published package already contains the frontend. Separate Windows and Linux instructions below apply only to preparing and serving the optional FFmpeg/Opus music export.
Install the resource
Copy the complete resource
Extract the release package and copy its resources/[sky]/sky_dj folder into your server's resources directory. Keep the resource name sky_dj and retain its complete config, source/html and stream folders.
The resulting resource path is resources/[sky]/sky_dj/fxmanifest.lua.
Your installation must contain fxmanifest.lua directly inside sky_dj, without an extra nested sky_dj directory. Keep the package-root documentation and prepare-music-stream.cjs separately; they are not resources to start.
Configure the database and start order
Start your database provider and ESX before the Sky resources. The following example uses an existing oxmysql installation; retain your own database connection settings and provider.
set onesync on
ensure oxmysql
ensure es_extended
ensure ox_lib
ensure sky_base
ensure sky_dj
OneSync must be enabled before resource startup. See the official FiveM resource commands and OneSync setting.
Sky Base creates the sky_dj_state table and missing initial records automatically. The database account must be able to create or alter the resource's tables and read and write their data. No manual SQL import is required.
Choose who owns the settings
The default Config.IngameSettings = true uses saved SQL settings. Open /djadmin → Settings as an authorized administrator and save changes there. Other global values in config/config.lua do not override these settings, including on first startup.
To configure global settings through files, change the existing IngameSettings entry to false, edit config/config.lua, and restart sky_dj. This disables global settings writes in-game while retaining the saved SQL settings. Club layouts, placed devices and playlists remain in SQL in either mode.
Administrator access defaults to ESX admin / superadmin or ACE sky.dj.admin. See Configuration for permissions, language and the configuration ownership rules.
Add music and verify startup
Add your own MP3 files to sky_dj/config/music/, then restart sky_dj. The customer package does not include a music library.
Open /djadmin → Settings → Music & Playlists, create a playlist and add tracks. Assign that playlist to a club and save the club. At its DJ booth, load an assigned track into deck A or B and test playback.
The fixed festival is configured separately from your own clubs. For a new custom club, place its DJ booth and at least one speaker before saving. Music synchronization is optional and starts disabled; ordinary playback does not require it.
Standard MP3 delivery
In the default mode, FiveM downloads the MP3s published in the owning resource's manifest when players connect. No external webserver is required.
- Use at most 500 MP3 files in the selected directory. Subfolders are not scanned.
- Keep each file below 50 MiB. Names may contain ASCII letters, numbers, spaces, underscores, hyphens and periods, must start with a letter, number, underscore or hyphen, and must end in lowercase
.mp3. Maximum length is 160 characters;..is rejected. - Keep paths and filename capitalization consistent, especially on Linux. Folder paths use forward slashes.
- Upload files through your server's file manager or SFTP. The in-game library does not upload audio files.
- Restart the resource owning the music after adding or replacing files.
To keep music in a separate resource, create resources/[music]/sky_dj_music/music/ and put this manifest beside its music folder:
fx_version 'cerulean'
game 'gta5'
files { 'music/*.mp3' }
Start sky_dj_music before sky_dj, then set Music folder to @sky_dj_music/music under Settings → Music & Playlists → Library & Queues. In file mode, use Config.MusicDirectory = '@sky_dj_music/music' instead.
This MP3 resource must not be server_only. A custom folder inside sky_dj also needs a matching manifest files entry. Absolute Windows/Linux paths and symlinked folders are not supported as runtime music sources.
Optional HTTPS Opus delivery
This mode keeps the files on your server but delivers audio through a separate HTTPS webserver. Players request a track when it is loaded or buffered, rather than downloading the selected library through the FiveM connection packfile. Normal browser buffering and caching still apply.
The flow is original MP3 → offline FFmpeg export → private server catalogue + HTTPS .opus files. FXServer does not launch FFmpeg or the external Node.js executable for playback. You can prepare the export on another computer and copy the complete result to the server.
files, client_script, shared_script or stream entries. MP3s left in config/music/*.mp3, or published by another resource, still download on connection.1. Install the preparation tools
Use a supported Node.js LTS release and FFmpeg with its libopus encoder. No npm packages are needed.
winget install --id OpenJS.NodeJS.LTS --exact --source winget
winget install --id Gyan.FFmpeg --exact --source winget
# Open a new PowerShell window after installation.
node --version
ffmpeg -hide_banner -encoders | Select-String 'libopus'
# Install a supported Node.js LTS release using the Node.js download instructions.
sudo apt update
sudo apt install ffmpeg
node --version
ffmpeg -hide_banner -encoders | grep 'libopus'
The Windows commands use WinGet's exact package selection. If WinGet is unavailable on your Windows installation, use the Node.js installer and a Windows build linked from the FFmpeg download page, then make ffmpeg available on PATH.
On Windows, the preparation tool also detects an ordinary ffmpeg.exe beside prepare-music-stream.cjs. On Linux, install ffmpeg on PATH or pass its executable with --ffmpeg.
2. Prepare the export
For automatic paths, retain the extracted package layout:
Sky-DJ-package/
├── prepare-music-stream.cjs
└── resources/
└── [sky]/
└── sky_dj/
├── fxmanifest.lua
└── config/
└── music/
Place the original MP3s in that config/music/ directory and run the helper from the package root:
Set-Location -LiteralPath 'D:\Sky-DJ-package'
node '.\prepare-music-stream.cjs'
cd '/opt/sky-dj-package'
node './prepare-music-stream.cjs'
The helper reads config/music/ and creates config/music-stream/ beside it. It writes 48 kHz stereo Ogg Opus at 128 kbit/s VBR, with SHA-256 filenames and a music-stream.json catalogue. The original MP3 filenames remain the playlist IDs. Original audio is not modified or deleted. The helper runs outside the resource and does not need to modify or decrypt its Lua core.
Automatic discovery supports this package layout and the development checkout's tools/ location. It does not search arbitrary server directories. If you moved only the runtime resource, keep the original package for preparation or provide both paths explicitly:
node 'D:\Sky-DJ-package\prepare-music-stream.cjs' --input 'D:\Music\Originals' --output 'D:\FXServer\server-data\resources\[sky]\sky_dj\config\music-stream'
node '/opt/sky-dj-package/prepare-music-stream.cjs' --input '/srv/music-originals' --output '/opt/fivem/server-data/resources/[sky]/sky_dj/config/music-stream'
Input and output must be separate, non-nested directories without symlinks. A failed conversion leaves the previous catalogue active; unchanged sources reuse verified exports.
Copy the complete generated folder, including music-stream.json and every referenced .opus file, to the matching sky_dj/config/music-stream/ on FXServer. If you prepared music in the live resource, move its original MP3 copies out of client-published locations after backing them up.
With Music folder left at config/music, enabling HTTPS automatically selects config/music-stream. A custom music-folder value remains an explicit override. For a separate streaming resource, place the complete export in sky_dj_music/music/, use @sky_dj_music/music, and replace the earlier MP3 manifest with:
fx_version 'cerulean'
game 'gta5'
server_only 'yes'
Start this resource before sky_dj. Keep the complete catalogue on FXServer even when another machine hosts the public audio. Do not add client files entries to this streaming-only resource.
3. Serve the files with Caddy
The following manual examples use a dedicated audio.example.com hostname on the same machine as FXServer. Point its public DNS records at that machine, make TCP ports 80 and 443 reachable, and use your real hostname. Caddy manages certificates for an eligible public hostname; see its HTTPS prerequisites.
Install Caddy using its official Windows binary or Debian/Ubuntu package instructions. For Debian/Ubuntu, follow the signed repository setup on that page; the official package installs the caddy systemd service. These examples do not install or configure Caddy automatically.
Use one of these hostname blocks in your Caddyfile. Replace the domain and export path. If you already host other sites, retain their existing configuration.
audio.example.com {
header {
Access-Control-Allow-Origin "*"
Access-Control-Allow-Methods "GET, HEAD, OPTIONS"
Access-Control-Allow-Headers "Range"
Access-Control-Expose-Headers "Accept-Ranges, Content-Length, Content-Range"
}
@preflight method OPTIONS
handle @preflight {
respond "" 204
}
@audio path /music/*.opus
handle @audio {
uri strip_prefix /music
root * "D:/FXServer/server-data/resources/[sky]/sky_dj/config/music-stream"
header Content-Type "audio/ogg; codecs=opus"
file_server
}
handle {
respond "Not found" 404
}
handle_errors {
header Access-Control-Allow-Origin "*"
respond "{err.status_code}" {err.status_code}
}
}
audio.example.com {
header {
Access-Control-Allow-Origin "*"
Access-Control-Allow-Methods "GET, HEAD, OPTIONS"
Access-Control-Allow-Headers "Range"
Access-Control-Expose-Headers "Accept-Ranges, Content-Length, Content-Range"
}
@preflight method OPTIONS
handle @preflight {
respond "" 204
}
@audio path /music/*.opus
handle @audio {
uri strip_prefix /music
root * "/opt/fivem/server-data/resources/[sky]/sky_dj/config/music-stream"
header Content-Type "audio/ogg; codecs=opus"
file_server
}
handle {
respond "Not found" 404
}
handle_errors {
header Access-Control-Allow-Origin "*"
respond "{err.status_code}" {err.status_code}
}
}
The webserver account must be able to read the exported files and traverse their parent directories. The examples expose only matching .opus URLs; music-stream.json, configuration files and directory browsing remain unavailable. See Caddy's file server, response headers and error handling references.
Validate the configuration, then run or reload Caddy:
& 'C:\Caddy\caddy.exe' validate --config 'C:\Caddy\Caddyfile' --adapter caddyfile
& 'C:\Caddy\caddy.exe' run --config 'C:\Caddy\Caddyfile' --adapter caddyfile
sudo caddy validate --config '/etc/caddy/Caddyfile' --adapter caddyfile
sudo systemctl reload caddy
The Windows run command stays in the foreground for initial verification. For permanent hosting, install a Windows service using Caddy's service instructions; a foreground terminal is not a service. On Linux, use the official package's systemd service. Command behavior is documented in the Caddy CLI reference.
4. Verify HTTPS and enable streaming
Choose an actual 64-character .opus filename from the export and replace YOUR_HASH below. Test from outside the server's local network:
curl.exe -sS -D - -o NUL -H 'Origin: https://cfx-nui-sky_dj' -H 'Range: bytes=0-1023' 'https://audio.example.com/music/YOUR_HASH.opus'
curl -sS -D - -o /dev/null -H 'Origin: https://cfx-nui-sky_dj' -H 'Range: bytes=0-1023' 'https://audio.example.com/music/YOUR_HASH.opus'
Expect a valid public TLS certificate, 206 Partial Content, Content-Range, Accept-Ranges: bytes, the Opus-compatible content type and Access-Control-Allow-Origin: *. Keep CORS headers on partial and error responses. The endpoint must work without login, cookies or authentication. A track playing in an ordinary browser tab alone does not prove that cross-origin WebAudio and music analysis will work.
With the default SQL configuration, open /djadmin → Settings → Music & Playlists → Library & Queues:
| Setting | Default-path setup |
|---|---|
| Music folder | Leave config/music; HTTPS selects config/music-stream automatically |
| HTTPS music folder URL | https://audio.example.com/music/ |
| HTTPS music streaming | Enable, confirm Are you sure?, then save |
Cancel or Escape leaves the switch disabled. A new enable also requires the acknowledgement on the server; an already saved enabled setup does not ask again on restart.
For file-owned configuration, edit these existing entries in config/config.lua, then restart sky_dj:
IngameSettings = false,
MusicDirectory = 'config/music',
MusicStreamingEnabled = true,
MusicStreamingBaseUrl = 'https://audio.example.com/music/',
The URL must be an HTTPS folder address without credentials, query parameters, fragments or traversal. The system appends the generated .opus filename. For a custom streaming resource, use MusicDirectory = '@sky_dj_music/music' instead.
Restart the resource owning the export after publishing changes. Reload tracks already on the decks so they use the new delivery URL. Missing or invalid exports make the catalogue unavailable; the system does not silently fall back to a downloaded MP3 library. Keeping the original MP3 filename IDs preserves playlist entries and club assignments when switching delivery.
Final check and updates
Test playback, seeking, A/B transitions and music synchronization from two FiveM clients. In private HTTPS mode, verify that neither the exported audio nor published copies of the original MP3s remain in FiveM's connection download. Confirm saved settings and club assignments after restarting.
Before updating, back up config/, your music/export folders and the sky_dj_state database table. Replace the complete published runtime together so Lua, NUI and streamed assets match. Keep a custom music resource separate from the runtime replacement. After a map update, fully exit and relaunch FiveM before checking streaming and collision.
Continue with Overview and Configuration. For missing tracks, connection downloads, playback or access errors, use Troubleshooting.