Steamworks Documentation
Steam Datagram Relay
Steam Datagram Relay (SDR) is Valve's virtual private gaming network. Using our APIs, you can not only carry your game traffic over the Valve backbone that is dedicated for game content, you also gain access to our network of relays. Relaying the traffic protects your servers and players from DoS attack, because IP addresses are never revealed. All traffic you receive is authenticated, encrypted, and rate-limited. Furthermore, for a surprisingly high number of players, we can also find a faster route through our network, which actually improves player ping times.

This relay network can be used for both peer-to-peer traffic and dedicated servers.

General requirements and tips for porting existing network code

Here are some general things to be aware of that apply to both P2P and dedicated server connectivity.

First, any place where network hosts are identified by a public IP (almost always the case for gameservers) will need to be changed to use a different identifier instead. There are several options for this:
  • For clients and gameservers that signin into Steam, you will usually the SteamID.
  • If your gameserver does not signin to Steam, and you are using the ticket-based authentication flow, you can use any other identifier that is meaningful to you. See SteamNetworkingIdentity.
  • In some codebases, the assumption that network hosts and gameservers are identified using an IPv4 address is ubiquitous, and changing this assumption is a significant amount of work. Indeed, the Steamworks ISteamMatchmaking and ISteamMatchmakingServers APIs have this property, as do some of our own games, such as Team Fortress 2. In this case, you can use the Steamworks "Fake IP" system. A FakeIP is an IP that "looks" like a valid IPv4 address for most purposes, but comes from a reserved address space that is not used on the Internet. By assigning your server a FakeIP, your server can still be addressed using an IPv4 address, and almost everything will "just work". The ISteamNetworkingSockets and ISteamMatchmakingServers systems recognize these special IPs and take appropriate action. They are not routable and do not work for general internet purposes (e.g. you cannot ping them). See ISteamNetworkingSockets::BeginAsyncRequestFakeIP for more info.

