Skip to content

SKYMP WORLDS · Server operator handbook

Connect your server. Keep your world.

A technical guide for independent SkyMP servers: registration, downloads, client packages, authentication and operation with the shared launcher.

Launcher 0.2.0 · Updated 2026-10-22

01Integrate an existing serverCheck the interfaces and prerequisites, add the required parts and test your own installation.02Use the SkyMP forkUse the linked source as a starting point and verify its launcher interfaces.
01

Scope & compatibility

#

This handbook describes the shared SkyMP Worlds launcher 0.2.0 and the interfaces checked on 2026-10-22. You can extend an existing compatible SkyMP server or use the RealHartlMax/SkyMP fork as a starting point. Registering with the launcher does not automatically migrate player data or the game world.

There is no compatibility guarantee. A server listing, a successfully loaded manifest or a successful build does not prove that a game session works. The game protocol, server, native client, Skyrim version, SKSE, Address Library, mods and load order must match. Adding HTTP routes does not make another multiplayer mod compatible with SkyMP.

Test changes on a separate installation first. Back up server settings, world data, accounts and keys before switching. Examples contain recognizable placeholders; file sizes, CRC32 and SHA-256 must be generated from your actual files.

↑ Back to top
02

How the services work together

#
ComponentAddress / protocolPurpose
Central listhttps://api.skymp-worlds.net/list.phpDiscover servers; fixed in the launcher
Operator accounthttps://manage.skymp-worlds.net/Register servers and manage metadata and private keys
Online masterhttps://api.skymp-worlds.netAuthentication, heartbeats and game sessions
Your game serverPublic host and UDP port, for example 7777Actual game connection
Your file serverPublic HTTP(S) base, for example https://files.example.org/Mod manifest and downloads
Client catalogFull URL to catalog.jsonSelect a matching native client / SKSE combination

The game address, file server and master are separate destinations. resourceUrl is the file server base, not the URL of its manifest route. In contrast, runtimeSource is a full catalog or client manifest URL. The launcher prepares files and then starts the SKSE loader from the selected game directory.

↑ Back to top
03

Route A: Use the linked fork

#
  1. Use the RealHartlMax fork. Check the chosen commit or specific release; an arbitrary upstream package does not necessarily include the same launcher extensions.
  2. For your own build, follow the fork's CMake workflow and CONTRIBUTING.md. Replace a running installation only after backup and testing.
  3. Build output normally places the server in build/dist/server and the Windows client in build/dist/client. Prepared server packages start through launch_server.bat or launch_server.sh. The fork's server guide describes the required runtime and initial setup.
  4. Supply your own Skyrim / DLC master files in the configured dataDir. Server packages do not replace your own Skyrim installation. Preserve an existing compatible load order.
  5. Register the server, add the connection settings, publish mods and a matching client package, and complete the validation steps.

Create a separate source checkout:

sh
git clone https://github.com/RealHartlMax/skymp.git skymp-server-source
cd skymp-server-source

Cloning does not build or start the server. The launcher extension mainly involves skymp5-server/ts/launcherResources.ts, its registration in ui.ts, and the master / login systems. The published mod routes were compared with the local source; this does not validate your own binaries. Local unpublished client changes do not become available simply by linking the repository.

↑ Back to top
04

Route B: Integrate an existing server

#

Extend your current server deliberately. The shared launcher changes neither your gamemode logic nor your database format. A different implementation may need additional adjustments.

RequirementWhat you must supply or check
Game protocolA UDP server compatible with the native SkyMP client in use
Connection settingsPublic game host, game port, file base URL, authentication mode and client source
Mod deliveryPrefer manifest v2 and verifiable downloads; alternatively the limited legacy contract
Online authenticationMaster heartbeats and server-side session validation according to the authentication contract
Client runtimeComplete client files matching the game and server; a catalog for automatic version selection
EvidenceAPI, download and restoration checks, followed by actual gameplay tests

The fork implements modern mod delivery as a separate resource component with explicit settings. Copying its file alone is insufficient: the HTTP router must register it, pass the real source directories and load order, and return appropriate errors. Another server stack can implement the same contract. JSON field names and download rules remain binding.

