DEV Community

Cover image for Building a full-stack Aavegotchi minigame - Part 3: Deploying your game
Caleb Coyote
Caleb Coyote

Posted on • Updated on

Building a full-stack Aavegotchi minigame - Part 3: Deploying your game

In part 1 of the tutorial we created gameplay using Phaser 3, then in part 2 we created a server to verify the scores submitted to the leaderboard.

All we got to do now is deploy it! However, due to the nature of our app, it isn't as simple as uploading a HTML file to a web hosting service.

Instead, our backend server and front end application have different requirements to be hosted and accessed on the World Wide Web, and therefore need different solutions.

You can follow along from the previous lesson by cloning the end result of the previous lesson. Bare in mind you will need to set up a firebase project and assign the project keys in the repo to get it to work.

World wide web

 

End result

By the end of this tutorial your game will be accessible to the Aavegotchi masses to play and compete!

We will be using Google Clouds Compute Engine to host and deploy our web-socket server onto a Virtual Machine. We will then use Firebase to host our React app and ensure that both the Server and Front end can communicate with each other.

Unless you have coded it to work otherwise, you wont be able to play the game without owning an Aavegotchi. You can buy one here or you could remove the development mode requisite within app/src/pages/Home to allow everyone to be able to select Use Default Gotchi without the requirement of owning an Aavegotchi.

 

Step 1) Setting up a virtual machine

First you will need to get set up on Google Cloud Platform, you can use my referral code to get $50 credit, which should be more than enough for this project.

If you have a Google account, go to Google Clouds Console and in the top right select CREATE PROJECT.

Create project

Then set the name of your project to whatever you like.

Name project

It will take a couple of seconds to create the project, but once it does you will be presented with your Projects dashboard.

In the side menu, navigate to Compute Engine -> VM Instances.

VM instances in side menu

Enable the Compute Engine API.

Then select Create Instance.

Give it a name, select your region.

For machine configuration, select what works best for you depending on your app. Flappigotchis server is very simple so I will be selecting the smallest machine of the E2 series.

Then for the Firewall select allow HTTP and HTTPS traffic so that the browser is able to connect.

Then click create. It will take a minute or so to set up.

 

Step 2) Set up domain

Later on we will be setting up TLS (Transport Layer Security) for our server. For that we are going to need a domain name.

If you already have one to hand then great, otherwise you can get one from Google Domains.

Once you’ve got your domain name. Go back to your VM instances and copy the External IP to your clipboard.

Copy external IP

Now go to the side menu, scroll down, and under Networking select Network services -> Cloud DNS.

Cloud DNS

Enable the API if you haven’t done so already, then create Zone.

Set your name and your DNS name to the domain. Ensure that DNSSEC is off.

Zone config

After clicking create, a zone will be populated with NS and SOA records.

To point your registered domain name to the IP address of the hosting server, you must set an A record to your zone.

To do this:

  1. Click Add Record Set
  2. Select A from the Resource Record Type menu
  3. In DNS name put server
  4. Under IPv4 Address, paste the External IP address from your instance
  5. Click create

It will take a few minutes to become active.

Alt Text

To update the name servers in Google domains:

  1. Go to Google Domains
  2. Click the domain you set up prior
  3. Click DNS from the left side menu
  4. At the top click Custom
  5. Copy all 4 NS records from the Zone details page one at a time and paste them into the Name server inputs.
  6. Click save
  7. Click switch to these settings

To verify your changes were successful in your terminal run
dig +trace server.example.com where example.com is the domain you registered.

You should see at the end of the output the IP_Address of your virtual machine

server.example.com. 300 IN  A   34.105.146.34
;; Received 68 bytes from 216.239.36.109#53(ns-cloud-d3.googledomains.com) in 51 ms
Enter fullscreen mode Exit fullscreen mode

 

Step 3) Installing dependencies on Virtual Machine

Now we need to prepare our Virtual machine. To do this we use the Cloud Shell to access the machines terminal.

Alt Text

To log into the virtual machine, in the Cloud shell terminal run (replacing zone and name with the zone and name of your VM instance):

