This document is about: SERVER 5
SWITCH TO

This page is a work in progress and could be pending updates.

Certificate Setup

Follow instructions carefully. For the sake of simplicity and consistency we will use the same domain name "photon.example.com" throughout this page. We will also try to keep changes to the minimum mainly by preserving defaults. Some steps may seem optional or trivial but we kept them for consistency and completeness.

General Guide

To allow your clients to connect to your self-hosted Photon Server using a Secure protocol proceed as follows.

  1. Obtain a TLS/SSL certificate:
    a. For development purposes, you can generate a self-signed certificate. See "Generate Self-Signed Certificate" section.
    b. For production servers, acquire a certificate that is signed by a trusted Certificate Authority.
  2. Configure the listener(s) 'to be secured' in "PhotonServer.config":
    i. Enable "Secure" attribute.
    ii. Optionally add <ServerCertificate> node(s) per listener for advanced configuration of your certificate(s). Read more here for details.
  3. Copy/paste the certificate file(s) to the expected folder. By default it should be under "deploy\bin_Win64\certs". If you want to change the folder path take a look here. By default server expects both certificate and private key in the same file called "server.pem". If you want to split them or choose different file name, take a look here.
  4. Start or restart your Photon Server.

WebSocketsSecure Step by Step

In this section we will go through how to setup a self-hosted Photon Server that accepts WebSocketSecure connections using a self-signed certificate.

  1. Get SDK:
    1. Download v5 SDK.
    2. Unzip it.
    3. Download (free) license and put it in "deploy\bin_Win64" next to PhotonSocketServer.exe.
  2. "PhotonServer.config": listeners.
    1. Open "deploy\bin_Win64\PhotonServer.config" and edit it.

    2. Uncomment the 3 HttpListeners with Type="WebSocket" and marked Secure="true", respectively ports 19093 (NameServer), 19091 (GameServer) and 19090 (MasterServer). As follows:

      XML

      <HTTPListener
        Name="*:[PORT]::Master"
        IPAddress="0.0.0.0"
        Port="19090"
        DisableNagle="true"
        InactivityTimeout="10000"
        Secure="true">
        <Routing>
          <Route 
            Url="/*" 
            OverrideApplication="Master"
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      <HTTPListener
        Name="*:[PORT]::Game"
        IPAddress="0.0.0.0"
        Port="19091"
        DisableNagle="true"
        InactivityTimeout="10000"
        AppDataInactivityTimeout="15000"
        Secure="true">
        <Routing>
          <Route 
            Url="/*" 
            OverrideApplication="Game"
            PingEvery="2000" 
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      <HTTPListener
        Name="*:[PORT]::NameServer"
        IPAddress="0.0.0.0"
        Port="19093"
        DisableNagle="true"
        InactivityTimeout="10000"
        AppDataInactivityTimeout="15000"
        Secure="true">
        <Routing>
          <Route 
            Url="/*" 
            OverrideApplication="NameServer"
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      
    3. Replace "/*" with "/+" in those listeners' URLs (due to a known issue in v5 RC). As follows:

      XML

      <HTTPListener
        Name="*:[PORT]::Master"
        IPAddress="0.0.0.0"
        Port="19090"
        DisableNagle="true"
        InactivityTimeout="10000"
        Secure="true">
        <Routing>
          <Route 
            Url="/+" 
            OverrideApplication="Master"
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      <HTTPListener
        Name="*:[PORT]::Game"
        IPAddress="0.0.0.0"
        Port="19091"
        DisableNagle="true"
        InactivityTimeout="10000"
        AppDataInactivityTimeout="15000"
        Secure="true">
        <Routing>
          <Route 
            Url="/+" 
            OverrideApplication="Game"
            PingEvery="2000" 
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      <HTTPListener
        Name="*:[PORT]::NameServer"
        IPAddress="0.0.0.0"
        Port="19093"
        DisableNagle="true"
        InactivityTimeout="10000"
        AppDataInactivityTimeout="15000"
        Secure="true">
        <Routing>
          <Route 
            Url="/+" 
            OverrideApplication="NameServer"
            PeerType="WebSocket"
            Counters="false" />
        </Routing>
      </HTTPListener>
      
    4. Save "deploy\bin_Win64\PhotonServer.config".

  3. [optional] Master Server address configuration:
    1. Open "deploy\Nameserver.json".
    2. Make sure you set "hostname" to the domain name. In this example: "photon.example.com".
    3. Save "deploy\Nameserver.json".
  4. [optional] Master Server (port + path) configuration:
    1. Open "deploy\NameServer\bin\NameServer.xml.config".
    2. Make sure MasterServerPortSecureWebSocket is 19090 (to match corresponding MasterServer listener port in PhotonServer.config, default is 19090).
    3. Make sure MasterServerWsPath is "Master".
    4. Save "deploy\NameServer\bin\NameServer.xml.config".
  5. [optional] Game Server (address + port + path) configuration:
    1. Open "deploy\LoadBalancing\GameServer\bin\GameServer.xml.config".
    2. Make sure GamingSecureWebSocketPort is set to 19091 (to match corresponding GameServer listener port in PhotonServer.config, default is 19091).
    3. Make sure GamingWsPath is set to Game.
    4. Change PublicIPAddress to the IPv4 address of the machine where the GameServer is running and accessible from MasterServer and clients.
    5. Change PublicHostName to the domain name. In this example: "photon.example.com".
    6. Save "deploy\LoadBalancing\GameServer\bin\GameServer.xml.config".
  6. Self-Signed Certificate:
    1. Generate a self-signed TLS/SSL certificate as shown here.
    2. Copy contents of certificate and private key files into the same file called "server.pem".
    3. Move result file under "deploy\bin_Win64\certs".
    4. Setup DNS for the self-signed certificate domain (see Make Sure Server Is Reachable By Client).
    5. Perform this little Chrome browser hack (see Chrome Console Error: ERR_CERT_INVALID_AUTHORITY).
  7. Start server:
    1. Open PhotonControl.
    2. Start Server as follows: "LoadBalancing" -> "Start As Application".
    3. OpenLogs, inside "deploy\bin_Win64\log\Photon-LoadBalancing-{date}.log", you can find something like this:

    Plain Old Text

    65896: 12:51:13.577 - Config|INFO| HTTP: 0.0.0.0:19093 (*:19093::NameServer) - uses SSL
    65896: 12:51:13.577 - Config|INFO| HTTP: 0.0.0.0:19093 (*:19093::NameServer) - Cipher list: DEFAULT
    65896: 12:51:13.577 - Config|INFO| HTTP: 0.0.0.0:19093 (*:19093::NameServer) - Server Certficate: D:\ExitGames\SDKs\Server\Photon-OnPremises-Server-Classic-SDK_v5-0-12-24441-RC1\deploy\bin_Win64\certs\server.pem
    65896: 12:51:13.578 - Config|INFO| HTTP: 0.0.0.0:19093 (*:19093::NameServer) - Server Domain Name: photon.example.com
    