An existing server can still be opened through Direct connection for initial tests. Public name search additionally requires registration and a valid heartbeat. A public listing does not confirm technical compatibility.

↑ Back to top
05

Account, listing & public identity

#
  1. Create a regular account in the operator dashboard and confirm your email address if required. Demo accounts are not used for game logins.
  2. Add your server with a public host, UDP game port and player limit. Select status active when it should be publicly available.
  3. Open Launcher & online authentication for the entry. Enter the public file server base and full client catalog URL. Description, tags, country, gamemode, banner, logo and your own community links are public profile data.
  4. Copy the displayed public server ID and private API key into the server settings. Then restart the server cleanly.
  5. It appears in the central list after an accepted heartbeat. An empty response [] is normal when there are no active entries. The PHP master hides entries without a valid heartbeat after about five minutes.
ValueVisibilityUse
serverUidPublicStable ID for selection and game sessions
masterKey in server-settings.jsonPrivateAuthenticates your server to the master
masterKey in the public listingPublicHistorical field name; the current PHP master puts the public server ID here
Login token / game sessionPrivateTime-limited user or server authentication

Never publish the private heartbeat key as a description, tag or download. It does not belong in the player's launcher profile. Rotate keys through the dashboard, then update the private server settings and restart the server.

↑ Back to top
06

Extend your existing server settings

#

This JSON is a merge example, not a complete replacement configuration. Keep your server's gamemode, data paths, world data, other settings and complete correct load order. Replace the public ID and private key with those of your own entry.

json
{
  "port": 7777,
  "uiPort": 8080,
  "listenHost": "0.0.0.0",
  "uiListenHost": "0.0.0.0",
  "master": "https://api.skymp-worlds.net",
  "serverUid": "srv_REPLACE_WITH_PUBLIC_ID",
  "masterKey": "REPLACE_WITH_PRIVATE_SERVER_KEY",
  "offlineMode": false,
  "launcherResources": {
    "enabled": true,
    "directory": "./client-resources",
    "runtimeSource": "https://update.skymp-worlds.net/client-runtime/catalog.json"
  }
}

The fork resolves launcherResources.directory relative to the server process working directory. Start it from the intended package directory or deliberately choose an absolute path. Without explicit settings, mod delivery is enabled and uses ./client-resources. Set enabled: false to disable the new mod API.

The catalog on the update domain must actually be uploaded and suitable for your client / server combination. Its URL is not a promise of support for every Skyrim version. You can provide your own complete catalog.json instead. Keep the server manifest and dashboard consistent; changes to download settings require a new heartbeat.

↑ Back to top
07

Connectivity, TLS & reverse proxies

#
ConnectionTypical accessCheck
Game client → game server7777/UDP or your game portFirewall, NAT and public game address
Launcher → file server443/TCP with HTTPS or a direct HTTP portAnonymous access to manifest and files
Game server → masterOutbound 443/TCPDNS, TLS certificate and heartbeats
Player → dashboard / masterHTTPSLogin, consent and session creation

PHP hosting can serve the dashboard, master gateway, documentation and static downloads. It cannot replace a continuously running native game server. An ordinary HTTP reverse proxy does not automatically forward the UDP game port.

For a proxy, use the final public base URL, for example https://files.example.org/realm/. Both api/launcher/manifest and the relative download routes must be accessible under that prefix. The launcher follows no HTTP redirects for manifests or files. Enter the final HTTPS address with a matching hostname; login pages, Basic Auth and redirects are not public downloads.

Download / catalog URLs must contain no credentials, query parameters or fragments. The public PHP master rejects private, loopback and link-local destinations, including DNS resolutions to them. 127.0.0.1 refers to the player's own computer from their perspective. Use a direct local connection during development; do not publish internal addresses in the production profile. Launcher file requests run in the Rust backend and need no browser CORS permission.

↑ Back to top
08

Publish mods, assets & load order

#
text
server-settings.json
data/
  Skyrim.esm
  World.esp
  World.bsa
