The advantages are obvious: everything on one server greatly simplifies code architecture, deployment, provisioning, etc., and renting one server instead of three is most likely going to be cheaper.
But let’s look at the relevant concerns, and why you might not want to do this.
First of all, isolation. If you put things on separate servers, then one server going down doesn’t take the others with it, and a process going haywire on one server only affects the others to the degree in which they depend on it – e.g., if your game starts eating up all the RAM and causes the game server to grind to a swapping halt, then obviously players won’t be able to play the game anymore, but the website, forum, and database will happily keep churning along.
Then, scalability. Scaling along the service axis (i.e., scale out individual parts of the system) is the easiest and most effective way of gaining performance by adding more hardware, so if you design this into the system from day 1, you will have an easier time scaling when you need to. Having clear network boundaries between services also means that you can run most of them redundantly, and load-balance them for additional scalability and reliability (e.g., you may have several game servers, running independently except for the persistence layer that they all talk to, so that gives you more reliability and more computing power for the game logic). Having explicit interfaces between services also means you can apply caching between any two of them, where and when it is appropriate, using off-the-shelf solutions.
Security wise, it’s a two-edged sword. Having everything on one server makes for a harder shell (that is, your services need to make fewer connections outside of localhost), but splitting things up improves isolation (harder to escalate from the website to the game server).
DDoS is something to worry about, but not a lot – if someone is going to target you, then they can DDoS your game server just as easily as your web server, and if it’s the usual stuff, then they’re going to hammer your entire IP range anyway, which means all your servers are going down one way or another. And, as you noted, DDoS protection is available at the infrastructure level, and while incidents do happen, leaving it to the hosting provider is the way to go.
A more interesting concern is plain DoS (i.e., not distributed, but exploiting possibilities of generating a lot of work for your server with small payloads). Unlike DDoS, exploiting DoS requires finding a suitable request, and that request is going to be different for every service. So if one of your services is vulnerable, and you have everything on the same server, then the whole server is going down; but if you have split things up, then the attacker needs to find a fresh exploitable vulnerability for every server they want to bring down. Then again, you don’t necessarily need to isolate things at the server level; running things in separate processes, with RAM and CPU quota, could also do the trick.
Then there’s the performance tuning aspect. A web server is typically optimized for network throughput, but doesn’t need fast disk I/O; a database server’s bottleneck is disk throughput; a game server needs to prioritize latency over throughput; etc. With a multi-server setup, you can tune each server to the needs of its service, while having everything on the same server means you have to compromise.
Now for the non-obvious downsides of the multi-server approach.
First‚ you might not need any of those benefits ever. A dedicated server with a good database engine can pack quite a punch; unless we’re talking tens of thousands of visitors per hour, you don’t really need to worry about it. And unless you are handing out SLA’s, or 24/7 availability of your game and forum are of critical importance, going crazy on the reliability isn’t really worth it either.
Resource efficiency is also a concern: when everything runs on the same server, resources can easily be shared between them, but if every service has its own server, you need to decide how much RAM, CPU, and disk space to allocate for each beforehand, and because you need headroom for each of them, you will end up having more unused resources most of the time. For example, both the web server and the game might need up to 1 GB of RAM each at peak, but average at 500 MB – but they practically never peak at the same time, so in fact just having 1.5 GB would be enough (500 MB for each, plus another 500 headroom for the occasional peak).
Scaling things out over multiple servers also introduces a communication overhead – loopback connections are at least an order of magnitude faster than a fast ethernet connection, and even outperform virtual network connections within the same VM host (though not as drastically). Having to go through a network stack at all adds overhead as well – you need to serialize and deserialize at every network boundary, and that means additional work on both sides, and can greatly complicate development and maintenance.
So here’s what I would do:
- Start with a single server
- But design your system such that splitting it up into separate services remains a possibility – that is, write modular code, and possibly even split things up into separate processes where that is feasible right now.
- Keep an eye on usage statistics and server load, and start preparing a scaling strategy when things approach the edge of your comfort zone. IIRC Google has a “10x rule” that says all systems should be able to handle 10x the current load – that’s quite drastic, but being able to scale by a factor of at least 2 is the minimum headroom I’d want.