gcloud compute ssh --zone [zone] [name]
Enter fullscreen mode Exit fullscreen mode

The rest of the tutorial assumes that the distribution of of linux the virtual machine uses is Debian. To check what distribution you are running, in your cloud shell invoke lsb_release -a. If it is different, the concepts will remain the same, it's just some syntax may or may not be different.

At the moment our virtual machine is very vanilla. We are going to have to install a bunch of dependencies to get it to be able to clone and run our application.

These will be

  • Git - So we can clone our project
  • NGINX - To proxy the web requests to the node server
  • Certbot - To provision a TLS certificate
  • UFW - user-friendly front-end for managing iptables firewall rules.

To install them, in your cloud shell run:

sudo apt-get install git nginx certbot python-certbot-nginx ufw
Enter fullscreen mode Exit fullscreen mode

Next we will install Node. For this we need to install the latest Node repository which you can find here, for me the latest stable release is Node.js v16.x so I will run:

curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
Enter fullscreen mode Exit fullscreen mode

Once its installed run:

sudo apt-get install -y nodejs
Enter fullscreen mode Exit fullscreen mode

To install NodeJS and npm.

The final thing we will need to install is ts-node due to the fact our server is written in typescript, because we have downloaded npm. This command is as simple as running:

sudo npm install -g ts-node
Enter fullscreen mode Exit fullscreen mode

 

Step 4) Config NGINX

First we got to config the NGINX so that it can proxy requests to the Node server. To do this, in the Cloud Shell terminal create a new file sudo nano /etc/nginx/sites-available/server.[domainname].com and inside it paste (replacing domainname with the domain you set up earlier):

server {
    listen 80;
    listen [::]:80;
    root /var/www/html;
    server_name server.[domainname].com; 
}
Enter fullscreen mode Exit fullscreen mode

Press CONTROL + X to save the changes then Y to confirm, then ENTER to exit.

Enable the config file by running:

sudo ln -s /etc/nginx/sites-available/server.[domainname].com  /etc/nginx/sites-enabled/
Enter fullscreen mode Exit fullscreen mode

Then because you edited the config, restart NGINX by running:

sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

You can then check NGINX status by running:

sudo systemctl status nginx
Enter fullscreen mode Exit fullscreen mode

 

Step 5) Set up Firewall

As we have installed UFW (Uncomplicated firewall) this step is as simple as running

sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
Enter fullscreen mode Exit fullscreen mode

and then enabling it using

sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Finally, we can check that the rules have configured properly by running:

sudo ufw status
Enter fullscreen mode Exit fullscreen mode

You should hopefully get a response that looks like this:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)
Enter fullscreen mode Exit fullscreen mode

 

Step 6) Provisioning the TLS certificate

Now we have our NGINX and Firewall setup, we can run certbot to create our HTTPS certificates and config the rest of our NGINX.

In your cloud shell terminal run

sudo certbot --nginx
Enter fullscreen mode Exit fullscreen mode
  • Enter your email, agree to the terms of service, choose whether you want to share information or not.

  • Enter domain of the app including the sub domain.

  • Last choice is whether we want to redirect HTTP traffic to HTTPS, which we do so select option 2.

Your private certificate and chain will now be saved onto your virtual machine.

Now all we need to do is add a reverse proxy into our
nginx/sites-available/server.[domainname].com file, so open it up again using:

sudo nano /etc/nginx/sites-available/server.[domainname].com
Enter fullscreen mode Exit fullscreen mode

at the end of the top server object add location:

server {
    ...
    location / {
        # we're actually going to proxy all requests to
        # a Nodejs backend

        proxy_pass http://localhost:8080/;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;

        proxy_set_header Connection 'upgrade';

        proxy_set_header Host $host;

        proxy_cache_bypass $http_upgrade;

    }
}
server {
    ...
}
Enter fullscreen mode Exit fullscreen mode

 

Step 7) Preparing app for deployment

We have everything we need, we can now prepare our app to deploy both front end and the backend.

First thing we want to do is let our app know which url to target when initiating socket.io.

