These are preliminary instructions with limited testing. It is possible that some instructions are incomplete for some platforms. Please let us know via Discord if you encounter any issues and we will endeavor to both assist you with your installation and update these instructions.
This guide is a guide to run a Metaverse Server on your Linux machine.
git clone --recurse-submodules https://github.com/MetaversalCorp/MSF_Map_Svc.git
cd MSF_Map_Svc
npm install
Execute the following:
npm run build:linux:mysql
Execute the following:
npm run build:linux:mssql
We can now create the Metaverse Server
cd dist
npm install
At this point, your Metaverse Server needs to support HTTPS. To configure an SSL certificate, you can either use a public, trusted certificate or a self-signed certificate.
This example uses certbot with Let’s Encrypt.
sudo apt install -y snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
certbot --version
sudo certbot certonly --standalone -d example.xyz.com
sudo ln -sf /etc/letsencrypt/live/example.xyz.com/fullchain.pem ~/MSF_Map_Svc/dist/ssl/server.cert
sudo ln -sf /etc/letsencrypt/live/example.xyz.com/privkey.pem ~/MSF_Map_Svc/dist/ssl/server.key
sudo groupadd ssl-cert 2>/dev/null || true
sudo usermod -aG ssl-cert {USER}
sudo chgrp -R ssl-cert /etc/letsencrypt
sudo chmod -R g+rx /etc/letsencrypt
sudo chmod 750 /etc/letsencrypt/{live,archive}
Certbot will automaticly create a renewal timer that runs every 10 hours, to check run
sudo systemctl list-timers | grep -i certbot
TBD
mv settings.json.sample settings.json
"MVSF": {
// ... other values
"LAN": {
// ... other values
"port": "<LAN_PORT>",
"SSL": {
"bUseSSL": true,
"key": "key.pem",
"cert": "cert.pem"
}
}
}
NODEBIN="$(readlink -f "$(which node)")"
sudo setcap CAP_NET_BIND_SERVICE=+ep "$NODEBIN"
getcap "$NODEBIN"
"MVSF": {
// ... other values
"WAN": {
// ... other values
"host": "mydomain.com",
"port": "<WAN_PORT>"
}
}
"MVSF": {
// ... other values
"key": "<Select your own secure password>",
"sCompanyId": "<Your RP1 CompanyId>"
}
Set the database connection properties:
"SQL": {
// ... other values
"config": {
// ... other values
"host": "sql.mydomain.com"
"port": "3306"
"user": "username"
"password": "password"
"database": "my_database_name"
}
}
The install script will create the database using the name specified here.
Set the database installation properties:
"SQL": {
// ... other values
"install": {
// ... other values
"db_name": "<my_database_name>",
"login_name": "domain\\username", // Specifies the name of the login to grant execute rights
"pathname": "C:\\db" // Make sure you use double backslash
}
// ... other values
"config": {
// ... other values
"connectionString": "Driver=SQL Server;Server=sql.mydomain.com;Database=my_database_name;Trusted_Connection=Yes;",
"_alt_connectionString": "Driver=SQL Server;Server=la2-ntweb0.mv.local;Database=map_db;User Id=map_user;Password={PW};"
}
}
}
Your map service must have a login preconfigured on SQL Server before continuing.
If you haven't already configured a login on SQL Server, you can create one using one of these methods:CREATE LOGIN [{Login_Name}] WITH PASSWORD = '[{Login_Password}]' CREATE LOGIN [{Login_Name}] FROM WINDOWSWhen you're creating logins that are mapped from a Windows domain account, you must use the logon name in the format
<domainName>\\<login_name>.For more information on creating logins:
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-login-transact-sql?view=sql-server-ver17
You are done configuring your settings. You can save and close your editor.
This will install the server files.
npm run install:svc
This will install the sample scene and media files associated with it.
npm run install:sample
You should have a proper installation and configuration of your server. You can test it by running the following command:
npm run dev
If you get the following output, your server is ready to go.
SQL Server READY
Server running on port 2000
You have completed the installation of your server into the dist folder. You can now rename/move the dist folder to your desired location.
You will most likely want to install your server as a background service.
sudo nano /etc/systemd/system/msf-map-svc.service
[Unit]
Description=MSF Map Service
After=network.target
[Service]
Type=simple
User={YOURUSERNAME}
WorkingDirectory=/home/{YOURUSERNAME}/MSF_Map_Svc/dist
Environment=NODE_INTERNALPORT=2000
ExecStart=/usr/bin/node server.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
Let’s go ahead and talk about what’s in that file. In the [Unit] section, the Description and Documentation variables are obvious. What’s less obvious is the part that says
After=network.target
That tells systemd that if it’s supposed to start our app when the machine boots up, it should wait until after the main networking functionality of the server is online to do so. This is what we want, since our app can’t bind to NODE_PORT until the network is up and running.
Moving on to the [Service] section we find the meat of today’s project. We can specify environment variables here, so I’ve gone ahead and put in:
Environment=NODE_EXTERNALPORT=2000
So our app, when it starts, will be listening on port 3001. This is different than the default 3000 that we saw when we launched the app by hand. You can specify the Environment directive multiple times if you need multiple environment variables. Next is
Type=simple
Which tells systemd how our app launches itself. Specifically, it lets systemd know that the app won’t try and fork itself to drop user privileges or anything like that. It’s just going to start up and run. After that we see
User={YOURUSERNAME}
Which tells systemd that our app should be run as the unprivileged ubuntu user.
The token {YOURUSERNAME} needs to be replaced with the unprivileged user that systemd will run the app as. You definitely want to run your apps as unprivileged users to that attackers can’t aim at something running as the root user.
The last two parts here are maybe the most interesting to us
WorkingDirectory=/home/{YOURUSERNAME}/MSF_Map_Svc/dist
ExecStart=/usr/bin/node server.js
Restart=on-failure
First, WorkingDirectory tells system do where our applications current working directory is located. Then, ExecStart tells systemd what command it should run to launch our app. Then, Restart tells systemd under what conditions it should restart the app if it sees that it has died. The on-failure value is likely what you will want. Using this, the app will NOT restart if it goes away “cleanly”. Going away “cleanly” means that it either exits by itself with an exit value of 0, or it gets killed with a “clean” signal, such as the default signal sent by the kill command. Basically, if our app goes away because we want it to, then systemd will leave it turned off. However, if it goes away for any other reason (an unhandled exception crashes the app, for example), then systemd will immediately restart it for us. If you want it to restart no matter what, change the value from on-failure to always.
Last is the [Install] stanza. We’re going to gloss over this part as it’s not very interesting. It tells systemd how to handle things if we want to start our app on boot, and you will probably want to use the values shown for most things until you are a more advanced systemd user.
sudo systemctl daemon-reload
sudo systemctl enable msf-map-svc
sudo systemctl start msf-map-svc
sudo systemctl status msf-map-svc
Check the logs
journalctl -u msf-map-svc -n 50 --no-pager
sudo tee /etc/letsencrypt/renewal-hooks/deploy/restart-msf-map-svc.sh >/dev/null <<'EOF'
#!/bin/bash
set -e
systemctl restart msf-map-svc
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-msf-map-svc.sh
sudo certbot renew --dry-run --run-deploy-hooks
journalctl -u msf-map-svc -n 50 --no-pager
If for any reason you need to remove the software
sudo systemctl stop msf-map-svc
sudo systemctl disable msf-map-svc
sudo rm /etc/systemd/system/msf-map-svc.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
Verify
systemctl status msf-map-svc
Remove the directory
rm -r ~/MSF_Map_Svc