It depends on your willingness to lose services and your tolerance levels. If you are willing to lose calls “in flight” and be down for a minute or two, there are several inexpensive alternatives. If you need 100% call coverage and no loss of in-progress calls, your solution set gets much smaller and more expensive.
A “warm spare” is an obvious good choice that is easy to implement. Have your main system and the spare configured exactly the same way, but leave the warm spare “inactive”. When the main system fails, (manually or programmatically) cut all of your services and phones to the other server. Of course, there are problems and issues with that, but it’s basically as cheap a solution as you’re going to find.
FreePBX “High Availability” services are an option, but I’d recommend against them. They aren’t particularly resilient and leave you on an (basically) EOL version of FreePBX.
A cloud server could be a good choice, but that puts the onus of operation on your provider, and you still have to maintain your warm spare configuration.
There was some discussion a few months ago about implement a Session Border Controller implementation and letting it do the heavy lifting. This sounded intriguing, but we didn’t get into a lot of detail on how phones would connect, what needed to be done to switch from one server to the other, etc.
Up from there, you get into mirrored active services (two servers, one of which servicing the call, the other pretending to so no calls are lost “on the wire”), but that seems like a really tricky configuration to get right and there are still lots of questions (phone registrations, IP address diversion, etc.) that need to be answered. I’m not convinced anyone has done this reliably with free software, so this may end up being an expensive solution that may not actually work.
Moving your services exclusively to the cloud are an option, but lots of peripheral components (local management, local backup, service assurance, Internet connection performance requirements, and other hardware considerations) become harder and harder to implement. There are many people here that will chime in that letting someone else be responsible for the hardware is a good solution. I’m not one of them. but my experience set is different than theirs, so that’s fine. The advantage of cloud services is that many of them allow you to have backup servers that are actual bit-for-bit duplicates across multiple hardware platforms. Of course, these come with a price as well, so you have to weigh those considerations.
I’m old school (started in programming in the '70s) so I like things like local control of my hardware and not relying on other people and dodgy intermediaries for my critical infrastructure. That’s why my recommendations steer in the direction of warm spares and local backups. If you can tolerate a minute of down-time in the face of a catastrophic loss of a server, then I’d go towards the cheapest solution you can get and start looking through the archives for “Warm Spare”.