For this we can make use of .env and processes to target the create variables depending on if the app is run in development or production.

If you are carrying on from the previous tutorial, in the app directory you should already have a .env.development file in the app directory. What you should do is create a new file in the app directory called .env.production and copy all the firebase variables over as they will be the same in both development and production.

In .env.development create a new variable called REACT_APP_SERVER and assign it a value of the url of your server when ran on local host. It should look like this.

// app/.env.development
...

REACT_APP_COLLECTION_NAME="test"
REACT_APP_SERVER_PORT="http://localhost:8080"
Enter fullscreen mode Exit fullscreen mode

Now in .env.production we add in two different variables for the COLLECTION_NAME and the SERVER_PORT.

The collection name should be the name of the Database we want our app to target on production mode, therefore it should be different to the one used in development.

The SERVER_PORT should be the url of our servers domain. This by default will connect to port 443 which points to our NGINX setup, which in turns encrypts the request and connects to port 8080 on our virtual machine where our web-socket server will be listening.

// app/.env.production

...

REACT_APP_COLLECTION_NAME="highscores"
REACT_APP_SERVER_PORT="https://server.[domainname].com"
Enter fullscreen mode Exit fullscreen mode

In app/src/game/main.tsx you should see our .env variable is already being used to initiate the socket, so no more needs to be done here with the socket.

However our ServerProvider in app/src/server-store is still only fetching data from the "test" collection, so we need to update it to use the .env variables like so:

// app/src/server-store

...

 export const ServerProvider = ({
  children,
 }: {
  children: React.ReactNode;
 }) => {
  ...

  const snapshotListener = (
    ...
  ) => {
    return database
      .collection(process.env.REACT_APP_COLLECTION_NAME || "test")
      ...
  };

  useEffect(() => {
    const getHighscores = async (_firebase: fb.app.App) => {
      ...
      const highscoreRef = db
        .collection(process.env.REACT_APP_COLLECTION_NAME || "test")
        ...
    }
  }, [firebase]);

  ...
 };

Enter fullscreen mode Exit fullscreen mode

 

Preparing server

For the server we are also going to want to create some .env variables for the names of the Collections we set earlier. So create another .env.development and .env.production and inside put the variables for the collection name:

// server/.env.development

DB_COLLECTION="test"
Enter fullscreen mode Exit fullscreen mode
// server/.env.production

DB_COLLECTION="highscores"
Enter fullscreen mode Exit fullscreen mode

REACT_APP is not necessary as the server isn't a React app.

Then in server.ts replace the collection name with process.env.DB_COLLECTION

// server/server.ts
...

​​const submitScore = async ({tokenId, score, name}: ScoreSubmission) => {
 const collection = db.collection(process.env.DB_COLLECTION);
 const ref = collection.doc(tokenId);
 ...

Enter fullscreen mode Exit fullscreen mode

Now run the app locally and ensure everything is still working correctly.

 

Step 8) Deploying the front end

To host the front end up your app feel free to use any hosting service. Im going to be using firebase hosting purely due to the fact my database is on firebase and my backend is hosted on Google Cloud.

To get started visit the Firebase CLI documentation to learn how to install the Firebase CLI.

Once you have it installed, initiate hosting for the app by going into the app directory in your terminal and running:

firebase init hosting
Enter fullscreen mode Exit fullscreen mode

Select Use an existing project (as you should already have a project set up for your leaderboard in the previous tutorial), and select your project.

For your public directory, type in "build" as thats the folder react constructs after building the app.

For configure as single-page app select Yes as it is a React app and therefore is a single-page app.

And finally for set up automatic build, choose what ever you fancy. Il select no, but if you want to do an automatic redeploy every time you push your code to your main directory in GitHub then select yes.

Your app will now configure itself automatically.

Now to deploy the site, first you have to build your application by running:

npm run build
Enter fullscreen mode Exit fullscreen mode

in your app directory. This will compile your app into an optimised production build in the build folder. Then after it's compiled run:

firebase deploy --only hosting
Enter fullscreen mode Exit fullscreen mode