client-resources/
  Data/
    World - Textures.bsa
    Scripts/WorldClient.pex
    meshes/World/sword.nif
    textures/World/sword.dds
    SKSE/Plugins/World.ini

The fork automatically includes custom plugins from loadOrder and matching NAME.bsa or NAME - *.bsa archives from dataDir. Place additional client files under client-resources/Data/ with their final directory structure. This does not automatically distribute server-side scripts from data/scripts/ as client scripts.

All additional .esm, .esp and .esl plugins must appear in the actual server load order. If a plugin exists in both the data and resource directories, both copies must match. Plugins and BSA archives belong directly under Data/; textures, models and scripts keep their subdirectories. Restart the server after load order changes. The resource index uses a short metadata cache of about two seconds.

kindAllowed mod package content
mod.esm, .esp, .esl
archive.bsa
scriptCompiled .pex under Data/Scripts/
assetSupported models, textures, animations, audio, interface, language and image files
configPassive .ini, .json, .xml, .txt, .toml, .yaml, .yml

Native DLLs and JavaScript belong in the separate client package. Protected platform / authentication files, Bethesda masters and Creation Club files are not offered as mod downloads. Path traversal, symlinks / junctions, Windows device names, colons, trailing dots / spaces and destination paths differing only by letter case are rejected. The new mod API limits destination paths to 240 UTF-8 bytes.

ZIP / 7z / FOMOD packages are not unpacked or interactively installed on the player's computer. Prepare the required mod selection yourself and publish only the required files intended for redistribution. Skyrim / DLC files must come from the player's matching installation.

↑ Back to top
09

Manifest v2: Contract for custom implementations

#

GET <resourceUrl>/api/launcher/manifest returns JSON without an operator login, with version as the string "2". Numbers and checksums in the following structural example are illustrative, not an actual playable release. Your server must compute them from real files.

json
{
  "version": "2",
  "revision": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "generatedAt": "2026-10-21T12:00:00.000Z",
  "totalSize": 12345,
  "loadOrder": ["Skyrim.esm", "World.esp"],
  "requiredLocalFiles": [
    { "filename": "Skyrim.esm", "size": 249753412, "crc32": 123456789 }
  ],
  "runtimeSource": "https://update.skymp-worlds.net/client-runtime/catalog.json",
  "resources": [
    {
      "name": "World.esp",
      "path": "Data/World.esp",
      "kind": "mod",
      "size": 12345,
      "hash": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
      "downloadPath": "api/launcher/files/1111111111111111111111111111111111111111111111111111111111111111"
    }
  ]
}
FieldMeaning
loadOrderNon-empty ordered plugin list; do not infer names from directories
requiredLocalFilesLocal Bethesda / Creation Club requirements with filename, byte size and CRC32; no download URLs
resources[].pathUnique destination relative to the game directory, starting with Data/
nameDisplay filename; may repeat in different asset directories
sizeExact byte count as a JSON number
hashsha256: followed by 64 hexadecimal characters of the actual content
downloadPathRelative api/launcher/files/ route with an opaque 64-character hexadecimal ID
totalSizeTotal mod resource size; excludes the separate client package
revision, generatedAtRelease identity and creation time
runtimeSourceOptional full client catalog / manifest link

A generator must validate approved source roots, reject links, normalize destination paths according to Windows rules, detect duplicates, and derive size / SHA-256 from the content read. CRC32 applies to local game requirements; it does not replace SHA-256 for downloads. Do not return conflicting metadata when files disappear or change during publication. An error is preferable to an incomplete successful listing.

Current limits: at most 10,000 mod files, 8 GiB per file, 64 GiB per mod package; the launcher limits JSON manifests to 8 MiB. A custom implementation must enforce matching limits and protected destination paths.

↑ Back to top
10

Download endpoints & HTTP responses

#

GET or HEAD <resourceUrl>/api/launcher/files/<id> must serve the file announced in the manifest. A resource ID identifies an approved file; never interpret it as an arbitrary filesystem path. A separate file host is possible if the manifest and all relative routes remain accessible under its base.

