DEV Community

jtorbett23
jtorbett23

Posted on

Hosting a Godot Server on Oracle Cloud

Introduction

When working on multiplayer projects hosting a server is a key part of being able to share it with others.

In this article we will cover how to host a Godot (4.5.1) Server on an Oracle cloud instance. For this we will cover:

  1. The Godot project
  2. Dockerising a Godot server
  3. Hosting a Godot server to an Oracle instance
  4. Setting up HTTPS with NGINX and letsencrypt
  5. Hosting your client on itch.io

Requirements

  • Godot 4.5.1
  • Docker and a Docker account
  • An Oracle cloud account
    • Oracle has websites for each region so pick your closest
  • An itch.io account
  • A registered domain
    • This is only required if you want HTTPS
    • Personally I use GoDaddy

1. The Godot Project

The Godot project that we will host is using Godot 4.5.1 in compatibility mode and Godot's high-level multiplayer, specifically the WebSocketServer. This is because in this tutorial we will be hosting our client on the web.

As for what the project does, it allows players to join and leave a 2D space where they can move around with their connection ids shown above them.

Project Screeshot

You can find the source code for the project here.

2. Dockerising a Godot server

When dockerising an application it is important to have a clear idea of the steps we would manually take to achieve the same effect. In our case we want to have to have a Linux based version of our game running as a Server.

