8.7 KiB
Secure Runtime Production Setup
Quick setup guide for running Nitro with:
- configuration and gamedata served through
/nitro-sec/file; - encrypted runtime
/api/*calls; - obfuscated production bundles loaded as
.dat.
Replace the example domains with your real domains:
https://hotel.example.comhttps://nitro.example.com:2096
1. Build Nitro
Inside the Nitro-V3 repository:
yarn build
Then publish the dist folder to your web server, for example:
C:/inetpub/wwwroot/hotel/nitro
The deployed folder should contain at least:
configuration/
assets/
asset-loader.js
index.html
src/
2. configuration/client-mode.json
File:
Nitro-V3/dist/configuration/client-mode.json
Secure production configuration:
{
"distObfuscationEnabled": true,
"secureAssetsEnabled": true,
"secureApiEnabled": true,
"apiBaseUrl": "https://nitro.example.com:2096",
"plainConfigBaseUrl": "https://hotel.example.com/configuration/",
"plainGamedataBaseUrl": "https://hotel.example.com/client/nitro/gamedata/"
}
Meaning:
distObfuscationEnabled: trueloadsapp.js.datandapp.css.dat.secureAssetsEnabled: trueloadsrenderer-config.json,ui-config.json, and gamedata through/nitro-sec/file.secureApiEnabled: trueautomatically encrypts/api/*requests.apiBaseUrlmust point to the emulator/API.plainConfigBaseUrlandplainGamedataBaseUrlare fallbacks when secure assets are disabled.
3. configuration/renderer-config.json
File:
Nitro-V3/dist/configuration/renderer-config.json
Important values:
{
"socket.url": "wss://nitro.example.com:2096",
"api.url": "https://nitro.example.com:2096",
"gamedata.url": "https://nitro.example.com:2096/nitro-sec/file?kind=gamedata&file=",
"external.texts.url": [
"${gamedata.url}/ExternalTexts.json",
"${gamedata.url}/UITexts.json"
],
"furnidata.url": "${gamedata.url}/FurnitureData.json?t=%timestamp%",
"productdata.url": "${gamedata.url}/ProductData.json?t=%timestamp%",
"avatar.actions.url": "${gamedata.url}/HabboAvatarActions.json?t=%timestamp%",
"avatar.figuredata.url": "${gamedata.url}/FigureData.json?t=%timestamp%",
"avatar.figuremap.url": "${gamedata.url}/FigureMap.json?t=%timestamp%",
"avatar.effectmap.url": "${gamedata.url}/EffectMap.json?t=%timestamp%",
"crypto.ws.enabled": true
}
If you are not using WebSocket crypto yet, use:
"crypto.ws.enabled": false
4. configuration/ui-config.json
File:
Nitro-V3/dist/configuration/ui-config.json
Static image and camera URLs can remain plain:
{
"camera.url": "https://hotel.example.com/client/camera/",
"thumbnails.url": "https://hotel.example.com/client/camera/thumbnail/%thumbnail%.png"
}
Non-sensitive images can stay static. JSON configuration and gamedata should go through the secure endpoint.
5. Emulator config.ini
Inside Arcturus-Morningstar-Extended, edit the emulator config:
Emulator/config.ini
Production example:
ws.enabled=true
ws.host=0.0.0.0
ws.port=2096
ws.whitelist=https://hotel.example.com
ws.ip.header=CF-Connecting-IP
crypto.ws.enabled=1
nitro.secure.assets.enabled=true
nitro.secure.api.enabled=true
nitro.secure.config.root=C:/inetpub/wwwroot/hotel/nitro/configuration
nitro.secure.gamedata.root=C:/inetpub/wwwroot/hotel/nitro/client/nitro/gamedata
nitro.secure.master_key=change-this-to-a-long-random-secret
login.remember.enabled=true
login.remember.duration.days=30
login.remember.jwt.secret=change-this-too-if-you-use-remember-me
Notes:
nitro.secure.config.rootmust point to the folder containingrenderer-config.json,ui-config.json, andclient-mode.json.nitro.secure.gamedata.rootmust point to the live gamedata folder.- Files are read live from disk: if you update a JSON file, a new browser refresh reads the new version.
nitro.secure.master_keymust be secret and stable. Never put it in public files.
6. Cloudflare
If you use Cloudflare:
- Keep the proxy enabled for the website domain
hotel.example.com. - Make sure Cloudflare supports/proxies the port used by
nitro.example.com:2096. - Always use HTTPS/WSS in the browser:
"api.url": "https://nitro.example.com:2096",
"socket.url": "wss://nitro.example.com:2096"
If you get CORS errors, check:
ws.whitelist=https://hotel.example.com
7. IIS / .dat MIME type
If obfuscated .dat assets are enabled, IIS must serve them correctly.
Add this MIME type:
Extension: .dat
MIME type: application/octet-stream
Without it, the browser can receive 404 even when the file exists.
8. Final checklist
client-mode.jsonhassecureAssetsEnabled=true.client-mode.jsonhassecureApiEnabled=true.renderer-config.jsonuses/nitro-sec/file?kind=gamedata&file=.api.urlpoints tohttps://nitro.example.com:2096.socket.urlpoints towss://nitro.example.com:2096.config.inihas the correctnitro.secure.config.root.config.inihas the correctnitro.secure.gamedata.root.config.inihas a stablenitro.secure.master_key.- IIS knows the
.datMIME type. - Restart the emulator after changing
config.ini. - Refresh the browser after changing JSON files in
configurationorgamedata.
9. Temporarily disable secure mode
For quick debugging, only change client-mode.json:
{
"distObfuscationEnabled": false,
"secureAssetsEnabled": false,
"secureApiEnabled": false,
"apiBaseUrl": "https://nitro.example.com:2096",
"plainConfigBaseUrl": "https://hotel.example.com/configuration/",
"plainGamedataBaseUrl": "https://hotel.example.com/client/nitro/gamedata/"
}
Then hard refresh the browser.
10. configuration/bootstrap.js
File:
Nitro-V3/dist/configuration/bootstrap.js
This is the first loader when you use the external secure mode.
It does three things:
- opens an ECDH session with the emulator through
/nitro-sec/bootstrap; - downloads encrypted
client-mode.jsonthrough/nitro-sec/file?kind=config; - downloads encrypted
asset-loader.jsand imports it as a JavaScript module.
Value to check
Inside bootstrap.js there is:
const API_BASE = "https://nitro.example.com:2096";
It must point to your public emulator/API URL.
In production:
const API_BASE = "https://nitro.example.com:2096";
In local development:
const API_BASE = "http://localhost:2096";
If bootstrap.js fails, it automatically falls back to the plain loader:
configuration/asset-loader.js
So asset-loader.js must always exist inside the configuration folder.
11. configuration/asset-loader.js
File:
Nitro-V3/dist/configuration/asset-loader.js
This loader loads the actual bundle:
-
if
distObfuscationEnabled=true- it loads
app.css.dat; - it loads
app.js.dat; - it decodes, decompresses, and imports the bundle from a blob.
- it loads
-
if
distObfuscationEnabled=false- it loads
assets/app.css; - it loads
assets/app.js.
- it loads
Required files in production
With obfuscation enabled, these files must exist:
assets/app.css.dat
assets/app.js.dat
configuration/asset-loader.js
configuration/bootstrap.js
configuration/client-mode.json
With obfuscation disabled, these files must exist:
assets/app.css
assets/app.js
configuration/asset-loader.js
configuration/client-mode.json
12. index.html
index.html should stay minimal.
Secure production example:
<div id="root"></div>
<script src="/configuration/bootstrap.js"></script>
Vite development example:
<div id="root"></div>
<script type="module" src="/src/bootstrap.ts"></script>
Do not mix the two flows:
- production build: use
configuration/bootstrap.js; yarn startdevelopment: use/src/bootstrap.ts.
13. Files inside /configuration
The configuration folder should contain:
asset-loader.js
bootstrap.js
client-mode.json
renderer-config.json
ui-config.json
adsense.json optional
hotlooks.json if register hot looks are enabled
UITexts.json if separate UI texts are enabled
Login news should not live in news.json in production. They come from the database through:
"login.news.url": "${api.url}/api/auth/news"
The emulator reads from the ui_news table.
With secureAssetsEnabled=true, client-loaded files go through:
https://nitro.example.com:2096/nitro-sec/file?kind=config&file=...
The emulator reads them from:
nitro.secure.config.root=C:/inetpub/wwwroot/hotel/nitro/configuration
If you add new JSON/JS files inside configuration and want to protect them, they must be requested through the secure endpoint or loaded through bootstrap.js.