Using systemd for Application Management
The application is managed using systemd to ensure a robust and maintainable runtime environment. Systemd acts as the init system on modern Linux distributions, handling service lifecycle operations such as start, stop, restart, and logging.
Advantages of systemd
Systemd provides declarative configuration, automatic restarts, dependency management, logging, and resource control. It requires no external dependencies and is available by default on major Linux distributions like Ubuntu, Debian, and Fedora.
Creating a systemd Service
A service file is created under /etc/systemd/system/ defining unit metadata, service behavior, environment variables, execution path, restart policy, and boot target. The service is configured to start after networking and to restart automatically with a delay to prevent crash loops.
Enabling and Starting the Service
After making the binary executable, systemd is reloaded and the service is started using systemctl. The service is enabled to start automatically on system reboot and verified through status checks.
Configuring Reverse Proxy with Caddy
The domain is configured in Caddy to reverse proxy traffic to localhost:8080. After restarting Caddy, the application becomes accessible via the public domain.
Database Migration and Debugging
Initial login issues reveal that database migrations were not applied. Restarting the service triggers the migrations, creating the required tables and enabling proper authentication.
Verifying Application Functionality
The application is tested by logging in and creating content, confirming that authentication, validation, and publishing features work correctly in production.
Deploying Updates Safely
A new binary is built locally, transferred to the server via SCP, replaced, made executable, and the service is restarted. The application continues running without data loss or duplication, demonstrating a safe deployment workflow.
Final Deployment State
The application is successfully deployed on a VPS with its own database, accessible via a domain, and fully manageable through systemd.
Now, we need something to run this application in a maintainable manner. And this is why we're going to be using system D. Because we could just run it directly now and then log out of the server, but that is not really robust. So we want something that can manage the lifecycle of this application. And this is where system D comes in, because it's essentially the init system or initialization system for modern Linux. It's the first process that runs.
It can manage the entire lifecycle of a service on applications. So starting, stopping, restarting, logging. We have already seen this with Postgres. It's something that also replaced older systems that no longer use anymore. So this is the latest and modern alternative to running services on Linux. And it's commonly used by Ubuntu, Debian, Fedora. So basically all the modern Linux distribution has support for this system D setup.
Right. The reason why this is great for simpler service, and I say similar, but you can use this for quite some time, is that it's a declarative config. You describe what you want and not how to get there. You just say we have these things. You have to run this thing, and then you maintain it, right? We can specify that we want automatic restart. So if something crashes, we don't need to worry about it. It can restart it. It has built-in dependency manics, so we can say don't do anything until
XYZ has already been started. We have automatic logging we can grab. We have resource control limit we can set up and specify. There's also no external dependencies. It's already installed on a server. So it's ready to go compared to if you were to use something like Docker, we will need to install Docker and set that up as an external dependency. Right. So how do we create a system D service? Well, you go to
slash etc slash systemd slash service. And then we say bleeding edge dot service. And I need sudo so we can write to the file password. And then we're gonna add a unit. This is description equals to bleeding edge block.
This is just a description for ourselves. So if you want to interact with system D through what is known as system CTL, we get a descriptive command of what the service is. We can say after and say network target, which simply specifies that. Don't start this until the networking is up and running and ready. Right.
Okay, I did not. Do we have? Okay, let's try again. sudo vi bleeding edge.service. Now we can save. So let me just get this back in again, units. Description is bleeding edge block after network target, just like before.
Let me specify a service where we say the type is simple. So the process we start is the service. There's no other things going on. It's just a simple service. The user that will run the service is the admin user, which is the one we are currently logged in as. And then I'm going to add a bunch of ENV variables, which is simply the ENV variables we have currently in our .env file. So they are also made available to the
to the binary, then we say exec start equals home admin bin, say restart always and restart sec is 10. So we specify where it should, where the actual binary that it should run is located. Oh, and it's not in bin, it's in app.
We said it should always restart and we should apply 10 seconds wait before each restart so we don't have these crash loops. Finally, we say install and say wanted by multi-user-target. And this simply defines when to enable the service. This is a normal operation and it's a non-gui and multi-user.
And this is also what we can enable this. So by running system CTL enable, this will enable whenever time you reboot the server as well. So give that a save. Then we say, first of all, we need to go back and say Cmod plus X app to make it executable. Then we say sudo system CTL daemon reload.
And then we say systemctl start bleeding edge. And let's try and grab the status and hopefully it's running. It is running. Okay. Could not call as it refile. Datastar.js map. Okay. That's fine. That's from the datastar. That's okay. It's running. OpmaGrayson has been applied. Now.
The final thing we need to do is go into slashetc catty sudo vi catty. And then instead of all of this, we are going to reverse proxy this domain to localhost 8080. So jump out sudo systemctl restart catty. Check the status.
So now, if we go into the browser, we should see our application running on demo at masterfullstackgo-lang.com. Right, so we're in localhost 8080, and they cannot be reached because we are not running it locally. But if I go to demo at masterfullstackgo-lang.com, we don't see our application yet. Interesting.
Let's just check here, reverse proxy 8080 sudo vi catty. We should be ready to go. Let's try and say system CTL restart catty one more time. There we go. And we have our login. There we go.
And here we go. We actually have the app. We have all of the articles. Let's just validate that we can actually log in. So we say mbv at masterfullstackgolang.com password. We have logged in unsuccessful. So we cannot log in.
Let's start by, because we can see that the, actually let's log in to the server, and then say sudo dash i dash u, post gris, password, and then say psql connect to bleeding edge prod, select queue from, select queue star from users.
Users does not exist one about articles. Interesting. Okay, so let's just try and grab, that's not, okay, so our migration has not been applied. Okay, so that should have happened. Let's go to CT, system D, system,
and then say look into the bleeding edge service here, bleeding edge admin and password localhost edge. That all looks correct. Go back here and say system, sudo system, CTL restart.
is Proj. Restart the bleeding edge application. What is the status? Okay. So we do get that the migration has been applied. Now if we jump back in here and say pshql connect to bleeding,
edge select and see if we have any now we have right okay and we are creating the user as well mm-hmm okay
Let's just switch back to the browser and give this a refresh. We have no, that's what we expected. All right, let's now try and access the, okay, so our app is loading now. We have it on demo at masterful.go.lang, but we have no articles, but do we have a,
user, so mbv at masterfullstackgoldang.com password. And we are logged in, logged in successful. Let's try and create an article, my first article and our validation is working, it's beautiful. This is my first article live from the server. Look mom, no hands.
Try and save, create it successfully. Admin is published. Let's see. There we go. Live on demo at Masterful Stack Go lang. So our application is live now. And whenever we do a new, maybe make some changes, this is where we're going to make them. This is the flow that we just did. So if you go back into terminal here and go into command app.
We now want to remove all of this. Give that a save and say just build app. Then we say scp bin app, bleeding edge at home admin. Say app new.
right SSH into the server because we already have one right so we can say move sudo move app app back password and then move app app new to app make it executable app and then we say sudo restart
system.ctl restart bleeding edge and let's check the status you can see now we are still running as before but if we were tried to apply the or create the user again we would have an error and we do not and we can see our app is still
We can still access the admin. We did not break anything because we didn't try to recreate a user that already exists. And if we go into network, press refresh, everything is still memory cached. So everything is fast and snappy. Everything goes super quick. So this is it. This is the blog. It's live on demo at masterfullstack.go, masterfullstackgo.com.
You can manage it, you have an admin, you can log in, you can log out, all running on a $5 VPS with your own database.