How to what?? Sorry for the messy headline. That’s what happens when you try to cram every relevant aspect of an article into a half-sentence. So here is what I try to say with it: RDS databases on AWS are expensive, and if you don’t utilize them heavily, try to avoid them! On my web space at DomainFactory, I have 10 databases included in my plan, so why not use them instead! Sounds like no big deal, but you need to know some things about SSH tunnels and Unix Domain Sockets to pull it off. Here is what worked for me, and hopefully will help you as well.
The DataServer for my game Network Traders runs on an AWS EC2 instance, the smallest type, t2.nano, you can get. For convenience reasons (and since I tried before unsuccessfully) the database underneath also used an AWS service called RDS (Relational Database Service). Both are included in the free tier you can use for 12 months, but it gets interesting afterwards. On the right, you can see a typical bill for the AWS services I used after the free tier expired.
Opening an SSH Tunnel in C#
$16.88 (+ tax) a month is way too much for a game that is played by a handful of players only. Even for an enthusiast like me. But luckily, there are alternatives. DomainFactory is a typical webhosting service like many others. I am using it, e.g., to host this WordPress blog, which also requires a database. For security reasons, these databases are not accessible from outside. They are meant to be used by your web services hosted by DomainFactory. But it is possible to open an ssh tunnel to your host environment there like this:
ssh -N -L 5001:/var/lib/mysql/mysql.sock ssh-user@domain.tld
Now you can access your databases using port 5001 on your local machine, which forwards all your requests to the remote database.
Now, there are to ways of making use of this. The straight-forward one is to just open this tunnel when your server spins up and leave it open. But that is not the idea – the tunnel should not be open longer than necessary. And anyway, it is only possible to keep two ssh tunnels open at the same time (a limitation by DomainFactory). So better not waste them.
With Network Traders, database access is very sporadic. Whenever a player connects to the server, database access is required. If no player is playing, the connection can be closed. However, I had no idea how to translate the shell command above into C# code for my game server. So I did what people do nowadays if they want to solve a problem: I asked the Generative AI of my trust.
ChatGPT, how do I open an ssh tunnel in C#?
That was easy, wasn`’t it? Well, yes …
Tunnels and Unix Domain Sockets
The code example ChatGPT provides uses the library Renci.SshNet, a widely used C# implementation of the SSH-2 protocol. This approach is, of course, not an invention of ChatGPT, but found in other tutorials as well, such as for MariaDB.
So far so good, but there was one further hurdle I had to grapple with. In the ssh call above you can see that the DomainFactory ssh server does not connect to the database via a TCP port. Instead, it uses a so-called Unix domain socket. This is the common protocol for inter-process communication on Unix-like systems. Unfortunately, SshNet does not support Unix domain sockets!
Well, at least not normally. After spending a couple of hours trying to understand the exact problem (where ChatGPT was no help) and internet research, I came across an issue report on the SshNet issue tracker. In 2017, the contributor Tom Deseyn had already implemented just what I needed, but it had never made it onto the master branch.
What I did then to solve my problem is something I do not recommend to do – I am not sure myself if this is a good idea. I went back to the orphaned branch with the Unix domain socket implementation and cloned it locally. Getting this old version to compile properly required some fiddling about, but I finally made it work on .NET 8. But keep in mind: no bugfixes included since 2017! Since no one has direct access to the game server and the database host, this is probably okay, but it is definitely not ideal. I would love to see this feature included in SshNet officially.
Further Cost Optimizations
After migrating my database from AWS RDS to DomainFactory databases, my monthly bill has reduced drastically. But there was further potential for reducing cost. AWS offers so-called savings plans, where you basically guarantee to use a certain amount of processing time. This planning certainty is reimbursed by Amazon with a considerable rebate.
So everthing should be shiny now, shouldn’t it? I could now run my game server instance for less than $4 a month (in addition to what I pay anyway for the databases). Well, it should … if AWS had not decided to put some pressure on those folks still using IP4 addresses and charge them extra, just from this month on!
But that is to be solved another day.