The Best DX for scaling VPS Servers (and super cheap)
Chapters13
Overview of a horizontal multi-VM setup that scales VPS instances, enables zero-downtime deployments, automatic multi-server sync, and load balancing to route users to the nearest endpoint for low latency.
Scale VPSs cheaply with Docker Swarm via Docploy, add a global load balancer, and push code with zero downtime across multiple servers.
Summary
Ed from developedbyed outlines a cost-conscious approach to hosting apps on multiple VPSs instead of cloud. He demonstrates three key ideas: spreading traffic with a lightweight load balancer to cut latency, orchestrating deployments across servers with Docploy and Railpack, and keeping the setup secure with SSH keys and optional Cloudflare protection. He compares KVM2 (8 GB RAM, two vCPU) versus cheaper KVM1, and highlights why horizontal scaling beats vertical scaling for uptime. The walkthrough covers provisioning with Hostinger, wiring in GitHub-hosted code, and enabling auto-deploy so updates propagate to all VPSes without downtime. Ed also explains why not using Docker Swarm’s multi-node manager architecture alone is risky for reliability, hence the external load balancer approach. Finally, he duplicates a working setup across three VPSs and demonstrates instant code-spot updates on all nodes. Expect concrete steps: setting up TanStack Start with Nitro, pushing via Railpack, adding domains, and securing servers with a VPS hardening script and Fail2Ban. The takeaway is a repeatable, low-cost DX pattern for scalable VPS hosting with near-zero downtime deployments.
Key Takeaways
- Choosing a 24-month Hostinger VPS with 8 GB RAM (KVM2) costs $8.99 and supports about 5,000 requests/second according to Ed.
- Docploy with Railpack uses Docker Swarm under the hood to update containers without downtime during code pushes.
- Automated multi-server sync ensures all VPS instances run the latest code after each push.
- External load balancing (e.g., Cloudflare) is recommended to route traffic to the closest VPS and provide DDoS protection.
- Spreading servers geographically (UK, North America, Asia) reduces latency significantly compared to a single VPS.
- Setting up SSH keys, two-factor authentication, and a VPS hardening script improves security across all nodes.
- TanStack Start with Nitro and Railpack automates docker image creation and deployment from GitHub → simplifies multi-node deployments.
Who Is This For?
Essential viewing for developers and sysadmins who want a cost-effective, horizontally scalable VPS setup with zero-downtime deployments and automated multi-node syncing.
Notable Quotes
""the best deal you can get is the 24 month one, which gives you the VPS at $8.99.""
—Ed highlights cost efficiency of Hostinger VPS option.
""Docploy as well uses Docker Swarm to do a bunch of things for you... it’s not going to take your service down.""
—Justifies automated, zero-downtime deployment with Docploy.
""We will need to use a service that does the load balancing here for us... it’s going to handle the traffic between these servers as well for us.""
—Introduction of external load balancing to distribute traffic.
""If you push code up, it'll sync with all the different VPSs that you have.""
—Key feature: automatic multi-server sync.
""Using three VPSs spread across the globe reduces latency to 40-50 ms.""
—Illustrates latency improvement from multi-node setup.
Questions This Video Answers
- How can I deploy a scalable multi-VPS setup with near-zero downtime?
- What is Railpack and how does it work with TanStack Start for container builds?
- How do I implement external load balancing for VPS-based apps with Cloudflare?
- What are best practices for VPS security and hardening across multiple servers?
- Why choose Docker Swarm with an external load balancer over a single Swarm manager?
Full Transcript
Hey there, my gorgeous friends on the internet. Hope you are feeling dev opsy today, if that's even a word. I'm going to show you a really, really nice setup. If you were ever interested in kind of getting as much stuff off the cloud as possible and hosting your applications on VPS's, I'll show you a setup that lets you scale VPSs horizontally really easily that gives you zero downtime deployment so you can push up new code and your service won't go down. automatic multi-server sync as well. So when you push code up, it'll sync with all the different VPSs that you have.
So you have the latest version of your application and also load balancing and actually like trafficking, not trafficing. We're not trafficking anyone, but we're sending the user down to the closest endpoint that you have for low latency, of course. So hope you're going to enjoy this and let's get going. Now to get started, you will need a couple of VPSs. For this example, I'm going to show it with three different VPS's, but you can start with one and then scale as you need as your application grows. Now, you can also scale vertically if you need, which just means you're adding more RAM and CPU to one machine, but there comes to a point where you do want to span your application out horizontally to multiple different servers because there's a couple of advantages that you gain with that.
uh for example if one goes down then the other ones can still serve traffic and also if a request comes uh you know the user makes a request it can just hit the closest server rather than you know the one that there is so I highly recommend where where'd you get these VPS's from hostinger is a really really fantastic service they're partner of this channel as well and sponsored by I absolutely love them their uptime upkeep is is fantastic their support is great and it's very developer friendly So you have stuff like oneclick open claw deployments and and stuff like that.
So it's really really cool. Uh if you want to check the servers, I highly recommend the KVM2 here which gives you two virtual CPU cores and 8 GB of RAM which is really really strong. Like one of one of these machines you can do, you know, 5,000 requests every second just fine with your CPU going up to like 35%. It's pretty crazy. Uh, but if you were looking for a cheaper option, KVM1 will also work for this setup. Uh, Docloy, which we're going to set up, and Docker Swarm will work perfectly fine on 4 GB of RAM, but I'll choose KVM2 here just because it's faster when you're like deploying your images.
It'll just build faster. So, that's the advantage. So, on the checkout page, the best deal you can get is the 24 month one, which gives you the VPS at $8.99. So, you're getting 8 gigabytes of RAM for this price. But I have an additional coupon code that you can use, which is developed by AD, and that'll save you another buck off this. So, if you apply this, it's only eight now. Let's go. Okay. And then here for the server location, you want to go with United Kingdom or whatever is the closest one to you. And then if you are buying more VPS's, you want to spread them out across the globe.
So you might want to do the next one in North America and then one in Asia. Before we set up the VPS's, let me kind of just show you what the problem is if we only have one. So right now, if we just deploy one server, let's say in the UK here, if our user tries to hit our website, maybe from the US, well, we're kind of limited by the speed of light. So right, the latency is going to be like 120 ms regardless. That's like to the minimum absolute minimum uh possible speed. So that kind of sucks.
Not only that, if you know if this server goes down that our whole system is down. If we replicate this, we'll put one here. We'll put one, you know, in Africa and then one one here. Now, it doesn't really matter where the user hits it from. It's going to be pretty close regardless. So, we will need to use a service that does the load balancing here for us. But, it's going to be so so cheap that it's super worth it. And it's also going to handle the traffic between these servers as well for us. So now we're automatically reducing you know the latency to maybe 40 50 even less probably.
Now how are we going to orchestrate deploying our applications to all these different servers? Well we can do it manually by hand but that's really really difficult and oftentimes not worth it as you're going to be spending a lot of time trying to fix something that broke. And my whole goal with this was to make it as cheap as possible, but also really really developer friendly and easy to do. So you could do it with a bunch of bash scripts that you add and you know deploy uh when whenever you set up the VPS and Hostinger also has something like that.
You can have like a post script post install script. Here we go. Let me just show you this really quickly. So you'd essentially run a SH file when you're deploying your application that like automatically updates the packages, set up sets up like fire firewall rules, uh creates a user, etc., etc., and potentially deploy your application. Um, but there are other services out there that are specifically focused on this. So something like Kamal, something like Doku, something like Doc Ploy as well. and I tried all of them and by far the probably the easiest one that kind of gives you that versel like experience is doc boy.
So this is what we're going to be using under the hood. It uses Docker Swarm to to do a bunch of things for you like you know when you're pushing up new code. It's not going to take your service down. It's going to keep that container or that node alive until the new image finishes building and then it just swaps it. So it's really really good. So, let's just copy curl this link here and actually route into one of our servers. So, I'm going to start with this KVM2, which is a more powerful one. Before we access one of these servers, make sure you also have your SSH key set up.
So, if you go to settings here, SSH keys, you can add a new one. And you're going to need to add the public uh SSH key in here. So, if you don't have that, you can generate it like this. SH key gen ed 255. And then you add your email. Uh if you want to find the location of it, it's you go back to your root and then you go cd into ssh. If you do an ls, there we go. These are the public key and then you have your private key there. We want the public key.
So you're going to say cat id2551 9 pub. And that's just going to output it to the terminal. So we can simply grab it, copy it, and add it in here and hit save. So this is going to get saved and now you should be able to SSH into your server. So let's try that out. We're going to say SSH root at the IP address. So let's have a look at the IP address. Go back to home. There it is. Copy it. And let's paste it in. And I'm going to get an error because I had this set up once before.
So, I just need to remove this old known host. So, you're you're probably not going to get this, so don't worry too much about it. So, let's go back into it. And it's going to ask for your fingerprint. We're going to say yes. Perfect. And we are in. Great. If you see root there, that that's a good sign. So, let's head over to docloy and copy this command here at the beginning and paste it in. So, there we go. Now it finished installing traffic and everything that it needed and it exposed it on the IP address on port 3000.
Now this is not going to be a secure connection. So we'll need to secure it. But let's just simply head over it now. And you will need to add your email address, your name and then pick a password that you will remember. But the problem right now is that this is running on a unsecured port. See we don't have HTTPS. So to do that we essentially need to take this down. We don't want to serve this doc. So it basically put up an image where it's displaying this UI here on port 3000. So we can take that image down in dock ploy and just put it behind a HTTPS server.
So let's do that first actually. Okay. So you can head over to the web server here and as you can see we have a domain. So I'll just pick one that I have. I'll put it under a subdomain. Semicolons.dev. dev. I'll pick my email here to encrypt it and turn that on. And I'm going to select let's encrypt. So let's hit save and then go wherever you have your domain hosted whether that's name jeep cloudflare wherever. There we go. You go over to DNS records here. There we go. So now I have the IP address pointing to docloy semicolons.dev.
So now if I head over here, look at that. We can log in here through a secure connection. Great. Now we need to take it down from here where it's exposed through the non-secure connection and we can run this on the server. So docker service update docloy publish remove the port 3000. So let's head back over here and let's just run it here in root. Let's do that. There we go. It should take it down. So if we head back here and do a refresh. There we go. It's not loading anymore. That's great. Now, from here on, I recommend you set up two-factor authentification as well.
So, you can go to the bottom here to profile, and you can do enable two-factor right here. Okay, cool. Let's actually get a project up and running. So, what should we deploy? How about a tanstack start application? That sounds like a good time to me. So, let's exit out of the server for now. I'm going to clear this and open T-Max and just get a couple of uh terminals open here. So, I'm going to go cd back to the beginning here. And I think I actually have a little project here set up called tanstack docloy.
So if I cd into tanstack docloy I'll show you what this project entails. Now you can use anything you want. You can deploy next.js application a python application. I like tanstack a lot. And how I got this running is you essentially just run the tanstack start cli here. And you want to make sure that you select the what's it called? Nitro as your deployment because with tan tech start you can deploy it on cloudflare you can deploy it on netify a bunch of other services but you can run this command here tanstack cli latest you select react and then pick nitro okay and that's going to work really well when you use something like railpack uh to deploy your application.
So anyway, just a simple application. If I run npm rundev here, you're going to see it just runs vtier on port 3000. If we copy this over, quickly show you. There we go. So, it's just a really crappy looking resume page here, but hey, it's an app. Okay, cool. All right, so we have this. Now, you want to make sure you push this up to GitHub, right? So, it's available there. Cool. After you got on GitHub, we are ready to continue in docloy. So here's how this flow works. You go over to projects, you create a new project.
I'm going to call this tstack. Okay, we're going to create it. And here at the top, we can add services. So let's pick application here. And I'm going to call this tstack one as it's going to be the first server that hosts this application. My radiator just made a sound like it pissed itself. So hit create. There we go. We have tstack one here. Let's open this up and we are going to do provider here. We're going to hit GitHub. That's where my code is. We might need to go to settings here. Create a GitHub app.
This is just going to link it. Oh no. I think my phone's downstairs. Hold on. Did that work? Did that work? It worked. Let's go. Okay. So, you can keep any name you want here. Doesn't matter. Let's hit connect. And you might see action required here. So, let's just simply click uh this little icon here to the right. And we just need to essentially give permissions to access the repos. So, I'm going to pick all the repos here and hit install. And there we go. We should be able to go back now to tstack one here.
And there we go. It recognizes it. So, for the GitHub account, I'm going to select the dock ploy. And now we have access to all of the different applications here. I'm going to do tanstack dog ploy. The branch is going to be the main branch. Build path here is going to be slash. And here we are going to be using rail pack which is so so cool. It essentially creates the docker image automatically for you uh without you needing to do any config. So select that. It's really good. Hit save on both ends here at the top.
And this is again really really important. If you want all these servers to be in sync when you deploy new code up, keep auto deploy on. So even when we have four or five servers, it's going to auto deploy on all of them if you have this. And this uses Docker Swarm underneath the hood to do it. So that's pretty much it. We can hit deploy and get going. Let's hit confirm. And we are going to see it's going to pull down the code and then it's going to use Railpack to create that image automatically for you.
As you can see there, mpmi, MPM, CI, etc., etc. So let's let this run. And now, how about we do a domain here? Let's hook it up to a domain. But we don't really need to do a domain here because we need a load balancer somehow to kind of hit the IP endpoint that we want. But let me just show you just in case you only have one VPS and you want to keep this way, you can even use traffic here to generate one one for you automatically. And then all we need is to to do it.
Let's do it on port 3000. Okay, port 3000. You can do HTTPS as well if you want. Let's hit create. There we go. I don't think I turned HTTPS on. I didn't, but it's fine. Let's click. And we are getting a bad gateway. Let's We'll need to let the application build. Actually, it's not finished yet. So, that's the way you can do it if you have one. Okay. And then you can do a nice domain if you want. But what we want is to essentially just hit the IP here. So, this IP and it should just host our application.
Right now we have page not found. So what we can set it up here as is if we go to domains add a domain. I'm going to do do the host here to just use the IP address. Path we're going to keep off. Internal path off port we're going to put back on the 3000 here. And I'm not going to do HTTPS uh because we're going to do it somehow else. Okay. So let's hit create. Great. Okay. So now let's just wait for our application to deploy. Okay, looks like our application deployed. If we go here, as you can see, that's our image there.
It says it's done. And if we head over to the domain, we should be able to click this and boom, there we go. We are up and going. And if we go to the IP as well, we can get it working. Great. So that's one server ready to go, right? Ready to serve traffic. Now, what we can do is go back here and let's head over to remote servers. Now, to do that, we'll need to add an SSH key. So, I'm going to add a new SSH key. I'm going to say name, I don't know, servers.
And then here, I'm going to say hostinger servers. And I'm going to do the same private key and same public key that I added to the rest of the servers, right? the one that I have in my machine. So again, we can I'll go back to bash one here and SSH. So I basically want to cat the public key again and the private key. Now don't share the private key with anyone. So I'm going to I'm this the public key is fine, but I'm going to blur out the private key here. So, I'm going to do cat ID ED25519 without saying pub.
So, get that bit key, copy it over, and then just paste it here. Okay. And then hit create again. Don't show it to anyone. Cool. All right. So, now we got that going. We can head back over to the remote servers. We're going to hit create. I'm going to name this VPS 2. Now, you can add a name. I'm going to keep it as deploy server to host applications. The SSH key I can select it from here. And now I simply just paste in the IP address to uh with the other VPS. So copy that, paste it there.
I'm going to keep port 22 here so we can access it and deploy it. And then I'm going to simply hit create. Great. So that's one. And let's add the other one as well. So I'm going to copy the IP create server BPS3 deploy same SSH key this port and hit create. Great. So now hit setup here. If you go to deployments we are going to say setup server and hit confirm. So this is going to set up docker here for you. Railpack traffic everything that you need to get the application rolling. So there we go.
Nix packs rail pack. Cool. This should be all done. So you can verify that if you head over here to validate. And there we go. Look at that. And then you can also check security tab here to see what's correct and what's not correct. So normally with security you don't want root access. You want to disable that having able to just be able to access a server with a user. You want to disable passwords as well. So you so you only let people access your server with an SSH key. Fail to ban as well. That stops, you know, people from pinging your server a bunch.
Uh I have a really nice script that you can just simply run once and it'll secure it for you. Okay, let's close this up. So now we have two other VPSs. So how do we deploy the same application? Well, we just go up here and create a new service. I'm going to name this TStack 2 just to separate it. And I can just select VPS2 to deploy it on and hit create. And then I can do the same for VPS3. So I'm going to say Tstack 3. I'm going to put on three. Good. Let's hit create.
And there we go. And then from here on all we need is just selecting that repository on both of them. So I'll go here, select the repository on this one on main branch and keep everything the same. Go on rail pack and hit save. Okay. And then same for the other one. TS stack three. We'll do dog dock ploy tanstack deploy. Cool. Main branch and do rail pack as well and hit save. Let's actually deploy them. Great. All right. So we have it deployed on three different private servers in what like 20 30 seconds. How easy is that?
Now we want to set up the same thing in the domains. So, let's go on Tstack 3 here. So, this is my third one. I'll post the host in there uh on port 3000. And that's it. I'm not going to turn anything else on. I'm going to hit create. And let's do it on Tstack 2 as well. Domains. Add domain. I'll add the second one. Cool. There we go. Port 3000. And just with this simple setup, you can push up code now and it'll sync it through all the different servers. And I'll demonstrate that in just a second.
But let's wait for them to finish up. And look at that. All three servers are up and running. Now check out the magic. If I go back here to my code, let's head over to the Stanstack project. I'm going to envx. Is that the one? Nah. Let's look for a different one. Something that we can see on the homepage. Here we go. Index html. Cool. Do we have a header here? Let's go. Header. Perfect. Okay, let's modify this file. So, scroll down here. Let's see which part should we change. We hit this one. My resume.
Let's update that. So, my Where is my resume? My resume. Here we go. So, let's update this. Delete and say VPS baby. And hit save. Okay. So, I'll just get add this. get committed with a little message saying baby and I'm going to say get push. Now watch the magic happen. Oh my god. Cool. Let me just pull up all the three VPS's here. Look at that. Start rebuilding them. So I'll go and just copy over the IP for each. If you work with dog ploy before, you might be wondering, hey Ed, how come you didn't use swarm here where you set set up docker swarm and just deploy nodes on the different servers?
I tried that before. The main problem with that architecture is that if the VPS that hosts the docker swarm, like the manager role goes down, then the whole service goes down because you're just spanning nodes across different VPSs, but they don't have traffic or anything set up. Uh so it's it's not really worth doing that in my opinion. Instead, what we will do is we will have an external load balancer just distribute the traffic between these three VPSs's and also route the traffic to the closest user. So there we go. Looks like all of them got deployed.
So if I head back over to all three IPs, if I refresh, watch the my resume. Look at that. Updated there. Updated there. Updated there. Let's go. So we're keeping everything nice and sync. Now, this is probably the best $5 you will ever ever spend considering what it gives you. So, we need some sort of external load balancer. Again, the problem is if you have another, let's say you have a separate VPS that just handles, you know, the trafficking, you know, like go to this VPS, go to this VPS, do round robin, whatever. It still acts as a single point of failure.
If that goes down, it's not going to be able to route traffic to any of these VPS's. So, if you need to spend $5 and get an external load balancer, I cannot highly recommend this enough. The Cloudflare load balancing, you can do traffic steering here as well, which is great, right? Getting to the closest user. So, we're going to get this one here. So, let's get this one. Let's purchase. And what we also need through Cloudflare anyway is going to be DDoS protection because right now we can hit an endpoint as many times as we want and then just increase the CPU usage on that server.
Don't believe me? Let me show you. Let me do a little curl here for you. Look at that. I'm just hogging all the CPU usage on this server. So this is something that we should not be allowed to do. So again, that's what we're using Cloudflare for again. So let's just get this and continue to dashboard. Great. So now we have that. But before we set up the load balancing, let's also secure these servers a little bit. So I'll leave this in the description down below. This is a little fantastic script I I wrote here.
Uh if I go to here, I believe, check this out. I have a VPS hardening script. So VPS hardening sh. This essentially just creates a new user, blocks root from being able to to log in, stops password login as well. Um, make sure Docker is installed, but more importantly, also copies the SSH keys that we have now in root over to this new user that we're making. And that's the logic right here. Okay. And yeah, that's pretty much it. It sets it disables all the unused ports as well. We're keeping SSH 22 and then HTTP and HTTPS and also adds fail to ban uh which is great.
So nobody can just start smashing our server. Okay, so these are a couple little bits here. I'll leave this in the description so you can just simply run it. Now, how do you get on the server? Well, let's head over here and copy the IP address. You essentially want to do this on all the servers. So we can do SCP. That's a command you can run and then the file. So VPS hardening.sh. SH oops there and then you say root at that specific IP colon squiggly and hit enter. That should copy it over. There we go.
Copy it over. So if I SSH root at that address again, we are in. Cool. And now we can simply ls there it is. We can chod plus X that so we can make it executable. There we go. LS. Now it's green. So if it's green, that's a good sign. Sudo/vps hardening sh. Boom. It's going to run it automatically. Make sure everything is up to date on our system. Disable root login. Fail to ban. So if everything works fine, we should be able to log in SSH docloy at that IP and not as root. If you want to see if everything worked as well, there's a nice little package VPS audit it's called.
Check it out on GitHub. I really really like it. If you want to get a quick snapshot of, you know, of your system security, this one shows it really nice. It's just a simple curl command that you can get it. So here it is. I'll copy this and we'll run it. There we go. See, it shows you all the different things in your system. So, this is the most important ones here. SSH root login, it passes. Password login passes. Um, it's giving me a warning here for the port security. I forgot to remove these. Uh, so you can remove these.
I had an older script here version where I included this for Docker Swarm, but I don't need them. So, you can remove those as well. with UVF UVF uh okay good so you can run this on different server on all the three servers and you're good to go or use the hostinger postcript okay so now that we have the load balancer I'm going to hit create load balancer here let's pick a name dstack there we go at semicolons dev you can add a description I'm going to turn adaptive routing on here which is going to give you that failover across VPS's so if one VPS goes down it'll automatically reroute to one That works.
So that's great. We have that. Make sure you have proxy enabled here as well. Let's hit next. Here we need to create a new pool. So let's create a new pool. We'll call this Dstack. You can add a description for the endpoint steering. Here you have random which just distributes it evenly or depending the weight you pick here. If I do one here and one here, it's 50/50. So it's going to distribute it evenly. But we can also pick least outstanding requests, which is going to look at the connection first. And if there's more connections on one server, then it will hit the other one instead.
Okay. So, I'm going to add VPS one VPS two here. And looks like we can only do two. You might need to upgrade to get even more, unfortunately. Damn it. No. Uh, okay. Well, let's add two for now. So, I'll add one IP here. Add another IP here. Great. Okay. We can go down. Uh, let's hit configure coordinates for proximity steering. We won't need that one. Load shedding. We won't need that one. Let's just hit save. Okay. So, there we go. We have that one. Let's hit next. For the monitoring here, and we essentially just want to monitor at slash.
So, there we go. Slash. So, if you create a monitor, you can give it a name. HTTP at slash will work fine. Okay. Cool. Did I attach it? Attach it. Add. Save. Great. Cool. Let's hit next. Now, here is where you have the traffic steering. Unfortunately, again, it's not part of the package. So, if you want the extra oomph of, you know, having the ability to, you know, route the user to the closest one, then it'll probably cost a bit extra. So, that would be your proximity steering here, request to the closest physical pool. Finally, the last step, if this is still not working, is to head over to the SSL TLS and hit configure.
And let's do full here. Or you can also do flexible if you want. And hit save. So there we go. And now we have our pool going. We have SSL connection as well. This is going to give us bot protection against DDOS. And if we hit tstack developed, sorry, semicolons.dev. Look at that. It is secure connection and it's getting through our load balancer. How cool is that? So that's the full setup. Hope you enjoy this episode. Let me know what you think of this. Do you like the setup? Do you use something else? I'm curious to hear what you have to say.
Also, thank you to Hostinger again for sponsoring this episode. And I'll catch you guys in the next one. Peace.
More from developedbyed
Get daily recaps from
developedbyed
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.