Once it's deployed the terminal will return the URL to the deployed web app.

If you go to your deployed site, you should have an empty leaderboard, abd when you try running the game the loading bar should get stuck on connecting to server. Thats because we haven't deployed our server app on the virtual machine yet.

 

Step 9) Deploying the back end

We are going to be using git to clone our app into the virtual machine. Therefore we need to ensure our code is up to date on GitHub.

If you were following from the start you should have your own GitHub rep setup for your app. So just run:

git add .
git commit -m "Ready for deployment"
git push
Enter fullscreen mode Exit fullscreen mode

If you haven't got a GitHub repository setup yet, then do so by following these instructions to import project to Github here.

Once that is done, go back to the cloud shell of your app, and log back into your virtual machine.

Press up ↑ on your keyboard to get previously used commands.

Now get the url to your GitHub project:

Url to repo

And clone your Github project into your virtual machine by running:

git clone https://github.com/[username]/[example].git`
Enter fullscreen mode Exit fullscreen mode

You may notice that we have cloned both the app and the server into the virtual machine with this method which is not ideal. You can just clone the server directory, but in terms of ease of managing different versions of your app, this way saves a lot of headache.

If you find your project ends up taking up too much space in your machine, then opt to remove the app from the virtual machine. Or create a separate repo for your server and app directories.

You can now in your virtual machine go to your server directory and install its dependencies:

cd flappigotchi/server
npm install
Enter fullscreen mode Exit fullscreen mode

Now before we can run the app there are a few things we need to add to the project. Those with keen eyes may notice that both our service-account.json and our .env variables are in the .gitignore file. Therefore when we pushed and pulled our code from github, these files wouldn't of been included. Therefore we need to rewrite them within the cloud shell.

Because we only run our server in production mode with the virtual machine, we will just add the .env.production file. To do this, run sudo nano .env.production within the server directory to create and open up a .env file. Then inside copy and paste your variable from before:

DB_COLLECTION="highscores"
Enter fullscreen mode Exit fullscreen mode

Now do the same for the service-account JSON file. Run sudo nano service-account.json and paste in your service account key.

If you are to run sudo npm run start:prod now, then your server should hopefully output a message saying its listening on port:8080!

Hopefully now, when you open your deployed app, it should connect to your server without a hitch and you will be able to play and submit a score to the leaderboard!

 

10) Set domain name for front end

Your game is now live and ready to be tested by the Aavegotchi community! Now we just want to set up our domain name from earlier to point to the front end of our application.

To do this, go to your firebase console, and in the side menu select Hosting:

Hosting

  1. Click Add custom domain
  2. Type in the domain name that you used for the server but without the added server subdomain.
  3. Go back to the Cloud DNS from before and add in both of the A records

A records in Firebase

A records in Firebase

A records inputted into Google Cloud DNS

A records inputted into Google Cloud DNS

The status should now go to pending as it verifies ownership of the domain. This process can take anywhere from a couple of minutes to 24 hours.

Once its verified you should now be able to play your game at your given domain!

 

Conclusion

That's it! Your game is live and ready to be played!

In this lesson you learnt how to securely set up a web-socket server on Google Cloud, as well as deploy your front end application.

Deployed

This 3 part series has been a high level overview of the concepts that go into building a game. There is still more that can be done, so if there is any concepts that you want to see tackled in a future tutorial, comment them down below.

If you have just deployed your own game. Message me on Twitter or Discord to see about running an Aavegotchi EXP event!

Part 4 of the series will likely be how to add a Pay2Play/Play2Earn system into your game. So make sure to follow me @ccoyotedev or @gotchidevs on Twitter for updates on future tutorials.

If you have any questions about Aavegotchi or want to work with others to build Aavegotchi minigames, then join the Aavegotchi discord community where you can chat and collaborate with other Aavegotchi Aarchitects!

If you own an Aavegotchi, you can play the end result of this tutorial series at flappigotchi.com.

Top comments (1)

Collapse
 
gregwoodsfrontier profile image
Richard Chung

Really good job btw. Just the setting up part is getting me dizzy ...