ResponseFork behavior / meaning
200Complete file, correct Content-Length; HEAD has no response body
206Supported single byte range with Content-Range
304If-None-Match matches the ETag
400Invalid resource ID
404API disabled or ID from an older revision no longer present
409File changed since indexing; fetch the manifest again
416Invalid byte range
503Incomplete, unreadable or inconsistent publication

The fork also sends X-Resource-Hash, ETag and Accept-Ranges: bytes. Immutable file IDs may be cached long term; the manifest must stay current. The launcher checks downloaded data against size and SHA-256 independently of HTTP headers. It requires complete downloads; HTTP range support does not promise that this launcher version resumes interrupted downloads.

↑ Back to top
11

Older servers: Legacy contract

#

Only HTTP 404 from /api/launcher/manifest permits fallback to /api/resources/manifest and /manifest.json. A 503, an invalid v2 response or a checksum mismatch is not silently bypassed using legacy mode.

The older resource contract uses version: "1", flat filenames and downloads through /api/resources/download/<name>. It cannot fully describe subdirectories in modern asset packages. The additional game manifest has the following structure, for example; these numbers are also placeholders:

json
{
  "versionMajor": 1,
  "mods": [
    { "filename": "Skyrim.esm", "size": 249753412, "crc32": 123456789 }
  ],
  "loadOrder": ["Skyrim.esm"]
}

Without a resource API, this only works when every required file is already present locally and matches the published size / CRC32. It does not repair an old blanket .esm restriction or a missing download for custom plugins. Use v2 for new integrations and structured mod packages.

↑ Back to top
12

Publish the client, SKSE & Address Library

#

The launcher EXE contains no SkyMP / SKSE DLLs. Publish a matching client combination separately. runtimeSource may point to one runtime-manifest.json or to a catalog.json containing multiple approved Skyrim versions. The catalog chooses the exact matching entry from the actual file version of SkyrimSE.exe; it does not install another supposedly newer game version as a substitute.

Catalog example with a relative manifest address; replace the illustrative SHA-256 with the hash of the exact manifest file:

json
{
  "version": 2,
  "packages": [
    {
      "gameVersion": "1.7.104.0",
      "manifest": "1.7.104.0/client-release/runtime-manifest.json",
      "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    }
  ]
}

The selected client manifest uses numeric version: 1, gameVersion, skseVersion and files. Every file has path, size and a SHA-256 without the sha256: prefix. A complete versioned package requires at least these core paths; include all additional runtime, CEF and script files from the finished client as well:

text
Data/SKSE/Plugins/SkyrimPlatform.dll
Data/SKSE/Plugins/MpClientPlugin.dll
Data/Platform/Plugins/skymp5-client.js
Data/Platform/Distribution/RuntimeDependencies/SkyrimPlatformImpl.dll
skse64_loader.exe
skse64_1_7_104.dll
Data/SKSE/Plugins/versionlib-1-7-104-0.bin

These seven names illustrate Skyrim 1.7.104.0 with SKSE 2.3.1; they are not a complete file list or a general guarantee. Other game versions need their corresponding files and native support. In the checked versions, Address Library uses format 1 for the 1.5 branch, format 2 for 1.6, and format 5 for 1.7. A new Address Library does not automatically make an old incompatible plugin DLL compatible.

Generate packages using tools from the launcher repository, not from the server directory. The following PowerShell commands assume a finished client build, the extracted matching SKSE archive and the correct address file:

powershell
node launcher/scripts/create-runtime-manifest.mjs `
  --source C:/Build/skymp/build/dist/client `
  --output C:/Publish/client-runtime/1.7.104.0/client-release `
  --game-version 1.7.104.0 `
  --skse-version 2.3.1 `
  --skse-source C:/Packages/skse64_2_03_01 `
  --address-library C:/Packages/AddressLibrary/SKSE/Plugins/versionlib-1-7-104-0.bin

node launcher/scripts/create-runtime-catalog.mjs `
  --root C:/Publish/client-runtime `
  --manifest 1.7.104.0/client-release/runtime-manifest.json

The package output directory must be new. Repeat --manifest for additional game versions; each version may have exactly one current catalog entry, with at most 512 entries in total. Use --replace to deliberately replace an existing catalog. Upload complete new package directories first, and switch the catalog last. The catalog is revalidated; matching file hashes are reused from cache.

The tool excludes personal connection settings, saved authentication and Bethesda files, and copies matching SKSE scripts and available SKSE documentation. Publish necessary licenses too. A client source explicitly chosen in the advanced launcher profile takes precedence; remove that manual choice to use automatic server offers. A local build source does not receive internet updates.

The usual destinations are relative to the game directory: Data/Platform/Plugins for client scripts, Data/SKSE/Plugins for native plugins and Address Library, and the game root for SKSE. The fork reads plugin directories from Data/SKSE/Plugins/SkyrimPlatform.ini; the default is Data/Platform/Plugins;Data/Platform/PluginsDev. Old files under Platform/Plugins without Data/ are not automatically used or managed by the launcher.

If both the server manifest and selected profile omit runtimeSource, the launcher can only use already installed client files; no automatic client update is being offered. Changes to offered client files are detected from the manifest and file hashes during the next preparation. Only missing or different files need downloading. Private authentication state and generated connection settings are excluded from client packages.

↑ Back to top
13

Online authentication & session contract

#

The central platform uses regular dashboard accounts, explicit game consent and server-bound sessions. offlineMode must match between the server and connection profile. Changing only the launcher to offline does not change server authentication.

Method and route on the masterPurpose
GET /api/users/login-discord?state=<64-hex>Take the browser to account / game login
GET /api/users/login-discord/status?state=<64-hex>Obtain a login token and numeric identity after consent; 401 beforehand
POST /api/users/me/play/<serverUid>Request a session for the public server ID using a login token
POST /api/servers/<privateMasterKey>Server heartbeat with, for example, online, maxPlayers and optional serverUid
GET /api/servers/<privateMasterKey>/sessions/<session>Validate a session on the game server; a valid response includes user.id and user.name
GET /api/servers/<serverUid>/manifest.jsonObtain the public game manifest through the master proxy
GET /api/servers/<serverUid>/serverinfoObtain public connection properties

POST /api/users/me/play/... passes the login token in the Authorization header; the PHP master also accepts the Bearer prefix. The response contains session. Only the game server uses its private key for heartbeats and session validation. Treat relevant server log lines and URL logs as confidential and remove keys before requesting support.

A session applies only to its intended server and current private key. Expiry, dashboard logout and key rotation can invalidate sessions. The server must reject invalid sessions. A new master must not reassign existing numeric game identities without a planned data migration.

The historical route name login-discord means no automatically configured Discord OAuth or guild checks on this PHP master. Additional Discord role / guild rules need a suitable real provider integration. The public community invitation is not an authentication provider. A separate compatible master can be configured for direct connections; a centrally registered server uses the master settings published in its central listing.

↑ Back to top
14

Validate before players join

#

Stage 1: Public HTTP interfaces

The PowerShell examples below use curl.exe to avoid the older PowerShell alias. On Linux, use curl with the same options. Replace files.example.org with your final public address.

powershell
curl.exe --fail-with-body https://api.skymp-worlds.net/health
curl.exe --fail-with-body https://api.skymp-worlds.net/list.php
curl.exe --fail-with-body https://files.example.org/api/launcher/manifest
curl.exe --fail-with-body https://update.skymp-worlds.net/client-runtime/catalog.json

Expect JSON responses without a login page or redirect. Check the public ID, file base, authentication mode, load order and client source. The private server key must not appear in the public list. Download at least one actual resource using its published ID and compare its local checksum with hash:

powershell
Get-FileHash -Algorithm SHA256 ./downloaded-file.bin

On Linux, use sha256sum ./downloaded-file.bin. Also verify that unknown IDs, changed files and invalid paths return meaningful errors and never expose arbitrary server files.

Stage 2: Preparation without starting the game

Choose a separate suitable test game directory containing SkyrimSE.exe. Close Skyrim. Open the server in the launcher, then Connection options and Prepare files. This does not start the game, but it does change the prepared test installation. Check subdirectories, complete client files, load order and generated connection settings. Prepare again: valid files should come from cache. Then test Restore original files and switching between two test profiles.

The launcher validates hashes and versions before activation. A wrong hash, unavailable package version or interrupted download must not activate an incomplete release. The launcher source also contains temporary HTTP / restoration tests and a test against a separate copy of the native server.

Stage 3: Your full gameplay test

Only now perform a real Skyrim / SKSE test with the intended version: startup, browser login and consent, session validation, UDP connection, shared world and reconnection. Check additional native plugins separately. Passing file or API checks does not replace this test. Record the actual server / client revision and mod package tested before offering it to players.

↑ Back to top
15

Updates, rollback & restoration

#

Publish new mod and client files as a coherent release. Keep load order, server data and client resources synchronized. For client updates, create new immutable package paths, upload all files and switch the catalog last. A catalog change does not replace a necessary server restart after plugin changes.

Launcher caches are separated by server target. Originals and the activation journal live under <Skyrim>/.skymp-launcher/. Plugin lists in the Skyrim profile and, where applicable, Skyrim.ccc are adjusted for the selected load order. Keep the journal while files are active; do not delete it as a supposed fix. Restoration may stop to protect your own changes to managed files.

Back up world data and server settings independently of the launcher before updates. The central PHP platform operator must preserve account storage and private authentication storage together with identity mappings and keys. Rolling back the client catalog changes only the offered client files; it does not automatically roll back a server / world data migration.

For a blocked or compromised server identity, rotate keys, update private settings and restart heartbeats. Support requests need only the public ID, timestamp, launcher / client / Skyrim versions and sanitized errors. Passwords, private master keys and sessions do not belong in Discord posts.

↑ Back to top
16

Troubleshoot specific failures

#
SymptomNext check
Heartbeat returns 404 with Server is not registered yetOld registry route: update the API webroot including api/servers/index.php and native-heartbeat.php together with the dashboard; preserve private settings and data
Server missing from name searchCheck active status, public address, valid private key and current heartbeat
New manifest route returns 404Check fork / router revision or enabled; only then is limited legacy fallback intended
Manifest returns 503Check server logs, source directories, links, duplicate destinations and an ongoing publication
Download returns 409 or a wrong hashFinish publication, obtain a new manifest and reindex actual contents and sizes
Master proxy returns 502Check public file URL, DNS / TLS, connectivity and excluded private destinations; remove redirects
Online session invalidDo not confuse public serverUid with private masterKey; check auth mode, key rotation, expiry and consent
/account or login route returns 404Check the API webroot, Apache rewrite / Authorization forwarding and master settings
Files ready but game cannot connectCheck UDP port, firewall / NAT, game protocol and actual server / client compatibility
REL/ID.h / Address Library errorIdentify the failing plugin DLL; check Skyrim version, SKSE, expected filename and native data format together
Latest address file exists but error remainsAn old DLL may request the wrong file or fail to parse the new format; update the DLL rather than rename the BIN file
Client files stay oldCheck manual client source in the advanced profile, the actual runtimeSource and catalog entry hash
Restoration refuses changesClose the game, back up external changes to managed files and preserve the journal; do not delete blindly

For help, use the SkyMP Worlds Discord. Resolving one loading failure does not prove that every other native plugin supports the game version.

↑ Back to top
17

Sources, revision & responsibility

#

This handbook was checked against launcher 0.2.0, the local server source based on commit a037003d57890b26ed21936ac2432c987aced878, and the published resource implementation in the linked fork. Updated 2026-10-22. Later commits, local extensions and other forks may differ. The combination present in the prepared client catalog is not a promise of support for other game versions; each release still requires a full gameplay test.

This web area is static and needs no Node process or database on the host. It does not automatically deploy the main site, dashboard, master, file host or game server. Each operator remains responsible for their tested server / client combination. No guarantee is given for integration with existing servers or arbitrary mod packages.

↑ Back to top