Second, you'll need to modify any low-level socket code to use one of the Steamworks APIs for connectivity.
  • Ideally, you can use one of the connection-oriented API ISteamNetworkingSockets interfaces that returns an HSteamNetConnection.
    (Note that these API also supports plain UDP transport, which is very useful for testing. Also, there's an opensource version.)
  • Some codebases are written in a more UDP-like manner, where packets can be sent ad-hoc to any remote host at any time, and not all messages are sent to an established "connection". In these situations, there are two Steamworks features that might be useful.

Using SDR on other platforms and stores

A Networking API and DDoS solution for a cross-platform game is useless if it only works on one platform. In most cases, your players on other platforms and stores can access the relay network, provided that your game meets some basic conditions.
  • Have a version of your game shipping on Steam.
  • Agree to update your game within a reasonable time frame (say, a few months) when asked, if we need to ship a bugfix or security patch.
  • Understand that, unfortunately, we cannot promise that this service will always be available to non-Steam players. In the unlikely event that we need to downgrade this service, we will do everything possible to work with you to avoid disruption to your players, including giving you time to make a plan. The SDK has built in mechanisms such that we can instruct clients to fall back to direct UDP connectivity or attempt NAT punch, but you should also keep this possibility in mind.
  • Have some sort of matchmaking service (SDR refers to this as your "game coordinator") that can issue some authentication credentials. We have a separate SDK for this. See below.

Please contact us for the relevant SDKs and to talk about the fine print. We're still working through the details of the best way to distribute the code to partners, please bear with us.

If you don't meet the criteria above, feel free to use the opensource version of the API for whatever you want.

Peer-to-peer games

For peer-to-peer traffic on Steam, all you need to do to take advantage of SDR is to use APIs such as ISteamNetworkingSockets::CreateListenSocketP2P and ISteamNetworkingSockets::ConnectP2P. Steam will take care of everything else.

On other platforms or stores, as mentioned above, there are some other technical requirements. Specifically, you must provide your own "signaling" service, by which we mean a low-bandwidth, non-latency-sensitive, best-effort-delivery channel capable of forwarding occasional rendezvous messages used to negotiate routing. This requires clients to have a persistent connection to your matchmaking service, such that you can push messages to them. (E.g. a websocket or TCP connection. If clients only talk to your game coordinator using request/response, e.g. http, that won't work.)

Dedicated Servers in Known Data Centers

The peer-to-peer APIs work just fine even when one "peer" is a dedicated server! But there's one important catch: if your dedicated server is not near one of the data centers where we are running relays, then the best relayed route might be slower than the default IP route, and there will be at least some players whose latency is worse than the status quo.

For the optimal dedicated server experience, the server should be run in a known data center that is part of the SDR network. We make sure that relays are running nearby and the relayed route is never too much slower than the default IP route. Servers running in these known data centers connect using a special API. This use case is referred to in the SDK as "Hosted Dedicated Server". Note that this doesn't necessarily mean that Valve is hosting the servers or the relays -- it could be a third party data center that we have established a relationship with, and is known to the Steam Datagram Relay system.

If you are running game servers in a major hosting provider and are interested in using SDR, please get in touch with us. We'll try to work with your hosting company to run relays in the data center. That's the ideal situation, but even if this is not possible we may be able to add the data center to our network.

If you are a dedicated server hosting company and want to join our network so that your customers can take advantage of SDR, please get in touch with us! We have not yet deployed relays in any third party hosting companies, however we are interested in doing this.

Simple Connection Flow to Dedicated Server Without Game Coordinator

If you don't have your own central matchmaking / login service (we sometimes call this the "game coordinator") that assigns players to servers, or just want to keep things as simple as possible, then you can connect to a dedicated server in a known data center using ISteamNetworkingSockets::CreateListenSocketP2P and ISteamNetworkingSockets::ConnectP2P. In this case, the connection begins on the client just like an ordinary P2P connection. Rendezvous messages are sent through Steam, so if the player or server loses their connection to Steam, the connection cannot be made. Also, Steam does not restrict who can attempt to connect, aside from verifying that the player is signed into Steam and owns the game.

Ticket-Based Server Connection Flow

If you do have your own game coordinator service, it is recommended to use a ticket-based connection flow. It's usually only a bit more work compared to a simple P2P-style connection flow, and it offers two important advantages:
  • You only issue tickets to players who should be allowed to attempt to connect, so unwanted connection attempts do not even reach your server.
  • Once a player has a ticket, they can connect to the server even if they lose connection to Steam, the server loses its connection to Steam, the player's computer crashes and reboots, etc. Making reconnection to the gameserver robust against these common failures is especially important for games that penalize players for leaving the game.

A ticket-based connection to a dedicated server over SDR works like this:

At this time, the ticket-based authentication is not available in combination with the FakeIP system.

Game Coordinator SDK

"Game Coordinator" is the term we use to refer to your backend / matchmaking services. There is a separate, small SDK that you can link with your game coordinator which can be used to:
  • Issue tickets to give clients access to gameservers hosted behind SDR
  • Parse with PingLocation_t strings and calculate ping times between these objects
  • Issue identity certificates for players on other platforms and stores
  • Take advantage of certain other advanced features.

The SDK is available here

Authentication using the Game Coordinator SDK

SDR uses two authentication mechanisms:

  • Hosted server tickets are issued by your game coordinator and authorize a specific client to talk to a specific dedicated server for a period of time. Relay tickets are only used for the dedicated server use case. See SteamDatagramRelayAuthTicket.
  • Certificates are used in the traditional way to authenticate, and perform DH key exchange to establish an encrypted channel. Certificates are an end-to-end concept, and can be used in all forms of SteamNetworkingSockets communication, including direct UDP connectivity or P2P. See SteamDatagram_CreateCert from the Game Coordinator SDK and ISteamNetworkingSockets::GetCertificateRequest.

We use a proprietary public key infrastructure (PKI) to authenticate clients and servers. Players are issued individual, short-term certificates, tied to their specific player identity. Steam takes care of this. For gameservers, we typically use longer term certificates that authorize an entire data center for a particular AppID. You will issue those certificates.

Before you can issue tickets and certificates, you'll need to generate a keypair and send us your public key. We will publish a certificate signed by our master CA key that marks your key as trusted for your app(s). Then, offline you will generate a certificate for each data center where you want to run servers, using our certificate tool, and sign it with your private key. You'll distribute those certificates to your gameservers over a secure channel, passing it to your server in the environment (see below).

You'll also use your key to generate tickets, each time a player connects to a gameserver.

Keep your CA private key and the private keys of your certificates safe! If your key leaks and needs to be revoked and replaced, it could lead to a disruption.

Running servers in known data centers

This section documents some technical details involved in running dedicated servers in known data centers.

Environment variables

The dedicated server gets its configuration from environment variables. Note that in Valve data centers, all of these values will be set automatically for you.
  • SDR_LISTEN_PORT: The UDP port where your server will receive traffic from relays. The dedicated server only uses a single socket. (But you can have more than one logical "listen socket" by using "virtual ports". See ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket.) In our data centers, we typically use the 30xxx range.
  • SDR_IP: Your server must have a public IP that can receive "unsolicited" traffic from relays. If the server only has one interface with a public IP, then this will be used. Otherwise, you will need to tell the gameserver what IP to use. The SDR socket will be bound to INADDR_ANY, but this information is needed to fill out the server's SteamDatagramHostedAddress. Note in particular that this will usually need to be set in dev environments, where your server is behind a corporate firewall. (See below.) You can also specify a port, if the public port differs from SDR_LISTEN_PORT.
  • SDR_POPID: The 3- or 4-letter alphanumeric code (SteamNetworkingPOPID) of the data center, in production. In development environment, leave this blank.
  • SDR_PRIVATE_KEY: The private key from your certificate. It's an OpenSSH PEM block that begins with "-----BEGIN OPENSSH PRIVATE KEY-----".
  • SDR_CERT: Your signed certificate. It's a proprietary format PEM-like block that begins with "-----BEGIN STEAMDATAGRAM CERT-----".
  • SDR_NETWORK_CONFIG: Full path to a local, recent copy of the SDR network configuration file for your app. If this variable is not set, then to obtain the network configuration the server will fetch the copy using HTTP at boot time. For optimal performance you can periodically (e.g. once an hour) download the latest configuration and save it locally, so that a network hiccup doesn't cause any disruption. This is how Valve servers are configured.

Running in a dev environment

Because ISteamNetworkingSockets supports plain UDP connectivity, it's usually best to start by getting your code working through this interface over UDP, without worrying about relays.

We suggest that your server code use the presence of the SDR_LISTEN_PORT environment variable to decide whether your server should listen for SDR. You can use ISteamNetworkingSockets::GetHostedDedicatedServerPort to fetch the value.

In development, you will leave SDR_POPID blank. When SDR_LISTEN_PORT and SDR_POPID is blank, the POPID is set to the special 3-character code "dev".

In general, authentication is disabled for servers in the "dev" environment. (Clients and relays will both allow connections to "dev" servers without a signed cert, as long as they have a signed ticket.) You will need another mechanism to authenticate with your game coordinator. And your game coordinator needs to be careful when it issues tickets to any servers claiming to be in "dev"!

Your server needs to be able to receive unsolicited public traffic, which means that if it doesn't have a public IP, you'll need to setup a port forward in your firewall. And you'll probably need to set SDR_IP with the proper public IP (and port, if it differs from SDR_LISTEN_PORT).