Overview
The standard publishing workflow for Space Station 14 looks like so:- Builds are periodically created by a CI system like GitHub Actions.
- Build files (client and server zips) are sent to a central server. Server builds get indexed and configuration injected for client CDN, client files are ingested so they can be downloaded by the launcher.
- Game servers (via SS14.Watchdog) get notified of update, and automatically download new server builds from central server.
- Injected game server configuration is used to inform clients where they can download files.
- Receiving new builds directly from GitHub Actions.
- Serving game server builds for access by game servers (watchdog).
- Automatically notifying watchdogs of the new update.
- Providing client delta downloads.
Concepts
Robust.Cdn currently serves two core functions:- Managing server manifests
- Managing client delta downloads
It is possible to run Robust.Cdn without making use of the server manifest support. In fact before 2.0, Robust.Cdn only did client CDN. See the rest of the documentation for details.
Installation
We provide official container images of Robust.Cdn via GitHub Container Registry. Otherwise, we also have instructions for manually publishing the project via the .NET SDK.Container image
The latest stable image of Robust.Cdn isghcr.io/space-wizards-federation/robust.cdn:2. Information about the container:
- Listens on port 8080
- Default UID/GID is 1654
- Important volumes to mount:
/app/appsettings.json: primary config file./builds: contains server/client build zip files./manifest: contains SQLite database for server manifest operations./database: contains SQLite database for client content downloads.
docker-compose.yml, please modify it to your needs.
builds, manifest and database folders. If you get an error about unable to open database file then try the below commands.
Manual compilation
If you hate containers, you can manually publish Robust.Cdn and deploy the files yourself. For this you will need Git and the .NET 10 SDK. The server that will run the build needs the matching ASP.NET Core Runtime installed, but does not need the SDK itself. Clone the git repo, then publish:Robust.Cdn/bin/Release/net9.0/linux-x64/publish. You can copy these into some random location you fancy like /opt and run Robust.Cdn from there. For example:
Configuration
Robust.Cdn is an ASP.NET Core app, so it supports configuration both via config file and other sources such as environment variables. You can see ASP.NET Core’s documentation for a more in-depth overview. Most configuration of Robust.Cdn is done via theappsettings.json config file. Here is a complete reference of its contents:
You should go over this config file in full to understand what you are setting up.
Example reverse proxy configs
Robust.Cdn is a HTTP-based service, so you’ll likely want to run it behind a reverse proxy of some kind. There are a few things to make sure of:- When using multi-request publishing, you should set the maximum client body size to fit the entire client download at once.
- When using one-shot publishing, you should set the request timeout high enough (usually more than a minute or two).
Do not put it behind Cloudflare
Nginx
This example is intended to go into an existingserver block of your configuration (TLS termination, server name, etc…)
Caddy
This is an example Caddyfile to go into an existing block for the domain with the CDN. If you are putting this in a path you can just put all these under the path.Setting up publishing
GitHub Actions
If your fork’s repository is hosted on GitHub, the easiest way to automatically publish new builds to Robust.Cdn is via the GitHub Actions configuration available in the codebase. This is how official Wizard’s Den builds are published.- Edit
Tools/publish_multi_request.pyto modify the “configuration parameters” at the top of the script:
ROBUST_CDN_URLshould be the URL at which Robust.Cdn is accessible.FORK_IDshould be the ID of the fork you configured inappsettings.json
-
Create an Actions secret on your GitHub repository with name
PUBLISH_TOKEN, containing theUpdateTokenspecified for your fork inappsettings.json. - Make sure the “Publish” workflow is running, or trigger it manually.
Custom
For people looking to do custom publishing workflows without GitHub Actions, you can also use theTools/publish_multi_request.py script. I recommend you look at the Actions workflow as a reference for the required steps.
Watchdog configuration
Configuration SS14.Watchdog to use your new Robust.Cdn for getting builds is pretty easy. In the instance configuration, enter something like this:NotifyWatchdogs in Robust.Cdn’s fork configuration, so it notifies SS14.Watchdog when a new version is available. Check the reference up above.
Builds HTML page
Robust.Cdn generates a simple HTML web page to allow people to manually download the latest server builds. This page is available automatically at/fork/<fork_id>.
For example: Wizard’s Den builds.
Custom PathBase
If you can’t have subdomains for some reason (seriously, you should use subdomains if you can), you will want to mount multiple services behind the same domain with a reverse proxy such as nginx. When you do this you need to setPathBase in the config file to make links in the HTML builds page work. Other API functionality is not affected by this.
For example, if you want to host the CDN under https://example.com/cdn/, you should configure it as such:
Private forks
A fork can be marked as “private”. This prevents Robust.Cdn from giving unauthorized people access to server builds, which is desirable for forks with secret content. Access is restricted via HTTP Basic authentication. Usernames and passwords for this can be configured in the fork configuration. To give the watchdog access to these builds, you can configure it as such in the instance update configuration:Builds file layout
Robust.Cdn stores and expects build zips in theFileDiskPath directory (/build when using container image). Files in this directory have a pretty simple structure of <fork>/<version>/<file>.zip. For example:
Troubleshooting
504 gateway timeout during publish
Increase your reverse proxy’s response timeout. In nginx this is controlled viaproxy_read_timeout.
Connection errors during publishing (multi-request publish)
Make sure you have your reverse proxy’s max body size set high enough to allow404 not found error on CDN API while publishing
Make sure you are using the latest version of Robust.Cdn. Version 2.2.0 added a new publishing mechanism that is used by the upstream infrastructure.Migration from Robust.Cdn 1.x
If you were hosting an existing installation of Robust.Cdn from before multi-fork/server manifest support was added (1.0), this part of the guide will help you migrate. As part of multi-fork and manifest support, the following changes will need to be made to your setup, at the bare minimum:Cdn.UpdateTokenin configuration has been moved to fork configuration.Cdn.VersionDiskPathhas effectively been changed toManifest.FileDiskPath. Note that the file layout is different, you will need to manually move the builds one folder down to be underneath the fork folder (see above).
Cdn.DefaultFork in the configuration so it knows what fork to assign these versions to. Existing URLs (for replays etc) will keep working after this, as configuring Cdn.DefaultFork will make the CDN internally map the old /version/{version}/* URLs to the new ones under the specified fork.
After making the above changes, newer Robust.Cdn can still be used with the old publishing workflow (using gen_build_info.py and all the other scripts). Just make sure to account for the change in file structure and such. Obviously we recommend moving to the new built-in publishing system as soon as possible, however.
Ingesting existing server manifest contents
You can manually ingest your existing server manifest into the manifest database with the following Python script. Note that this is only really necessary if you care about being able to easily access old server versions via the HTML page or such, skipping this step This is very janky and you’ll need to publish at least one build normally for the JSON server manifest to be re-cached and become available. But hey, it works. If the script doesn’t work because you don’t havedateutil available, on Python 3.10+ you can remove the dateutil code by replacing dateparser.parse with datetime.fromisoformat.
Robust.Cdn API reference
This part of the guide will explain all of Robust.Cdn’s API endpoints that you can use and interface with.Authentication
Some API endpoints may require authentication:- Fork control endpoints such as publish need
Authorization: Bearer <updateToken>, with theUpdateTokenspecified in the fork configuration. - Endpoints to access server files require Basic authentication if the fork is configured as private.
Publishing
There are two separate APIs to publish: “one-shot” and “multi-request”. The one-shot API is under/fork/{fork}/publish, while the multi-request API is under /fork/{fork}/publish/{start,file,finish}. We recommend the multi-request publishing API, and it is also what the official publishing scripts use.
GET /fork/{fork}
Gets a nice human-readable HTML page about the last builds available.
POST /fork/{fork}/control/update
Instructs the client CDN to re-scan for new files. You can manually run this when not using Robust.Cdn’s server manifest support and only using the client CDN. You will need to put the files in the correct layout as specified below.
This require authentication.
GET /fork/{fork}/manifest
Gets a JSON list of every server build available for a fork.
POST /fork/{fork}/publish
Publishes a new version to the CDN in a single API request. This is as opposed to the “multi-request” API described below.
It expects a JSON body with the following information:
POST /fork/{fork}/publish/start
Start a new publishing operation that involves multiple subsequent API requests. The initial JSON request body is as follows:
POST /fork/{fork}/publish/file
Add an extra file to an in-progress publish.
The file contents are provided in the request body as application/octet-stream. Additional metadata should be provided in the following HTTP headers:
Robust-Cdn-Publish-File: the name of the file being published. Usually this is something likeSS14.Client.ziporSS14.Server_win-x64.zip.Robust-Cdn-Publish-Version: the version number being published to (provided before).
POST /fork/{fork}/publish/finish
Finishes publishing a new version started before.
POST & OPTIONS /fork/{fork}/version/{version}/download
Client CDN download endpoint for a version. See Delta Updates for details.
GET /fork/{fork}/version/{version}/file/{file}
Downloads a server or client build zip from a version. File is the file name.
GET /fork/{fork}/version/{version}/manifest
Client CDN manifest endpoint for a version. See Delta Updates for details.
POST & OPTIONS /version/{version}/download
Fallback endpoint that maps to the DefaultFork, if configured. This is for URL compatibility with old Robust.Cdn setups.
GET /version/{version}/manifest
Fallback endpoint that maps to the DefaultFork, if configured. This is for URL compatibility with old Robust.Cdn setups.