Rewriting For Cleaner Code

As Ravensholde approaches Public Beta, I wanted to refactor the games structure to match more like what a professional app would be like.

The file structure is as follows:

Classes
  Blocks
    Block
  Controllers
    Controller
  Database
    Connection
  Helpers
    Helper
  Models
    Model
 Templates
  Admin
  Base
  Game

With composer.json setting the autoload PSR for the Classes.

Index.php has been re-written to work as a router, like so (pseudo code to illustrate):

<?php

require 'vendor/autoload.php';

use Classes\Blocks\Block;
use Classes\Controllers\Controller;
use Classes\Database\Connection;
use Classes\Helpers\Helper;
use Classes\Models\Model;

class Index {

    protected Model $model;
    protected Helper $helper;

    public function __construct(
        Model $model;
        Helper $helper;
    ) {
        $this->model = $model;
        $this->helper = $helper;
    }

    public function execute()
    {
        session_start();

        // A router for a template
        $this->helper->addRoute('method', 'url', function(){
            $model = $this->model;
            $helper = $this->helper;
            $block = new Block($model, $helper);
            require_once('templates/base/template.php');
        });

        // A router for a controller
        $this->helper->addRoute('method', 'url', function(){
            $model = $this->model;
            $helper = $this->helper;
            $controller = new Controller($model, $helper);
            echo $controller-execute();
        });
    }

}

// Only create one connection to be used throughout
$mysqliAdapter = new Connection();
$mysqliConnection = $mysqliAdapter::connection();

// Initialise models and helpers
$model = new Model();
$helper = new Helper($model);

// Initialise the router
$index = new Index(
    $model,
    $helper
);

// execute the router
$index->execute();

This has made the code base much cleaner, and will be far easier to maintain long term.

Building The Web Server

To achieve the best performance of a website, I set out to choose the right software stack.

Firstly, I installed varnish as a full page cache. This required a few configuration changes at:

/usr/lib/systemd/system/varnish.service
ExecStart=/usr/sbin/varnishd \
          -j unix,user=vcache \
          -F \
          -a :80 \
          -T localhost:6082 \
          -f /etc/varnish/default.vcl \
          -S /etc/varnish/secret \
          -s malloc,2G

We change -a to 80, so it listens on port 80 for incoming requests, and we change malloc to 2G to allow it access to more RAM.

Secondly, I installed nginx as the web server, and set nginx to listen on port 8080.

Thirdly, I installed php 8.2 and 8.4 for the different websites. Some configuration changes I made are listed below:

memory_limit = 4G
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60

This gives PHP more memory, and enables PHPs opcache for better performance.

Next I installed redis, as another caching layer. I set a password for authentication.

Lastly, I installed mariadb.

CI/CD With Jenkins

With a recent announcement, Bitbucket stopped dedicated IPs on pipeline runners for free personal projects. As I didn’t want to adjust the firewall to allow all traffic in (Although it still needs SSH authentication) – I decided to get a jenkins server up and running.

  • Created a new cloud server
  • Added it to the existing network
  • Added the existing firewall rules for home SSH
  • Created a new firewall rule to allow jenkins ssh access to the dedicated server
  • Connected Jenkins build to my git repo
  • Configured Capistrano (and gems) to run the deployment
  • On build finish run bundle exec cap production deploy

Server Infrastructure

To host the myriad of websites I run, I had been using AWS. i recently noticed that the performance for what I was paying wasn’t great. I set about to migrate from AWS to hetzner, and make use of a dedicated server for the same cost as what I was paying in AWS.

My infrastructure looks like this now:

To achieve I followed the guide https://docs.hetzner.com/cloud/networks/connect-dedi-vswitch/ and these are the steps I took:

  • Created a new NginxLB cloud server
    • Set up nginx and certbot to handle web traffic on this server.
  • Set the firewall to allow my home SSH and web traffic (80/443) through to the LB server.
  • Created a dedicated hetzner server
    • Used rescue image to install ubuntu 24.04
  • Set the firewall to allow my home SSH through only.
  • Created a vswitch
    • Created a subnet
    • Assigned the dedicated server to the vswitch
  • Set up a cloud network
    • Added a subnet with the vswitch attached
    • Allowed routes to be shown to this subnet
  • Adjusted the dedicated server firewall to allow ports 80 and 8080 traffic through from the private IP of the LB server.
  • Adjusted the dedicated server firewall to allow ephemeral ports through – for loopback calls.

I now have a cloud server which is open to http and https traffic, that pushes the traffic to a dedicated server that is only open to the private network and not public facing.