We'll set up a Rust server on your own VPS: download it with SteamCMD, prepare a start script, run it as a systemd service, open the ports and set up management over RCON. At the end, you'll find the procedure for monthly updates and for installing Oxide or Carbon.
What you'll need
- A StormHost VPS with Ubuntu 24.04 or Debian 13, ideally 16 GB RAM or more (see Performance requirements)
- At least 30 GB of free disk space
- An SSH connection as root (guide), with the browser console open just in case
- Rust on your computer (to test the connection)
- About 45 minutes
Rust at StormHost
We're still preparing Rust servers. Until then, you can build a Rust server on a VPS with this guide. The same steps work on any Linux VPS.
How it will work#
- The
rustuser – the server doesn't run as root. If someone attacks it (for example through a bug in a plugin), they only get this user's permissions. - SteamCMD – Valve's official tool for downloading game servers. Rust Dedicated Server has the app number
258550on Steam. - Start script
/opt/rust/start.sh– contains all server parameters (ports, map, RCON). - systemd service
rust– starts the server when the VPS boots and restarts it after a crash. - RCON – the remote console. The console of a Linux server isn't interactive, so you send commands over RCON.
Folder structure:
| Path | What's there |
|---|---|
/opt/rust/steamcmd | SteamCMD |
/opt/rust/server | The Rust server (the server root; Oxide or Carbon also go here) |
/opt/ | World, players and configuration (identity rust) |
/opt/rust/start.sh | Start script |
Performance requirements#
- RAM: Facepunch states at least 12 GB of free memory for the server, and a size 6000 map needs more. Plugins and players add to that. So plan on a VPS with 16 GB RAM or more. Swap helps get through peaks, but it's no substitute for missing RAM.
- CPU: the server's main loop mostly uses a single core. Single-core performance matters more than the number of cores.
- Disk: Facepunch states at least 15 GB of free space, ideally SSD or NVMe. Leave headroom for updates, backups and maps.
Keep an eye on the memory of a busy server with free -h.
Preparing the system#
This applies to both Ubuntu 24.04 and Debian 13. Run the commands as root.
Update the package list and install the required programs:
bash apt update apt install -y lib32gcc-s1 curl ca-certificates unziplib32gcc-s1– a 32-bit library SteamCMD needs to run (SteamCMD is a 32-bit program).curl– downloads files from the internet.ca-certificates– certificates for secure downloads over HTTPS.unzip– extracts the Oxide archive (if you'll use it).
Create the
rustuser with the home folder/opt/rust:bash useradd --create-home --home-dir /opt/rust --shell /bin/bash rust--create-home --home-dir /opt/rust– creates the/opt/rustfolder, owned by therustuser.--shell /bin/bash– the user gets a regular shell so you can switch to it. It has no password, so you can't log in as it over SSH; switch to it from root withsu - rust.
Installing SteamCMD#
Switch to the
rustuser:bash su - rustThe command prompt changes to
rust@…. Run all following commands under this user, up to the systemd service section.Create a folder for SteamCMD and go into it:
bash mkdir -p ~/steamcmd cd ~/steamcmdDownload and extract SteamCMD:
bash curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -curl -sqL "…"– downloads the archive from Valve's official server;-sis silent mode (no progress bar),-qskips curl's personal config file~/.curlrcif there is one,-Lfollows redirects.| tar zxvf -– extracts the downloaded archive straight into the current folder (zgzip,xextract,vlist files,f -read from standard input).
The folder now contains the
steamcmd.shscript.
Downloading the Rust server#
Still as the rust user, run:
~/steamcmd/steamcmd.sh +force_install_dir /opt/rust/server +login anonymous +app_update 258550 validate +quit~/steamcmd/steamcmd.sh– starts SteamCMD. On the first run, SteamCMD updates itself, which takes a moment.+force_install_dir /opt/rust/server– where the server is installed. Use an absolute path and always put it before+login.+login anonymous– anonymous login. You don't need a Steam account to download the server.+app_update 258550– downloads or updates app 258550 (Rust Dedicated Server).validate– checks all files and restores damaged or modified ones to their original state. Careful: it also restores files overwritten by the Oxide framework.+quit– exits SteamCMD when done.
The download is several gigabytes. At the end you'll see:
Success! App '258550' fully installed.Test branches
Facepunch also offers test versions of the server (for example the staging branch). You get them by adding -beta staging after +app_update 258550. For a live server, use the default public version.
Start script#
As the
rustuser, create the file:bash nano ~/start.shPaste the content and adjust the values (explanation below the block):
/opt/ rust/ bashstart.sh #!/usr/bin/env bash cd /opt/rust/server || exit 1 export TERM=xterm export LD_LIBRARY_PATH="/opt/rust/server:/opt/rust/server/RustDedicated_Data/Plugins/x86_64" # Carbon: uncomment the next line (remove the #) once Carbon is installed # source /opt/rust/server/carbon/tools/environment.sh exec ./RustDedicated -batchmode \ +server.identity "rust" \ +server.port 28015 \ +server.queryport 28017 \ +server.level "Procedural Map" \ +server.seed 12345 \ +server.worldsize 3000 \ +server.maxplayers 50 \ +rcon.port 28016 \ +rcon.password "<STRONG_PASSWORD>" \ +rcon.web 1 \ +app.port 28082 \ -logfile /opt/rust/rust.logSave (Ctrl+O, Enter) and close the editor (Ctrl+X).
Set the permissions so the script can be executed and only the
rustuser can read the password in it:bash chmod 700 ~/start.sh
What each part does:
cd /opt/rust/server || exit 1– the server is started from its root folder (Oxide creates itsoxidefolder there). If the folder doesn't exist, the script exits.export TERM=xterm– the terminal type; a systemd service has no terminal, and according to the Carbon documentation some environments require it.export LD_LIBRARY_PATH=…– the folders where the server looks for its libraries (the server root andRustDedicated_).Data/ Plugins/ x86_ 64 source …/environment.sh– loads Carbon. Leave it commented out until you install Carbon.exec ./RustDedicated– starts the server;execmakes sure systemd tracks the server process directly.- The server parameters (
+server.port,+server.seed,+rcon.password…) are explained in detail in the server.cfg and launch parameters article. -logfile /opt/rust/rust.log– the server console output is written to this file.
Replace <STRONG_PASSWORD> with an RCON password (without the angle brackets), made only of letters and digits and at least 24 characters long. You can create one with the password generator. Choose the seed (12345), map size (3000) and slot count (50) to suit you. Keep only ports, RCON, identity, map and slot count in the script, so the same setting isn't in two places.
Still as the
rustuser, create theserver.cfgfile for the server name, description, tags and other settings:bash mkdir -p /opt/rust/server/server/rust/cfg nano /opt/rust/server/server/rust/cfg/server.cfgmkdir -p …– creates therustidentity folder and itscfgsubfolder (the server would create the folder on first start, but notserver.cfg).- What to put in the file is explained in the configuration article. One line is enough for now, for example
server.hostname "My Rust server".
Create both the folder and the file as the
rustuser. If root created them, the server couldn't write admin accounts or bans to thecfgfolder. The fix (as root):chown -R rust:rust /opt/rust/server/server.Switch back to root:
bash exit
systemd service#
As root, create the service file with nano /etc/:
[Unit]
Description=Rust Dedicated Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=rust
Group=rust
WorkingDirectory=/opt/rust/server
ExecStart=/opt/rust/start.sh
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target| Directive | What it does | Recommended value | When to change it |
|---|---|---|---|
After= and Wants= | The server only starts once the network is up. | network-online.target | – |
User=, Group= | Which user the server runs as. | rust | Never root. |
WorkingDirectory= | The process's working folder. | /opt/rust/server | If the server is at a different path. |
ExecStart= | The start script (absolute path). | /opt/rust/start.sh | – |
Restart=always | When the process exits, systemd starts it again, even if it exited “cleanly”. This is also what makes the restart command over RCON work (the server exits and systemd starts it again). | always | on-failure if you don't want a restart after shutting it down manually over RCON. |
RestartSec=15 | The pause before a restart. | 15 | – |
WantedBy= | After enable, the server starts when the VPS boots. | multi-user.target | – |
For a more detailed explanation of systemd services, see the Running an app as a systemd service guide.
Load, enable and start the service:
systemctl daemon-reload
systemctl enable --now rustsystemctl daemon-reload– systemd reloads the service files (after every change torust.service).systemctl enable --now rust– enables starting on VPS boot (enable) and starts the service right away (--now).
With Restart=always, the only way to stop the server is systemctl stop rust. If you shut it down over RCON (quit), systemd starts it again.
Ports and firewall#
| Port | Protocol | What for | Open to |
|---|---|---|---|
28015 | UDP | The game (player connections). | Everyone |
28017 | UDP | Query – listing the server in the server browser. | Everyone |
28082 | TCP | Rust+ (mobile app). Must be at least 10000. | Everyone (or no one, if you turn Rust+ off) |
28016 | TCP | RCON (remote console). | Your IP address only |
If you use UFW:
ufw allow 28015/udp
ufw allow 28017/udp
ufw allow 28082/tcp
ufw allow from 198.51.100.25 to any port 28016 proto tcpufw allow 28015/udp– allows the game port over UDP.ufw allow 28017/udp– allows the query port.ufw allow 28082/tcp– allows Rust+.ufw allow from 198.51.100.25 to any port 28016 proto tcp– RCON only from the IP address198.51.100.25; use your own public IP address.
If the firewall in the customer area is set to Block everything except allowed, add the same rules there (Direction Inbound, Action Allow, the correct Protocol; for RCON, fill in Source IP / range). The port has to be allowed in both firewalls.
Don't need Rust+? In the script, replace +app.port 28082 with +app.port 1- (this turns Rust+ off, according to Facepunch) and don't open port 28082.
Verification#
Check the service status:
bash systemctl status rustLook for the line
Active: active (running).Watch the server output:
bash tail -f /opt/rust/rust.logThe first start takes several minutes (the map is being generated). The server is ready when
Server startup completeappears. Stop watching with Ctrl+C.In the game, open the F1 console and connect:
text connect 203.0.113.10:28015Replace
203.0.113.10with your VPS's IPv4 address from the Network tab.A few minutes after startup, search for the server by name in the server browser (without a framework in the Community tab, with Oxide or Carbon in Modded).
Connect over RCON (RustAdmin or the web console) to
203.0.113.10:28016with the password from the script and add yourself as owner – the steps are in the Admin and RCON article.
Updating the server#
A major Rust update comes out once a month (usually on the first Thursday of the month), with smaller fixes in between.
Announce the restart to players and save the world over RCON:
server.save.Stop the service (as root):
bash systemctl stop rustUpdate the server as the
rustuser:bash su - rust -c "/opt/rust/steamcmd/steamcmd.sh +force_install_dir /opt/rust/server +login anonymous +app_update 258550 validate +quit"su - rust -c "…"– runs a single command as therustuser and returns.
If you use Oxide, upload it again (the update overwrote it) – see the Oxide or Carbon section below. Carbon updates itself on start.
Start the service:
bash systemctl start rust
Don't put the update in the start script if you use Oxide
If SteamCMD with validate ran on every start, every restart would remove Oxide and the server would run without plugins. Facepunch explicitly warns about this in its guide. Update manually using the steps above.
A monthly update usually also means a new world (force wipe). The procedure and what to delete are in the Rust server wipe article.
Oxide or Carbon#
What each one is and which to choose is explained in Oxide and Carbon. Installing on this VPS (the server has to be stopped):
Oxide
Stop the server:
systemctl stop rust.Download and extract Oxide as the
rustuser:bash su - rust -c "curl -fL -o /opt/rust/oxide.zip https://github.com/OxideMod/Oxide.Rust/releases/latest/download/Oxide.Rust-linux.zip && unzip -o /opt/rust/oxide.zip -d /opt/rust/server"curl -fL -o /opt/rust/oxide.zip …– downloads the latest stable Oxide for Linux to therustuser's home folder.-fmakes the command fail if the file doesn't exist,-Lfollows GitHub's redirect.&&– the next command only runs if the download succeeded.unzip -o … -d /opt/rust/server– extracts the archive into the server root and overwrites the original game files.
Start the server:
systemctl start rust.Check
oxide.versionover RCON.
After a monthly Rust update, repeat steps 1–3 only once an Oxide version newer than the Rust update is out on GitHub (opens in a new window).
Carbon
Stop the server:
systemctl stop rust.Download and extract Carbon as the
rustuser:bash su - rust -c "curl -fL -o /opt/rust/carbon.tar.gz https://github.com/CarbonCommunity/Carbon/releases/download/production_build/Carbon.Linux.Release.tar.gz && tar -xzf /opt/rust/carbon.tar.gz -C /opt/rust/server"- Downloads the stable (production) Carbon build for Linux and extracts (
-x) it from the gzip-compressed archive (-z,-ffile) into the server root (-C).
- Downloads the stable (production) Carbon build for Linux and extracts (
In the
/opt/rust/start.shfile, uncomment the linesource /opt/(remove therust/ server/ carbon/ tools/ environment. sh #at the beginning).Start the server:
systemctl start rust.Check
c.versionover RCON.
After a Rust update, just start the server; Carbon updates itself.
Backups#
The world and players are in /opt/, plugins and their data in /opt/rust/server/oxide (or carbon). We take care of VPS backups, but for quickly restoring a single world or configuration it's handy to also have your own backup of these folders. Before backing up, save the world (server.save) or stop the server. Backup options are described in Backups on a VPS.
Troubleshooting#
ERROR! Failed to install app '258550' (No subscription)#
The SteamCMD command is missing +login anonymous. You can't download the server without logging in (but you don't need a Steam account).
SteamCMD reports linux32/steamcmd: No such file or directory#
The 32-bit library is missing. Install it as root: apt install lib32gcc-s1.
SteamCMD reports Please use force_install_dir before logon!#
The +force_install_dir parameter has to come before +login in the command. Fix the order as shown in the guide.
The service exits immediately with status=203/EXEC#
systemd can't run the script: it isn't executable (chmod 700 /opt/rust/start.sh), the first line #!/usr/bin/env bash is missing, or the file has Windows line endings (you wrote it on Windows and uploaded it). Other error codes are explained in Running an app as a systemd service. Detailed output: journalctl -u rust -n 50.
error while loading shared libraries: …#
The server is missing a system library; its name is in the message. Check the export LD_LIBRARY_PATH=… line in the script and, if needed, install the library with apt.
The server is running, but you can't connect to it#
- The server hasn't finished starting yet (
Server startup completeisn't in the log). - Port 28015/UDP isn't allowed in UFW or in the firewall in the customer area. Note that the game uses UDP, not TCP.
- You're connecting to the wrong IP address or port.
The server isn't in the server browser#
The query port (28017/UDP) isn't open, or it's the same as the game port. The server only appears in the browser a few minutes after startup. Look in the right tab (Community or Modded).
The server crashes after a while and there's nothing in the log#
Most likely it ran out of memory and the system killed the process. Check:
journalctl -k | grep -i "out of memory"journalctl -k– prints the system kernel's messages (processes killed for lack of memory are logged here too).| grep -i "out of memory"– keeps only the lines containing this text;-iignores case.
Output mentioning RustDedicated means there isn't enough RAM. Use a smaller map, cut down on plugins, add swap or add more RAM (VPS upgrade).
Rust+ companion server connectivity test failed! Disabling Rust+ features.#
The server checks that the Rust+ port is reachable from the internet. Allow 28082/tcp in both firewalls, or turn Rust+ off (+app.port 1-). Facepunch notes that the port has to be at least 10000 and that the server needs access to companion-rust..
Plugins don't work after an update#
The update with validate removed Oxide. Upload it again (the Oxide or Carbon section).
Summary
- The server runs as the
rustuser in/opt/rust/serverand is downloaded with SteamCMD (app258550). - The parameters are in the
/opt/rust/start.shscript, and therustservice runs the server (systemctl start|stop|status rust). - Open 28015/UDP, 28017/UDP, 28082/TCP, and RCON 28016/TCP only for your IP – in UFW and in the firewall in the customer area.
- Send commands over RCON; the console on Linux isn't interactive.
- Updating: save, stop, SteamCMD with
validate, Oxide again (Carbon updates itself), start.