PUN 2 Client Test

  1. Open Unity and download/import latest PUN 2.
  2. Configure PUN2's PhotonServerSettings:
    • Set "photon.example.com" as "Server".
    • Set "Protocol" to WSS.
    • Make sure "Use Name Server" is checked.
    • Optionally specify "Port" 19093 but 0 should automatically choose default which is also 19093.
  3. Switch Unity Editor build platform to WebGL. This may work depending on your Unity version. Read more about UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED error.
  4. Test from Unity Editor by entering playmode from a PUN 2 demo scene.
  5. Build and run a WebGL demo scene from PUN 2.

JavaScript Client Test

  1. Download latest JavaScript client SDK.
  2. Modify "src\demo-loadbalancing\cloud-app-info.js" and uncomment "Wss:true,". Uncomment "NameServer: ws://localhost:9093" and replace with "NameServer: wss://photonexample.com:19093".
  3. Launch "src\demo-loadbalancing\default.html".

Secure Listeners Configuration

In v5 we use OpenSSL for certificates handling (format, configuration, etc.). In order to make a listener secure (use a certificate) set "Secure" to True. All other certificate related settings require this in order to be effective.

Common Attributes

You can skip all settings if the certificate file(s) path(s) match(es) default expected value(s). "RootCertificates" file can be skipped as it's completely optional and the server can work without it.

