This flake is for running a dedicated "Motor Town: Behind the Wheel" dedicated server.
Use this flake as an input for your flake.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
motortown-server.url = "github:ASEAN-Motor-Club/motortown-server-flake";
};
outputs =
{ self, nixpkgs, motortown-server, ... }@inputs: {
# Your flake outputs here
}
}Include nixosModules.default as a module in your NixOS configuration.
{
### in configuration.nix, or as a module passed into nixpkgs.lib.nixosSystem
services.motortown-server = {
enable = true;
enableMods = false;
user = "steam";
openFirewall = true;
credentialsFile = /path/to/dotenv/file;
dedicatedServerConfig = {
ServerName = "Test Server";
ServerMessage = "Welcome";
Password = "";
MaxPlayers = 10;
MaxVehiclePerPlayer = 10;
bAllowPlayerToJoinWithCompanyVehicles = true;
bAllowCompanyAIDriver = true;
MaxHousingPlotRentalPerPlayer = 1;
MaxHousingPlotRentalDays = 7;
HousingPlotRentalPriceRatio = 0.1;
bAllowModdedVehicle = false;
NPCVehicleDensity = 0.2;
NPCPoliceDensity = 0.1;
bEnableHostWebAPIServer = true;
HostWebAPIServerPassword = "hackme";
HostWebAPIServerPort = 8080;
Admins = [
{
UniqueNetId = "12345";
Nickname = "Admin1";
}
{
UniqueNetId = "54321";
Nickname = "Admin2";
}
];
};
};
}Before you can run this service successfully, you have to run steam at least
once under the user you provided, in order for the dedicated server to launch successfully.
A dedicated motortown-server-update systemd service handles game updates. It stops the server, runs steamcmd to update, then restarts — all in one shot.
The backend writes a trigger file watched by a host systemd .path unit. This is the same pattern used for restarts:
# From the host or backend (inside the container):
systemctl start motortown-server-update.serviceOr via the trigger file:
echo "update requested at $(date)" > /var/lib/motortown-update-trigger/triggerThe host's motortown-update-triggered.service clears the trigger and starts the update. The update service stops the server, runs steamcmd, then starts the server again.
Set the UPDATE_MOTORTOWN_SCRIPT environment variable on the amc-backend service. The backend can call this script to trigger an update cycle.
The initial game download still happens automatically via preStart when DedicatedServerConfig.json does not exist (first boot). Subsequent updates should use the update service.
Mods are stored in the MotorTownMods submodule. We use a branch-based versioning system where each release has its own branch (e.g., release/v19).
- Set
services.motortown-server.modVersion = "dev";in your NixOS configuration. - Make changes to the Lua scripts in
./MotorTownMods/Scripts. - If you have a new compiled DLL, place it in
./MotorTownMods/dlls/main.dll. - Important: Because this is a Flake, you must stage your changes for Nix to see them:
git add MotorTownMods
- Deploy as usual. Nix will bundle your local
./MotorTownModsfolder.
- Make sure your changes on the
masterbranch in theMotorTownModssubmodule are ready. - Create and push a new release branch:
cd MotorTownMods git checkout -b release/v20 git push -u origin release/v20 - GitHub Actions will automatically trigger, compile the project on Windows, and commit the resulting
main.dllback to therelease/v20branch. - Get the commit hash of the new release:
git rev-parse HEAD
- Update
mods.nixin the parent repository:- Add the version to
ue4ssVersionMap. - Add the version and its commit hash to
revMap.
- Add the version to
If you need to push a fix to an existing release branch (e.g., release/v19):
- Push the changes to the branch in the submodule.
- Wait for the CI to finish and commit the new DLL.
- Update the commit hash in
mods.nix'srevMap. This is required to keep the build "locked" and pure-compatible.
For rapid development iteration, use the scripts/deploy-dev-mod.sh script to deploy UE4SS mods (like MTDediMod) directly to a remote NixOS server without going through the full release process.
The deployment script (scripts/deploy-dev-mod.sh) automates:
- Building the mod package using Nix
- Syncing mod files and shared DLLs to the server
- Fixing permissions for container users
- Optionally restarting containers or reloading mods via API
- SSH Access: You need SSH access to the target server (e.g.,
root@asean-mt-server) - MTDediMod Source: The mod source should be in
./MTDediModor a custom path - Shared DLLs: Windows DLLs (luasocket, cjson, ssl, etc.) should be in
../sharedrelative to the script or set viaSHARED_PATH - Nix Package Command: The mod must have a
nix run .#packagecommand that builds to./package/
Deploy to a server (builds automatically if needed):
./scripts/deploy-dev-mod.sh root@asean-mt-serverThe script will:
- Build the mod package (unless
package/already exists) - Rsync files to
/var/lib/mtdedimod-dev/ue4ss/on the server - Copy shared DLLs to
/var/lib/mtdedimod-dev/ue4ss/Mods/shared/ - Fix permissions (
steam:modders)
Deploy and restart the container:
./scripts/deploy-dev-mod.sh root@asean-mt-server --restartDeploy and restart a custom container:
./scripts/deploy-dev-mod.sh root@asean-mt-server --restart motortown-server-devDeploy and hot-reload mods via API (no container restart):
./scripts/deploy-dev-mod.sh root@asean-mt-server --reloadSkip building (use existing package):
./scripts/deploy-dev-mod.sh root@asean-mt-server --no-buildCustom mod path:
./scripts/deploy-dev-mod.sh root@asean-mt-server --path /custom/path/to/MTDediMod
# Or use environment variable
MTDEDIMOD_PATH=/custom/path ./scripts/deploy-dev-mod.sh root@asean-mt-server| Mode | Command | Use Case |
|---|---|---|
| Basic | ./scripts/deploy-dev-mod.sh <target> |
Deploy changes without server restart |
| Restart | --restart |
Apply changes requiring full container restart |
| Hot Reload | --reload |
Reload Lua scripts without downtime (via API) |
| Quick Sync | --no-build |
Skip build, sync existing package only |
Typical workflow for script changes:
- Make changes to your Lua scripts in
MTDediMod/ - Deploy with hot-reload:
./scripts/deploy-dev-mod.sh root@asean-mt-server --reload
- Test your changes immediately (server stops briefly, then reloads mods)
For compiled mod changes (C++ DLLs):
- Make changes to your C++ code
- Force rebuild and restart:
rm -rf MTDediMod/package ./scripts/deploy-dev-mod.sh root@asean-mt-server --restart
Quick sync without rebuild:
If you've already built locally and just want to sync files:
./scripts/deploy-dev-mod.sh root@asean-mt-server --no-build --restartCustom shared DLLs path:
SHARED_PATH=/path/to/shared ./scripts/deploy-dev-mod.sh root@serverEnvironment variables:
export MTDEDIMOD_PATH=/custom/mtdedimod
export SHARED_PATH=/custom/shared
./scripts/deploy-dev-mod.sh root@asean-mt-serverPackage builds with root ownership:
If files in package/ are owned by root, remove the package and rebuild:
sudo rm -rf MTDediMod/package
./scripts/deploy-dev-mod.sh root@asean-mt-serverPermission errors on the server:
The script automatically fixes permissions, but if issues persist:
ssh root@asean-mt-server "chown -R steam:modders /var/lib/mtdedimod-dev/ue4ss/ && chmod -R u+w /var/lib/mtdedimod-dev/ue4ss/"Reload API not responding:
Ensure the server has the web API enabled and the correct port (55000/55001):
bEnableHostWebAPIServer = true;
HostWebAPIServerPort = 8080; # Or your custom portBuild not detecting changes:
Since this is a Nix flake, stage your changes:
cd MTDediMod
git add .
cd ..