Browse docs

Installation

Install the resource, add your music library, and optionally prepare FFmpeg/Opus streaming with Windows or Linux instructions.

Requirements

RequirementPurpose
FiveM server with OneSync enabledShared club state, routing buckets and server-side position checks
ESX with RunStaticPlayerMethod supportPlayer access and framework integration
ox_libCallbacks and shared utilities
sky_base with a working database connectionFramework bridge, interactions and automatic SQL persistence
Optional ox_targetTarget 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.

server.cfg
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:

sky_dj_music/fxmanifest.lua — standard MP3 mode
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

Advanced setup: only continue if you know what you are doing. You must understand HTTPS certificates, webserver file access, CORS and client-download exclusions. Incorrect configuration can stop music playback or expose files you did not intend to publish. If you are unsure, keep standard MP3 delivery until someone experienced can configure and verify the streaming host.

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.

Converting the files or switching on HTTPS does not remove existing client downloads. Back up your original MP3s, then remove or move their client-published copies. Do not include the export in any client 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'

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'

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'

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:

sky_dj_music/fxmanifest.lua — HTTPS mode only
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}
    }
}

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

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'

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:

SettingDefault-path setup
Music folderLeave config/music; HTTPS selects config/music-stream automatically
HTTPS music folder URLhttps://audio.example.com/music/
HTTPS music streamingEnable, 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:

config/config.lua — existing Config entries
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.