For ciphers list string, we recommend TLS >= 1.2 as SSLv3, TLS 1.0 and 1.1 should be deprecated.

  • Secure: True or False to define if this listener uses a secure connection.
  • CipherList: OpenSSL's ciphers list string. See OpenSSL's ciphers documentation page for more information, especially "CIPHER STRINGS" and "EXAMPLES" parts. Default is "DEFAULT". Requires "Secure" to be True.
  • CertificatePath: Absolute path of the directory that contains the certificate file with no trailing slash. You could use macros. Requires "Secure" to be True.
  • RootCertificates: Name of the file containing root certificates if any. Default is "root.pem". Folder is defined by "CertificatePath". Requires "Secure" to be True.
  • MinProtocolVersion: Minimal supported TLS version. For example can be set to "TLS12", default is "TLS".
  • MaxProtocolVersion: Maximum supported TLS version.

Client to Server Listeners

Here are the settings that should be used for the TCPListener, PolicyFileListener or HTTPListener.

  • DefaultDomain: Required if you use multiple server certificates.

Server Certificates Configuration

Example:

XML

<TCPListener>
  <ServerCertificates>
    <ServerCertificate Path=""
     Certificate=""
     Key=""/>
    <!-- add more ServerCertificate here if needed and if you do make sure to set DefaultDomain in the listener -->
  </ServerCertificates>
</TCPListener>
  • Path: Path to the folder containing the certificate and key files. [CERTS] macro could be useful here. By default, if not configured, the path is "deploy\bin_Win64\certs".
  • Certificate: Name of the file containing certificate. By default, if not configured, the file name is "server.pem".
  • Key: Name of the file containing private key. By default, if not configured, the certificate file will be used to read the key also.
  • Password: Optional password for the key.

Server to Server Listeners

Here are the settings that should be used for S2S or WebSocketS2S.

  • Certificate: Name of the file containing certificate.
  • Key: Name of the file containing private key.
  • Password: Password for the key.

Secure Ports Configuration

Example:

XML

<S2S>
  <SecurePorts>
    <SecurePort Port=""/>
    <!-- add more SecurePort here if needed -->
  </SecurePorts>
</S2S>

Generate Self-Signed Certificate

The following are just very basic and simple steps to generate a self-signed SSL certificate quickly for testing and development purposes. We will not give extensive detail about each method, step or command used. Feel free to look up more information on the internet.

You need OpenSSL installed with the binary properly added to the environment variable path. To check if OpenSSL is installed and available, open a cmd window and enter "openssl version".

  1. Prepare a configuration file, e.g. "req.conf" (replace actual values with your own):

    Plain Old Text

    [req]
    distinguished_name  = photon_wss
    x509_extensions     = photon_wss_x509_extensions
    prompt              = no
    [photon_wss]
    # Country Name: 2 letter code
    C = DE
    # State or Province Name
    ST = HH
    # Locality Name
    L = Hamburg
    # Organization Name
    O = ExitGames GmbH
    # Organizational Unit Name
    OU = Photon
    # Common Name: This needs to match Photon domain name.
    # The server's DNS names are placed in Subject Alternate Names. 
    # You must include the DNS name in the SAN too (otherwise, Chrome and other browsers that
    # strictly follow the CA/Browser Baseline Requirements will fail).
    CN = photon.example.com
    [photon_wss_x509_extensions]
    keyUsage                  = keyEncipherment, dataEncipherment
    extendedKeyUsage          = serverAuth
    subjectAltName            = @alt_names
    [alt_names]
    # if you use multiple machines or (sub)domains (e.g. one per Photon server type) add them here
    # you could make use of the  asterisk (*) as wildcard for subdomains
    DNS.1       = photon.example.com
    
  2. Generate certificate and key by running the following command with administrative privileges:

    Plain Old Text

    openssl req -x509 -nodes -newkey rsa:2048 -keyout cert.key -out cert.pem -config req.conf
    

