Server Setup
Introduction
The focus here is on Basis Server specific configuration and not the many ways you can host game servers in the cloud.
The multithreading on the server runs best the more cores avaiable but it has been shown to work well on as little as two cores. Social VR demands a lot of bandwidth so you'll want to keep that in mind when picking your service provider.
This doc applies to an Unmodified Basis Server: Version 6 from the LTS branch as of May 2025
You can find the ServerVersion in the code you cloned from the repo.
Client and server code must agree on the version.
BasisNetworkCore\BasisNetworkVersion.cs
5: public static ushort ServerVersion = 6;
Compile and Run on Windows
Assuming you have cloned the LTS branch of the repo.
git clone https://github.com/BasisVR/Basis.git
You will find the Visual Studio Solution file (sln) in the Basis Server
directory.
These steps assume Windows 11 using Microsoft Visual Studio Community 2022 (64-bit) - Version 17.12.3
The BasisNetworkConsole is the csproj you will need to target for compiling. You should be able to select that project from the start up item menu at the top. Once selected click the green arrow to build.
Once compiled, navigate to \Basis\Basis Server\BasisServerConsole\bin\Debug\net9.0\
to find the server exe and compiled dependencies.
To run the server on Windows locally, open a command shell in this directory and run .\BasisNetworkConsole.exe
\Basis\Basis Server\BasisServerConsole\bin\Debug\net9.0> .\BasisNetworkConsole.exe
This should open a console and show something like the following:
[20:07] [INFO] Logs are saved to C:\Basis\Basis Server\BasisServerConsole\bin\Debug\net9.0\Logs\2025-05-10.log
[20:07] [INFO] Server Booting
[20:07] [INFO] HTTP health check started at 'http://localhost:10666/health'
[20:07] [INFO] Loaded Admins 0
[20:07] [INFO] DidAuthIdentity initialized.
[20:07] [INFO] Server Wiring up SetPort 4296
[20:07] [INFO] Server Worker Threads Booted
[20:07] [INFO] CombinedURL: https://example.com/502c8e6c8405d50418.BEE, LoadAssetPassword: c661cfeaf9757e
[20:07] [INFO] Adding Object world
Be sure to point to localhost
when running the Basis Demo Client. The option is in the advanced panel when
you first start the client.
Compile and Run on Linux
Prerequisits Assuming Debian/Ubuntu
For Ubuntu 22.04,
sudo add-apt-repository ppa:dotnet/backports
For Debian or other qurirky setups:
wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
Then continue installation:
sudo apt-get update && sudo apt-get install -y dotnet-sdk-9.0
Get Basis
Change to the folder you wish to download Basis to, and execute the following command:
git clone https://github.com/BasisVR/Basis
Build Basis Server
Open a new terminal and cd /to/directory/with/Basis Server/, i.e. cd Basis/Basis\ Server
dotnet restore
Then build, with either:
dotnet build
(for debug)
or
dotnet build --configuration Release
(For release)
Executing
Navigate to the BasisServerConsole directory (Something like /BasisServerConsole/bin/Debug/net9.0/BasisNetworkConsole
)
and run:
dotnet .\BasisNetworkConsole.dll
You may compile with the following:
dotnet publish -f net9.0 --self-contained --os Linux
The --self-contained
switch is added to allow running on a OS without dotnet installed.
If you compile via this method (Or your build targeted the system) are on a you should be able to run
./BasisNetworkConsole
from BasisServerConsole/bin/Debug/net9.0/BasisNetworkConsole
.
Firewall
You may want to open ports:
- 1234/tcp
- 10666/tcp
- 4296/udp
Configuration Files
The first time you run the server a variety of config files and structure will be created in the directory the server exe rests in.
File/Folder | Description |
---|---|
config.xml | Main configuration file for the server. |
initialresources/ | this directory contains world and object files the server will load upon request. |
Log/ | Folder where server logs are stored. |
admins.xml | List of users with admin privileges. |
banned_players.xml | List of banned player accounts. |
Config.xml
Variable | Default | Description |
---|---|---|
PeerLimit | 1024 | Maximum number of players allowed on server. |
SetPort | 4296 | Network port the server listens on. |
QueueEvents | 10 | |
UseNativeSockets | true | LNL: Use system-native socket implementation |
NatPunchEnabled | true | LNL: Enable NAT punch-through |
PingInterval | 1500 | LNL: |
DisconnectTimeout | 5000 | LNL: Time to wait before disconnecting player |
SimulatePacketLoss | false | Simulate packet loss for testing. |
SimulateLatency | false | Simulate network latency. |
SimulationPacketLossChance | 10 | |
SimulationMinLatency | 50 | Minimum simulated latency. |
SimulationMaxLatency | 150 | Maximum simulated latency. |
UnsyncedEvents | false | |
UnsyncedReceiveEvent | false | |
UnsyncedDeliveryEvent | false | |
ReconnectDelay | 500 | Time before attempting reconnect. |
MaxConnectAttempts | 10 | Max number of reconnect attempts. |
ReuseAddress | true | |
DontRoute | false | |
EnableStatistics | true | LNL: |
IPv6Enabled | true | LNL: Enable IPv6 support. |
MtuOverride | 1500 | Override MTU (Maximum Transmission Unit). |
MtuDiscovery | true | Enable automatic MTU discovery. |
DisconnectOnUnreachable | true | Disconnect players if unreachable. |
AllowPeerAddressChange | true | LNL: Allow player clients to change IP address. |
UsingLoggingFile | true | Enable logging to file. |
HealthCheckHost | localhost | Hostname used for health checks. |
HealthCheckPort | 10666 | Port used for health checks. |
HealthPath | /health | Path to health check endpoint. |
BSRSMillisecondDefaultInterval | 50 | |
BSRBaseMultiplier | 1 | |
BSRSIncreaseRate | 0.005 | |
OverrideAutoDiscoveryOfIpv | false | |
IPv4Address | 0.0.0.0 | IPv4 bind address. |
IPv6Address | ::1 | IPv6 bind address. |
PromethusPort | 1234 | Port for Prometheus metrics. |
PromethusUrl | /metrics | URL path for Prometheus metrics. |
Password | default_password | Default server access password. |
MinThreadPoolThreads | 100 | Minimum number of thread pool threads. |
MaxThreadPoolThreads | 500 | Maximum number of thread pool threads. |
UseAuth | true | Enable or disable the server authentication. |
UseAuthIdentity | true | Use DID identity verification when auth is on. |
BasisUserRestrictionMode | Normal | Pertains to the user mod tools. Not completed at this time. |
HowManyDuplicateAuthCanExist | 2 | Number of times the same player can be authenticated at the same time. |
AuthValidationTimeOutMiliseconds | 9000 | Timeout for auth validation (ms). |
LNL
.
<UseAuth>true</UseAuth>
Meant to be used for turning off auth all together.
<UseAuthIdentity>true</UseAuthIdentity>
Enables disable DID auth provide
<BasisUserRestrictionMode>Normal</BasisUserRestrictionMode>
Not finished yet. Admin moderation.
<HowManyDuplicateAuthCanExist>2</HowManyDuplicateAuthCanExist>
How many people can connect with the same Auth credentials.
The default settings you may find in the config.xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PeerLimit>1024</PeerLimit>
<SetPort>4296</SetPort>
<QueueEvents>10</QueueEvents>
<UseNativeSockets>true</UseNativeSockets>
<NatPunchEnabled>true</NatPunchEnabled>
<PingInterval>1500</PingInterval>
<DisconnectTimeout>5000</DisconnectTimeout>
<SimulatePacketLoss>false</SimulatePacketLoss>
<SimulateLatency>false</SimulateLatency>
<SimulationPacketLossChance>10</SimulationPacketLossChance>
<SimulationMinLatency>50</SimulationMinLatency>
<SimulationMaxLatency>150</SimulationMaxLatency>
<UnsyncedEvents>false</UnsyncedEvents>
<UnsyncedReceiveEvent>false</UnsyncedReceiveEvent>
<UnsyncedDeliveryEvent>false</UnsyncedDeliveryEvent>
<ReconnectDelay>500</ReconnectDelay>
<MaxConnectAttempts>10</MaxConnectAttempts>
<ReuseAddress>true</ReuseAddress>
<DontRoute>false</DontRoute>
<EnableStatistics>true</EnableStatistics>
<IPv6Enabled>true</IPv6Enabled>
<MtuOverride>1500</MtuOverride>
<MtuDiscovery>true</MtuDiscovery>
<DisconnectOnUnreachable>true</DisconnectOnUnreachable>
<AllowPeerAddressChange>true</AllowPeerAddressChange>
<UsingLoggingFile>true</UsingLoggingFile>
<HealthCheckHost>localhost</HealthCheckHost>
<HealthCheckPort>10666</HealthCheckPort>
<HealthPath>/health</HealthPath>
<BSRSMillisecondDefaultInterval>50</BSRSMillisecondDefaultInterval>
<BSRBaseMultiplier>1</BSRBaseMultiplier>
<BSRSIncreaseRate>0.005</BSRSIncreaseRate>
<OverrideAutoDiscoveryOfIpv>false</OverrideAutoDiscoveryOfIpv>
<IPv4Address>0.0.0.0</IPv4Address>
<IPv6Address>::1</IPv6Address>
<PromethusPort>1234</PromethusPort>
<PromethusUrl>/metrics</PromethusUrl>
<Password>default_password</Password>
<MinThreadPoolThreads>100</MinThreadPoolThreads>
<MaxThreadPoolThreads>500</MaxThreadPoolThreads>
<UseAuth>true</UseAuth>
<UseAuthIdentity>true</UseAuthIdentity>
<BasisUserRestrictionMode>Normal</BasisUserRestrictionMode>
<HowManyDuplicateAuthCanExist>2</HowManyDuplicateAuthCanExist>
<AuthValidationTimeOutMiliseconds>9000</AuthValidationTimeOutMiliseconds>
</Configuration>
Loadable Configuration Files
You may setup world and object files to load on demand.
These are the files you place in the InitialResources
folder.
Note that the remote urls you use must be served from a proper server that supports chunking. Any modern server should do this but simple local dev servers may not.
One avenue you can use to test out a new scene is to create a scene in Unity, export the scene as a BEE file. Upload that BEE file to a server that supports HTTP, then, place the URL in CombinedURL
, and get the password from dontuploadmepassword.txt
and place it in UnlockPassword
.
Variable | Definition |
---|---|
Mode | Mode of the configuration: 0 = Game object, 1 = Scene. |
LoadedNetID | A Network ID: Server keeps a list of Network Objects that Clients can query and spawn with this value as a reference. |
UnlockPassword | Password required to unlock or access the resource. |
CombinedURL | URL to the .BEE file |
IsLocalLoad | Indicates whether the resource is loaded locally (true ) or from the internet (false ). |
PositionX | X-axis world position of the object. |
PositionY | Y-axis world position of the object. |
PositionZ | Z-axis world position of the object. |
QuaternionX | X component of the object's rotation (quaternion). |
QuaternionY | Y component of the object's rotation (quaternion). |
QuaternionZ | Z component of the object's rotation (quaternion). |
QuaternionW | W component of the object's rotation (quaternion). |
ScaleX | X-axis scale factor. |
ScaleY | Y-axis scale factor. |
ScaleZ | Z-axis scale factor. |
Persist | If the player that spawned the object leaves the server does the object continue to exist? |
<BasisLoadableConfiguration>
<!-- Mode of the configuration: Mode 0 = Game object, 1 = Scene -->
<Mode>0</Mode>
<!-- A Network ID: Server keeps a list of Network Objects that Clients can query and spawn with this value. -->
<LoadedNetID></LoadedNetID>
<!-- Unlock password -->
<UnlockPassword>ffee4439eff</UnlockPassword>
<!-- Combined URL link to BEE file -->
<CombinedURL>https://www.example.com/2lkj23j.BEE</CombinedURL>
<!-- Does this resource exist on the internet or in the client? -->
<IsLocalLoad>false</IsLocalLoad>
<!-- Position values -->
<PositionX>0</PositionX>
<PositionY>0</PositionY>
<PositionZ>0</PositionZ>
<!-- Quaternion values -->
<QuaternionX>0</QuaternionX>
<QuaternionY>0</QuaternionY>
<QuaternionZ>0</QuaternionZ>
<QuaternionW>1</QuaternionW>
<!-- Scale values -->
<ScaleX>1</ScaleX>
<ScaleY>1</ScaleY>
<ScaleZ>1</ScaleZ>
<!-- If the player that spawned the object leaves the server does the object continue to exist? -->
<Persist>false</Persist>
</BasisLoadableConfiguration>
ModifyScale
/// <summary>
/// this is used to state if the scale should be set or
/// just use whatever scale it thinks it is.
/// </summary>
public bool ModifyScale;
Advanced Server Configuration
Server Reduction System
As the number of players grows on the server the bandwidth requirements quickly grow. The SRS system attempts to reduce the network load and improve performance by slowing down how often it needs to send motion data to players based on distance.
The equation that governs how much longer the server takes to send Motion Data to users based on distance looks like:
int adjustedInterval = (int)(Configuration.BSRSMillisecondDefaultInterval * (Configuration.BSRBaseMultiplier + (activeDistance * Configuration.BSRSIncreaseRate)));
The rest of this section will be published later.
Client Reduction System
This section will be published later.
Health Check Endpoint
When running the server locally you may can check the server status by visiting the health check endpoint at: http://localhost:10666/health
{
"listening": true,
"visitors": "0",
"capacity": "1024",
"sent": "0",
"recv": "0",
"currentTime": "2025-05-09T20:19:03.200Z",
"startTime": "2025-05-09T20:19:00.049Z",
"version": "6"
}
Variable | Definition |
---|---|
listening | Is server listening for connections |
visitors | The number of current players aka visitors |
capacity | maxium number of players allowed on server |
sent | Total amount of data sent (in bytes?) |
recv | Total amount of data received (in bytes?) |
currentTime | The current server time in ISO 8601 format |
startTime | The server’s start time in ISO 8601 format |
version | The version number of the server. Important: Client code must match expected ServerVersion |
Terminology
Local Player
The local avatar data that represents you (the user or client).
Remote Player
Represents other players whose data is sent to you by the server.
Basis Client The application you are writing that will communicate with the server.
Motion Data The data that represents the player bone positions as well as position and rotation in the world. Stored in network serializable format in LASM data structure
LASM Stands for Local Avatar Sync Message, the data structure that contains compressed data for a players muscles, postion and rotation that is sent over the network.