We can achieve this in the following steps:

  1. Setup a Linux based system to run our Server

    FROM ubuntu:focal AS build
    
    # Install dependenices to download Godot and templates
    RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    unzip \
    wget 
    

    For this we are using the smallest ubuntu docker image I could find and then install dependencies to download Godot.
    (If you know of a smaller one, let me know in the comments)

  2. Install Godot and the templates required to export projects for Linux

    ENV GODOT_VERSION="4.5.1"
    # Download Godot and templates
    RUN wget https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip 
    RUN wget https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_export_templates.tpz 
    
    # Place Godot files in required folders
    RUN mkdir -p ~/.cache ~/.config/godot ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable \
    && unzip Godot_v${GODOT_VERSION}-stable_linux*.zip \
    && mv Godot_v${GODOT_VERSION}-stable_linux*64 /usr/local/bin/godot \
    && unzip Godot_v${GODOT_VERSION}-stable_export_templates.tpz \
    && mv templates/* ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable \
    && rm Godot_v${GODOT_VERSION}-stable_export_templates.tpz Godot_v${GODOT_VERSION}-stable_linux*.zip
    

    Here we use wget to download Godot and the templates for exports from the Godot Github releases.

  3. Export a version of our game for Linux

    # Create a space to build the executable
    RUN mkdir /godotbuildspace
    WORKDIR /godotbuildspace
    
    # Copy our Godot project into the container
    COPY . . 
    ARG EXECUTABLE_NAME
    ENV EXPORT_NAME="LinuxServer"
    ENV EXECUTABLE_NAME=$EXECUTABLE_NAME
    
    # Export the project in debug or release mode
    ENV EXPORT_MODE="debug" 
    RUN godot --export-${EXPORT_MODE} ${EXPORT_NAME} ${EXECUTABLE_NAME} --headless
    

    With Godot downloaded we can now export the project where:

    • EXECUTABLE_NAME: is the name of our final executable
    • EXPORT_NAME: is the name of our Linux export in our export_presets.cfg
    • EXPORT_MODE: is the type of export release or debug. I recommend at this stage using debug as this will allow you to see logs from print() in your Godot code.

    This stage also requires you have setup a Linux export in your export_presets.cfg file. The easiest way to do this is in your Godot editor go to Project -> Export and then Add... -> Linux.

    Linux Export Setup

    For this export preset we are using Options -> Embed PCK = true and Resources -> Export Mode = Export as dedicated server.

  4. Run the exported version as a Server

    # Start a new stage to execute the exectuable as we do not need the Godot files anymore
    FROM ubuntu:focal
    
    ARG EXECUTABLE_NAME
    ENV EXECUTABLE_NAME=$EXECUTABLE_NAME
    COPY --from=build /godotbuildspace/ ./
    EXPOSE 6069/tcp
    EXPOSE 6069/udp
    CMD ["sh", "-c", "./${EXECUTABLE_NAME} --headless -s"]
    

    Finally we run the created executable. For this tutorial:

    • Port 6069 is used, as it is defined as the port the client will connect to here, and will require tcp and udp connections.
    • We run with the flag --headless as this runs Godot without visual elements, which the server will not require.
    • We run with the flag -s as this is how in this project we tell our Godot project to run as a server not a client, the code of this can be seen here.

Now with this file we can build the container with docker build -t mutliplayer-hosting-tutorial-server . and run it with docker run -d -p 6069:6069 -p 6069:6069/udp mutliplayer-hosting-tutorial-server. However, if you do want to use this for local development I recommend using docker-compose.

For later steps we will need to push the image to our docker account so we can pull it on the Oracle instance.

docker build -t <Your Docker Username>/mutliplayer-hosting-tutorial-server .
docker push <Your Docker Username>/mutliplayer-hosting-tutorial-server 
Enter fullscreen mode Exit fullscreen mode

You can find the full Dockerfile here.

3. Hosting a Godot server to an Oracle instance

We are going to use Oracle for hosting our server as you can get two instances for free.

  1. Create the Oracle Instance

    Start by going to the instances section in Oracle Cloud and create a new instance.

    For this we are using Canonical Ubuntu 20.04 image and VM.Standard.E2.1.Micro shape.
    Oracle Image and Shape

    Make sure to download your private and public key for SSH.

    Oracle SSH key

    You can leave all the other settings as default.

  2. Setup Port Connections

    Our server will be communicating on port 6069 on both tcp and udp, so we need to allow connections on those ports.

    For this we need to change our subnet rules to allow this traffic. These subnet rules can be changed for your instance by:

    • Selecting your instance
    • Going to the networking tab and selecting the subnet
    • Then add a new one:

    Oracle Subnet rules

  3. Download docker and run container

    To connect to our server for our local machine we will use the ssh key we downloaded earlier. This can be done with the following command in your terminal:

    ssh -i <Path to your .key file> ubuntu@<Public IP of your instance>
    

    Now on the machine we need to first update the package installer apt and then install docker.

    sudo apt update
    sudo apt install docker.io
    

    Then download your published image and run it.

    sudo docker pull <Your Docker username>/mutliplayer-hosting-tutorial-server
    sudo docker run -d -p 6069:6069 -p 6069:6069/udp <Your Docker username>/mutliplayer-hosting-tutorial-server
    

    Now we can connect from our local client by updating 127.0.0.1 to the public IP address of your server here.

4. Setting up HTTPS with NGINX and letsencrypt

We want to setup HTTPS as the current HTTP setup will work for local development builds of your Godot client if we want to host our client on itch.io we will require a secure connection to communicate with our server.

Currently we are using a websocket connection with ws:// and we will need to use a secure websocket connection with wss:// from a trusted domain meaning we cannot self sign the connection.

To get that secured signed connection we will be using letsencrypt which requires a registered domain to sign our connection as secure.

  1. Security list updates

    With the HTTPS setup we will not be using connection on a the port 6069 directly but instead traffic from the standard HTTPS port 443 will be forwarded to it. This means we can update our security list for the subnet removing 6069 and adding 80 and 443:

    Updated HTTPS Security List

  2. Point your domain to IP of server

    For this tutorial we will be getting our domain from GoDaddy, you can pick up a cheap domain for year for cheap if you do not mind what the name of that domain will be.

    With a domain we need to now setup a A Record, this points our domain to the Public IP address of our server.

    GoDaddy A Record

    This record will point traffic for the sub-domain multiplayer-tutorial for the domain to the public IP address of the server, such that multiplayer-tutorial.<Domain name> will go to the servers public IP address.

  3. Add a NGINX to server

    Now we have our domain setup we need to handle requests coming to that domain and make sure any HTTP connections get redirection to HTTPS.

    sudo apt install nginx
    # Verify that nginx is now running
    sudo service nginx status
    

    Now we want to update our nginx config to send any traffic at the domain we defined to our Godot server. You can find the nginx config file at /etc/nginx/nginx.conf, in this tutorial we will just directly edit this file.

    # Open the config
    sudo nano /etc/nginx/nginx.conf
    

    We will then add the following server block to the http block:

    http {
      server {
        server_name  <Your subdomain>.<Your domain>;
        location / {
        # redirect all HTTP traffic to localhost:6069
        proxy_pass http://localhost:6069;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }
     }
    ...
    }
    

    This will forward traffic for your domain setup to port 6069 and make use of websockets for that connection. We can can then validate the changes with the following:

    # Check the file syntax
    sudo nginx -t
    # Restart the server
    service nginx restart
    
  4. Add lets encrypt

    For this we will need to add a firewall rule to allow letsencrypt to verify our server:

    sudo iptables -L --line-numbers
    #OUTPUT
    Chain INPUT (policy ACCEPT)
    num  target     prot opt source               destination
    1    ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
    2    ACCEPT     icmp --  anywhere             anywhere
    3    ACCEPT     all  --  anywhere             anywhere
    4    ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
    5    REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited
    

    We need to add in a line before the REJECT for traffic on port 80 for letsencrypt and port 443 to allow traffic on a secure connection:

    sudo iptables -I INPUT 5 -m state --state NEW -p tcp --dport 80 -j ACCEPT
    sudo iptables -I INPUT 5 -m state --state NEW -p tcp --dport 443 -j ACCEPT
    # Save the changes
    sudo netfilter-persistent save
    

    Now we can run certbot, the a cli used for letsencrypt, to verify our domain and update our nginx config.

    sudo apt-get install certbot python3-certbot-nginx
    sudo certbot --nginx -d <Your Subdomain>.<Your Domain>
    

    Make sure to select option 2 to redirect traffic to HTTPS.

    This should result in 2 server blocks /etc/nginx/nginx.conf:

    server {
        server_name  <Your subdomain>.<Your Domain>;
        location / {
        # redirect all HTTP traffic to localhost:6069
        proxy_pass http://localhost:6069;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
       }
    
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/<Your subdomain>.<Your Domain>/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/<Your subdomain>.<Your Domain>/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    }
    
    ...
    server {
        if ($host = <Your subdomain>.<Your Domain>) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        server_name  <Your subdomain>.<Your Domain>;
        listen 80;
        return 404; # managed by Certbot
    }
    ...
    

    Note: If certbot fails here, retry after an hour as most DNS records (like the A record we setup) normally take an hour (but can take up to 48 hours) to propagate.

    With this we now have an HTTPS connection we can use for websockets for our domain. Our connection will only stay certified for ~45 days through letscencrypt and will require refreshing our certification, for this I recommend setting up a CRON job on your instance to automate this.

5. Hosting your client on itch.io

With our server now running with a secure connection itch.io will allow the client we upload to it to connect.

To upload our client to the web we first need to export it in Godot as a HTML project. For this make sure to name export the .html file as index.html as itch.io requires this.

This will create a folder with your exported project, which then needs to be compressed to a zip folder.

With your compressed client folder, create a project on itch.io and upload it. Make sure to select your project as HTML.

Finally you can run your web clients, in two tabs and should see two players.

Conclusion

With this you should be able to host your Godot servers for only the cost of a domain name. This is great for hobbyist projects, testing and game jams. I hope this allows you to create more multiplayer projects.

Top comments (0)