Set up a Rust server on a VPS or dedicated box, step by step
On this page
- Before you start
- 1. First login and SSH keys
- 2. Your own admin user
- 3. Turn off password and root logins
- 4. The firewall
- 5. fail2ban for SSH
- 6. Install SteamCMD and the Rust server
- 7. Carbon or Oxide (optional)
- 8. The start script and the RCON password
- 9. What the server list shows: server.cfg
- 10. A small RCON tool
- 11. Run it as a service
- 12. First start and checks
- 13. Daily restarts
- 14. Patch day and forced wipes
- 15. Backups and snapshots
- 16. Logs
- 17. Common problems
- Get help
This guide takes a fresh Ubuntu 22.04 or 24.04 box to a running Rust server with a firewall, a service that restarts itself, daily restarts, nightly backups and a plan for patch day. The commands are the ones we use on our own Ubuntu servers, or checked against the tools' own documentation and the game's own code (Rust build 25083359, September 2026).
In the commands, replace SERVER_IP with your server's address, YOUR_IP with your home internet address (search "what is my IP" from home), and yourname with a user name of your choice. Each block says where it runs: on your PC, or on the server.
Before you start
- A VPS or dedicated box running Ubuntu 22.04 LTS or 24.04 LTS, with at least 8 GB of RAM. For a full-size map with plugins, 16 GB. Which hardware matters.
- The server's IP address and a root login from your provider.
- A terminal on your PC. Windows 10 and 11 have
sshin PowerShell; Mac and Linux have it in Terminal. - About an hour, most of it waiting for downloads.
- A snapshot. Take one in your provider's panel before any big change. It is the undo button for the whole box.
1. First login and SSH keys
An SSH key replaces the password. It has two halves: a private one that never leaves your PC, and a public one that goes on the server. Make one:
ssh-keygen -t ed25519
Press Enter to accept the default file and set a passphrase when asked. If your provider lets you paste a public key when you create the server, paste the contents of id_ed25519.pub there and skip the next command. Otherwise, copy the public key across. On Windows, in PowerShell:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root@SERVER_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
On Mac or Linux:
ssh-copy-id root@SERVER_IP
Now log in, bring everything up to date, and restart:
ssh root@SERVER_IP
apt update && apt full-upgrade -y
reboot
Wait a minute and log in again. If your provider gave you a user called ubuntu instead of root, log in as that and put sudo in front of each command in this step and the next.
Ubuntu installs security updates by itself. Check that it is switched on: both lines of this file should say "1".
cat /etc/apt/apt.conf.d/20auto-upgrades
If the file is missing, run sudo dpkg-reconfigure -plow unattended-upgrades and answer Yes. A new kernel only takes effect after a restart of the box: when the file /var/run/reboot-required exists, reboot at a quiet time.
2. Your own admin user
Working as root all the time makes every typo dangerous. Make a normal user that can use sudo, and give it your key:
adduser yourname
usermod -aG sudo yourname
mkdir -p /home/yourname/.ssh
cp /root/.ssh/authorized_keys /home/yourname/.ssh/
chown -R yourname:yourname /home/yourname/.ssh
chmod 700 /home/yourname/.ssh
chmod 600 /home/yourname/.ssh/authorized_keys
adduser asks for a password. That is the password sudo will ask for, so make it long and keep it in a password manager. Now open a second terminal on your PC and check the new user:
ssh yourname@SERVER_IP
sudo whoami
It should print root. Keep this second session open for the next step. From here on, log in as yourname.
3. Turn off password and root logins
With your key working, switch off password logins and direct root logins. Create a small settings file:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
Save with Ctrl+O and Enter, then leave with Ctrl+X. The 00 at the start of the name matters. SSH keeps the first value it reads for each setting and reads this folder in name order, and many providers put a file of their own in it that turns passwords back on. On one of our own boxes, a file we had named with 90 at the start was silently ignored for exactly that reason. Check the syntax, apply it, and ask SSH what it is really using:
sudo sshd -t && sudo systemctl restart ssh
sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin) '
All three lines should end in no. Before you close anything, test from a new terminal on your PC: ssh yourname@SERVER_IP must work, and ssh root@SERVER_IP must be refused. If you ever lock yourself out, your provider's web console still works: it is like a keyboard plugged into the server.
4. The firewall
Ubuntu's firewall, ufw, blocks everything coming in once it is on, apart from what you allow. Allow SSH first, then the Rust ports. RCON is the server's remote console: anyone who can use it controls your server, so open it to your own address only.
sudo apt install ufw
sudo ufw allow OpenSSH
sudo ufw allow 28015/udp
sudo ufw allow 28017/udp
sudo ufw allow 28082/tcp
sudo ufw allow from YOUR_IP to any port 28016 proto tcp
sudo ufw enable
sudo ufw status verbose
ufw enable warns that it may disrupt SSH connections; you allowed SSH first, so answer y.
| Port | Type | What it is | Open to |
|---|---|---|---|
| 28015 | UDP | The game. Players connect here. | Everyone |
| 28017 | UDP | Query. The server list asks it for your name and player count. | Everyone |
| 28016 | TCP | RCON, the remote console | Your address only |
| 28082 | TCP | Rust+, the companion app. Optional: set +app.port -1 in step 8 and skip this rule. | Everyone |
| 22 | TCP | SSH, keys only after step 3 | Everyone |
Home addresses change. If RCON stops answering one day, check your address and add a rule for the new one. sudo ufw status numbered lists the rules and sudo ufw delete NUMBER removes the old one. Some providers also have a firewall in their web panel; if players cannot reach the server later, check that one too.
5. fail2ban for SSH
With password logins off, nobody can guess their way in, but bots still try thousands of times a day. fail2ban blocks an address after repeated failures, which keeps the logs readable.
sudo apt install fail2ban
sudo nano /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 6h
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
If fail2ban will not start on Ubuntu 24.04, run sudo apt update && sudo apt full-upgrade: the first 24.04 package had a bug that a later update fixed.
6. Install SteamCMD and the Rust server
The game runs as its own user with no login of its own, so a problem in the game cannot reach the rest of the box. SteamCMD, Valve's download tool, is a 32-bit program in Ubuntu's multiverse section, so the box needs both switched on:
sudo useradd -m -s /bin/bash rustserver
sudo add-apt-repository multiverse
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install steamcmd python3-websocket
SteamCMD asks you to accept the Steam licence: read it and choose "I AGREE". python3-websocket is for the small RCON tool in step 10. If add-apt-repository is not found, install it with sudo apt install software-properties-common.
Now download the server. 258550 is the Rust dedicated server's Steam app. The first run also updates SteamCMD itself.
sudo -iu rustserver /usr/games/steamcmd +force_install_dir /home/rustserver/rust +login anonymous +app_update 258550 validate +quit
It should end with "Success! App '258550' fully installed." The game lands in /home/rustserver/rust.
7. Carbon or Oxide (optional)
Plugins need a mod framework. There are two, both free. Use one, not both, or neither for a vanilla server.
- Carbon, carbonmod.gg, describes itself as a drop-in replacement for Oxide and runs most Oxide plugins. Our own plugins are built and tested on Carbon.
- Oxide, umod.org, is the original framework, and most public plugins were written for it.
Carbon: download the production build for Linux and unpack it into the server folder.
sudo -iu rustserver
curl -fsSL -o /tmp/carbon.tar.gz https://github.com/CarbonCommunity/Carbon/releases/download/production_build/Carbon.Linux.Release.tar.gz
tar -xzf /tmp/carbon.tar.gz -C /home/rustserver/rust
exit
Plugins then go in /home/rustserver/rust/carbon/plugins. The start script in the next step loads Carbon when it finds it.
Oxide: download the Linux build and unpack it over the server folder.
sudo apt install unzip
sudo -iu rustserver
curl -fsSL -o /tmp/oxide.zip https://github.com/OxideMod/Oxide.Rust/releases/latest/download/Oxide.Rust-linux.zip
unzip -o /tmp/oxide.zip -d /home/rustserver/rust
exit
Plugins then go in /home/rustserver/rust/oxide/plugins. Oxide works by changing some of the game's own files, and every Rust update puts the originals back, so you install Oxide again after each update (step 14).
Before you install a plugin, check it. The plugins folder appears after the first start (step 12). Then, to copy a file from your PC: scp MyPlugin.cs yourname@SERVER_IP:, and on the server sudo install -o rustserver -g rustserver -m 644 ~/MyPlugin.cs /home/rustserver/rust/carbon/plugins/ (or oxide/plugins).
8. The start script and the RCON password
Switch to the game's user, make a random RCON password, and write the start script. The script holds the launch settings, so the service in step 11 never needs to change.
sudo -iu rustserver
openssl rand -hex 16 > ~/.rcon-password
chmod 600 ~/.rcon-password
mkdir -p ~/logs
nano ~/start.sh
#!/usr/bin/env bash
cd /home/rustserver/rust || exit 1
export LD_LIBRARY_PATH="$PWD:$PWD/RustDedicated_Data/Plugins/x86_64"
if [ -f carbon/tools/environment.sh ]; then
source carbon/tools/environment.sh
fi
LOG="/home/rustserver/logs/server-$(date +%F-%H%M%S).log"
ln -sfn "$LOG" /home/rustserver/logs/latest.log
find /home/rustserver/logs -name 'server-*.log' -mtime +14 -delete
exec ./RustDedicated -batchmode -nographics -logfile "$LOG" \
+server.identity "myserver" \
+server.port 28015 \
+server.queryport 28017 \
+rcon.port 28016 \
+rcon.web 1 \
+rcon.password "$(cat /home/rustserver/.rcon-password)" \
+app.port 28082 \
+server.level "Procedural Map" \
+server.worldsize 3500 \
+server.seed 12345 \
+server.maxplayers 50 \
+server.saveinterval 300
chmod +x ~/start.sh
exit
What the settings do:
| Setting | What it does |
|---|---|
server.identity | The folder for this server's saves and settings: /home/rustserver/rust/server/myserver. A new name means a fresh server. |
server.port | The game port, UDP. |
server.queryport | The server-list port, UDP. If you leave it out, Rust uses one above the higher of the game and RCON ports. |
rcon.port, rcon.web, rcon.password | The remote console over WebSocket, TCP. Rust will not start RCON with an empty or common password (changeme, password, 123456 and a few more) and warns about anything under 8 characters. |
app.port | Rust+, the companion app, TCP. -1 turns it off. |
server.level, server.worldsize, server.seed | A procedural map, its size in metres, and its seed. The same size and seed always give the same map. Bigger maps hold more entities, and entities cost CPU and memory. |
server.maxplayers | The number of slots. |
server.saveinterval | Seconds between automatic saves. The default is 600; we use 300. |
-logfile | Where the log goes. The script starts a new file each time, points latest.log at it, and deletes logs older than 14 days. |
The Carbon line only does something when Carbon is installed. The RCON password ends up on the server's command line, where anyone with a shell on the box could read it. Keep other people off the box, which you should anyway.
9. What the server list shows: server.cfg
The name, description and pictures go in server.cfg, not the start script. Rust reads the launch settings first, then serverauto.cfg, then server.cfg, and the last value wins. The server writes serverauto.cfg itself (at every clean shutdown), and it keeps some of these settings, including the header image and the tags. Set on the launch line, an old saved value would quietly win.
sudo -u rustserver mkdir -p /home/rustserver/rust/server/myserver/cfg
sudo -u rustserver nano /home/rustserver/rust/server/myserver/cfg/server.cfg
server.hostname "My Rust Server | Weekly"
server.description "Weekly wipe. Be nice. Discord and rules on our website."
server.url "https://example.com"
server.headerimage "https://example.com/header.jpg"
server.tags "weekly,EU"
Replace the example text and links with your own; leave out a line you do not need. The header image is shown in the server list; 512 by 256 pixels, hosted on your own website. For tags, Rust keeps only the ones it knows, such as a wipe schedule (monthly, biweekly, weekly) and a region (NA, SA, EU, WA, EA, OC, AF), and drops the rest.
10. A small RCON tool
The daily restart, the save before each stop, and making yourself an admin all go through RCON. This short script sends one command from the box itself and prints the reply.
sudo -u rustserver nano /home/rustserver/rcon.py
#!/usr/bin/env python3
import json
import sys
import websocket
command = " ".join(sys.argv[1:])
if not command:
sys.exit("usage: rcon.py <command>")
with open("/home/rustserver/.rcon-password") as f:
password = f.read().strip()
try:
ws = websocket.create_connection("ws://127.0.0.1:28016/" + password, timeout=10)
except (OSError, websocket.WebSocketException) as e:
sys.exit(f"RCON is not answering: {e}")
answered = False
try:
ws.settimeout(90)
ws.send(json.dumps({"Identifier": 1, "Message": command, "Name": "rcon.py"}))
# A second, harmless command. Rust runs commands in order,
# so its reply means the first one has finished.
ws.send(json.dumps({"Identifier": 2, "Message": "server.fps", "Name": "rcon.py"}))
while True:
raw = ws.recv()
if not raw:
sys.exit("RCON closed the connection: a wrong password, or the server stopped.")
reply = json.loads(raw)
if reply.get("Identifier") == 2:
break
if reply.get("Identifier") == 1:
answered = True
if reply.get("Message"):
print(reply["Message"])
except (OSError, ValueError, websocket.WebSocketException) as e:
sys.exit(f"RCON stopped answering: {e}")
finally:
ws.close(timeout=0)
if not answered:
sys.exit("No reply. Rust does not know that command.")
sudo chmod +x /home/rustserver/rcon.py
Use it as sudo -u rustserver /home/rustserver/rcon.py status, with any console command in place of status.
11. Run it as a service
systemd starts the server when the box boots, restarts it if it crashes, and saves the world before it stops.
sudo nano /etc/systemd/system/rust-server.service
[Unit]
Description=Rust dedicated server
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=900
StartLimitBurst=3
[Service]
Type=simple
User=rustserver
Group=rustserver
WorkingDirectory=/home/rustserver/rust
ExecStart=/home/rustserver/start.sh
ExecStop=-/usr/bin/python3 /home/rustserver/rcon.py server.save
Restart=on-failure
RestartSec=30
KillSignal=SIGINT
TimeoutStopSec=120
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now rust-server
The lines that matter:
WorkingDirectorymust be the server folder. Rust finds its saves (server/myserver) and a downloaded custom map relative to the folder it was started from. Started anywhere else, it builds a fresh world in the wrong place, or a custom map downloads but never loads. The start script'scdcovers the same trap.ExecStopsaves the world first. Rust does not save when it is stopped by a signal. In the game's code, only its own quit and restart commands save on the way out, and any save is skipped once the program is quitting (we read this in build 25083359). Without this line, every stop or restart of the service would lose everything since the last automatic save.Restart=on-failurebrings the server back after a crash. Rust's ownrestartcommand ends the process in a way systemd counts as a failure (exit code 137), so this line also starts it again after a planned restart. We saw exactly that on our US server on 2026-09-24.StartLimitBurst: after three failed starts in 15 minutes systemd stops trying, so a broken server does not loop forever.sudo systemctl reset-failed rust-serverclears it.
12. First start and checks
Starting takes a while. Our small 1500 m test server starts in about 70 seconds on our Dallas box (Ryzen 9 7950X, Rust build 25454815, 2026-09-28); full-size maps take longer, and the very first start longest, because it builds the map. Watch the log until it says "Server startup complete". Ctrl+C stops watching; the server keeps running.
sudo tail -f /home/rustserver/logs/latest.log
Then check the service and RCON:
systemctl status rust-server --no-pager
systemctl show rust-server -p NRestarts -p ActiveEnterTimestamp
sudo -u rustserver /home/rustserver/rcon.py status
NRestarts counts automatic restarts. If it climbs, the server is crashing and coming back, even though it looks up. Join from the game: press F1 and type client.connect SERVER_IP:28015. To make yourself an owner, use your 17-digit Steam ID (it starts with 7656119):
sudo -u rustserver /home/rustserver/rcon.py ownerid YOUR_STEAM_ID yourname
The server saves that to server/myserver/cfg/users.cfg straight away. In the server list, servers running Carbon or Oxide show under Modded; give it a few minutes after startup.
13. Daily restarts
A server that runs for days gets slower. On our Australian server a 200-player test took 32.4 ms a frame after 51 hours up and 25.0 ms after a restart (Rust build 25083359, 2026-09-26). A daily restart with a five-minute warning fixes that.
sudo nano /etc/systemd/system/rust-restart.service
[Unit]
Description=Restart the Rust server with a five minute warning
[Service]
Type=oneshot
User=rustserver
ExecStart=/usr/bin/python3 /home/rustserver/rcon.py restart 300
sudo nano /etc/systemd/system/rust-restart.timer
[Unit]
Description=Daily Rust server restart
[Timer]
OnCalendar=*-*-* 05:00:00
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now rust-restart.timer
systemctl list-timers rust-restart.timer
restart 300 counts down five minutes with warnings in game, kicks everyone, saves, and ends the process; the service starts it again 30 seconds later. The time is in the box's own time zone, which timedatectl shows; many servers run on UTC. To use your own, put its name after the time, for example OnCalendar=*-*-* 05:00:00 Australia/Sydney, and check it with systemd-analyze calendar "*-*-* 05:00:00 Australia/Sydney".
14. Patch day and forced wipes
Facepunch releases a Rust update on the first Thursday of each month. Our Australian server's game files are dated 2026-09-03, a first Thursday, and the next is due 2026-10-01. It is a forced wipe: players cannot join until your server runs the new version, and the new version starts a fresh map. Smaller patches in between can also stop players joining; if they report a version mismatch, update.
sudo systemctl stop rust-server
sudo -iu rustserver /usr/games/steamcmd +force_install_dir /home/rustserver/rust +login anonymous +app_update 258550 validate +quit
Then the framework:
- Carbon: run the Carbon commands from step 7 again once Carbon has released a build for the new Rust version.
- Oxide: run the Oxide commands from step 7 again, every time. The update replaced the game files Oxide changes.
sudo systemctl start rust-server
Plugins can break on a big update. The directory's Rust update reports list which plugin files hosted here still compile on each new build.
Wiping by hand
The world save's file name carries a save version (287 on build 25083359), and a monthly update usually brings a new one, so the server starts a fresh map by itself. To wipe the map yourself, between forced wipes or to use a new seed:
sudo systemctl stop rust-server
sudo -u rustserver bash -c 'rm -f /home/rustserver/rust/server/myserver/*.sav*'
sudo systemctl start rust-server
That removes the save and the two backup copies the server keeps beside it (.sav.1, .sav.2). For a different map, change +server.seed in the start script first. Blueprints live in player.blueprints.* in the same folder and survive map wipes. To wipe them too, delete those files while the server is stopped.
15. Backups and snapshots
Snapshots copy the whole disk. Take one before updates, before an operating-system upgrade, and before letting an AI agent work on the box. Some providers take them on a schedule.
File backups keep the world, player data and plugin settings. This script saves the world first, then packs a dated copy and keeps a week of them:
sudo -u rustserver nano /home/rustserver/backup.sh
#!/usr/bin/env bash
cd /home/rustserver || exit 1
mkdir -p backups
python3 rcon.py server.save || echo "Server not answering; backing up the files as they are."
tar -czf "backups/rust-$(date +%F-%H%M).tar.gz" --exclude='*.sav.*' --exclude='logs' -C rust server/myserver carbon
if [ $? -gt 1 ]; then exit 1; fi
find backups -name 'rust-*.tar.gz' -mtime +7 -delete
Running Oxide? Change carbon at the end of the tar line to oxide. Vanilla? Remove the word. The backup leaves out logs and the save's two rotating copies. tar ends with code 1 when a file changed while it was reading, which a running server does now and then; the script treats that as a warning and anything worse as a failure.
sudo chmod +x /home/rustserver/backup.sh
sudo nano /etc/systemd/system/rust-backup.service
[Unit]
Description=Back up the Rust server files
[Service]
Type=oneshot
User=rustserver
ExecStart=/home/rustserver/backup.sh
sudo nano /etc/systemd/system/rust-backup.timer
[Unit]
Description=Nightly Rust server backup
[Timer]
OnCalendar=*-*-* 04:30:00
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now rust-backup.timer
sudo systemctl start rust-backup.service
sudo ls -lh /home/rustserver/backups
A backup on the same disk dies with the disk. Now and then, copy one to your PC:
sudo cp /home/rustserver/backups/FILE_NAME ~/
sudo chown yourname: ~/FILE_NAME
scp yourname@SERVER_IP:FILE_NAME .
A backup you have never restored is a guess. Try it once on a quiet day:
sudo systemctl stop rust-server
sudo -u rustserver tar -xzf /home/rustserver/backups/FILE_NAME -C /home/rustserver/rust
sudo systemctl start rust-server
16. Logs
sudo tail -f /home/rustserver/logs/latest.logshows the game's log as it happens.sudo grep -iE 'error|exception' /home/rustserver/logs/latest.log | tail -20shows the last errors.sudo journalctl -u rust-server -n 50 --no-pagershows the service's own record: starts, stops and crashes.systemctl show rust-server -p NRestarts -p ActiveEnterTimestampshows how often it restarted by itself and when it last started. Check this, not just whether the process exists: one of our own checks once said a server was up while it was restarting every nine minutes (2026-09-24).- Carbon writes its own logs to
/home/rustserver/rust/carbon/logs, Oxide to/home/rustserver/rust/oxide/logs.
17. Common problems
The server is not in the server list
- Wait for "Server startup complete" in the log, then a few minutes more.
sudo ufw statusmust show 28015/udp and 28017/udp. Check your provider's panel firewall too.sudo ss -ulpn | grep -E '28015|28017'should show RustDedicated on both ports.- Join directly with
client.connect SERVER_IP:28015. If that works, the list will catch up. - With Carbon or Oxide, look under Modded, not Community.
Players cannot connect
- The game port, 28015/udp, is blocked: by ufw, or by the provider's firewall.
- A Rust update came out and the server is still on the old version (step 14).
RCON does not answer
- Your home address changed: add a ufw rule for the new one (step 4).
- The password is one Rust refuses (changeme, password, 123456 and a few more). The log says "RCON password is very insecure, RCON is disabled".
- Your tool uses a different port from
+rcon.port.
It started a fresh world, or a custom map never loads
The server was started from the wrong folder. Check WorkingDirectory=/home/rustserver/rust in the service and the cd in the start script. With a custom map, the log shows a NullReferenceException at World.GetCachedHeightMapResolution right after "Downloading World"; we hit exactly this on our own map work (2026-09-12). Custom maps load from a web address set with +server.levelurl. When you change the map, upload it under a new file name: players keep a cached copy, looked up by that address.
I changed a setting and nothing happened
serverauto.cfg in server/myserver/cfg is read after the launch line and wins over it. Put the setting in server.cfg, which is read last, or delete its line from serverauto.cfg while the server is stopped.
The server keeps dying: out of memory
The log just stops, and the service record shows status=9/KILL. Rust's own restart ends the same way, so check the kernel's record before you blame memory:
sudo journalctl -k | grep -i "out of memory"
free -h
systemctl status rust-server shows the server's memory; on Ubuntu 24.04 it also shows the peak. Our Australian server peaked at 8.1 GB during a test on a 15 GB box without swap, and was stopped by the kernel once (Rust build 25083359, 2026-09-26). The fixes, cheapest first: daily restarts (step 13), fewer or lighter plugins, a smaller map, more RAM. A swap file gives the kernel somewhere to put memory instead of stopping the server. It is slow, so a server that lives in it stutters, but it is no longer killed outright.
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
It restarts over and over
Check NRestarts (step 12) and read the last lines of the log before each restart. A plugin that restarts the server by itself can loop. On our US server a popular restart plugin, left on its defaults, compared Carbon's stand-in Oxide version with the latest Oxide release, always saw an update, and restarted the server every nine minutes (2026-09-24).