Troubleshooting WSS

This section is mainly for troubleshooting common issues with WebSocketsSecure (WSS) setup (configuration + certificate) using self-hosted Photon Server SDK.

Make Sure To Use Domain Name And Not IP Address

From the client, the server address to connect to should be a domain name and not an IP address.

Make Sure To Use WSS Prefix

From the client, the server address to connect to should have the prefix or scheme "wss://" which indicates that you are using WebSockets Secure protocol.

Make Sure To Use The Correct Port Number

Double-check the port number used to connect to the server. It needs to match the port of the WebSocket Listener of the respective server application as configured in "PhotonServer.config". Read more here and here is the list of default TCP and UDP port numbers.

Make Sure Server Is Reachable By Client

Try reaching the server using "ping" command. For development purposes, if the domain name is not DNS ready yet you can add the IP address to your local "hosts" file. On Windows, it's located under "C:\Windows\system32\drivers\etc\hosts". Add a line with format: <IP Address> <domain name>.

Example:
If the server is on the same machine as the client and your domain is "photon.example.com"

Unknown

127.0.0.1           photon.example.com

Also, don't forget to open the required ports from the server. Read more about "Firewall Settings".

Try Connecting To Photon Server Using UDP or TCP

Try switching the transport protocol to make sure the client can connect to the server.

Try Connecting To Photon Cloud Using WSS

To make sure there is nothing wrong with the client, connect to Photon Cloud and see if it works.

Chrome Console Error: ERR_CERT_INVALID_AUTHORITY

If you encounter this error in Chrome, you can use the following workaround:

If your server address is "wss://photon.example.com:19093":

  1. Open a new tab.
  2. Enter "https://photon.example.com:19093" (Replace "wss://" with "https://" in the server address) in the address bar and click enter.
  3. Chrome will complain about the site not being secure.
  4. Click "Advanced".
  5. Click "Proceed to https://photon.example.com:19093 (unsafe)". This will make Chrome accept your self-signed certificate using wss.
  6. Restart Chrome.
  7. Test your client again.

Chrome Console Error: ERR_CERT_COMMON_NAME_INVALID

You can try the previous workaround used for ERR_CERT_INVALID_AUTHORITY error. Or you need to make sure your certificate uses Subject Alternative Names (SANs). See "Generate Self-Signed Certificate" for how to use OpenSSL to generate a self-signed SSL certificate with SANs.

UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED

Some Unity versions simply cannot work with self-signed certificates and will throw the following error:

System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> Mono.Security.Interface.TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
Read more [here](https://issuetracker.unity3d.com/issues/curl-error-51-unitytls-x509verify-flag-not-trusted-when-making-a-request-to-the-server-using-self-signed-certificate).

Try Guide From Clean SDK

If you encounter issues when configuring WSS for your self-hosted Photon Server, we recommend that you start by downloading a clean SDK version and following the steps provided on this page using it. If you don't encounter the same issue then you need to find out what is wrong with your own custom setup.

Try Starting Photon As An Application

Sometimes when Photon Server is configured to be started as a service some issues may be encountered. We recommend that you follow the steps provided on this page with a Photon Server started as an application.

Read The Server Logs

Always! Check the logs. The server's logs' files' locations can be found here.

Back to top