Go-Based Car Hire Web App with Jenkins CI/CD on a VPS

Hello Everyone , Once again thank you for always visiting my blog here on Hashnode, i really appreciate the views likes and comments .

Today's Project, I designed and deployed a Go-based web application for a fictional car hire company, “Tech Man Car Hire.” The goal was to simulate a real-world DevOps CI/CD pipeline using Jenkins, Docker, and a VPS. I built the app from scratch, containerized it, and automated the deployment pipeline using Jenkins running on my server. This project sharpened my backend, containerization, and CI/CD automation skills, all in one go.

My Core Concepts in This Project.

Go (Golang) : A lightweight, fast programming language used to build the backend web server. Go’s simplicity made it easy to create multiple HTTP routes and compile to a single binary. in a layman's Language it means Go is a fast and easy-to-use programming language. It’s great for building the “behind-the-scenes” part of a website (called the backend). Also It makes it simple to set up different web pages or actions which is called routes, and when you're done, everything gets packed into one file you can run

Docker: This Tool is Used to containerize the Go application. This ensures the app runs identically on any machine by packaging code, dependencies, and environment into one image. In Essence it is saying We used a tool (called Docker) to put the Go app inside a special box (called a container). This box includes everything the app needs to run like code, setting etc. For this reason this app will run exactly the same no matter the computer you use.

Jenkins: Our CI/CD engine. Jenkins automatically pulls the code from GitHub, builds the Go app, creates a Docker image, and runs the container, all without manual steps. That is Automation.

CI/CD (Continuous Integration / Deployment) : Automating the build and deployment process, so every change pushed to GitHub can be tested, built, and deployed with minimal effort.

VPS (Virtual Private Server) : The private server that hosted Jenkins and ran the live Docker container. This mirrors a real-world production environment.

Prerequisites:

Before following along, make sure you have:

i. A VPS (I used Ubuntu-based server with root access) or you can use Local Machine (Laptop/Desktop) or any Free Tier Cloud Platforms

ii. Go installed on the VPS or your Local Machine

iii. Docker installed and running

iv. Jenkins installed and accessible externally (mine runs on http://:8081)

v. A GitHub account with a repo named car-hire-app

vi. The folder structure and files prepped (see GitHub repo)

vii. SSH access via Termius or equivalent

My car-hire-app Folder Structure.

car-hire-app/

├── Dockerfile

├── go.mod

├── go.sum

├── main.go

├──.gitignore

├──.dockerignore

├── README.md

├── jenkins/

│ └── Jenkinsfile

├── templates/ │

├── layout.html │

├── home.html │

├── about.html │

├── contact.html

│ └── admin.html

├── static

│ └── car.jpg

Project Folder Explained

main.go: This is the main file where your Go web app starts running.

It tells the app:

What to do when someone visits pages like /about, /contact, or /admin

And it starts the web server so you can view your app in a browser (usually on http://localhost:8080)

go.mod: This file tells Go: “This is a Go project, and here are the tools or packages I’m using.”

It's created when you run go mod init.

It keeps track of your project name and any extra code you pulled in (like helper tools).

go.sum: This is a security file automatically made by Go. It checks if the tools or packages you downloaded are the exact ones you should be using (no tampering, no changes).

Dockerfile: The container recipe for the app. It defines how to build a Docker image of the Go app: uses golang:1.22.2-alpine, copies the code, builds the binary, and sets it to run on container startup.

.dockerignore: Tells Docker which files and folders to skip during image build. Helps reduce image size by ignoring things like .git/, logs, compiled binaries, and docs.

.gitignore: Ensures Git doesn’t track unnecessary or sensitive files like binaries, test artifacts, and local environment files. Keeps your repo clean.

jenkins/Jenkinsfile : Contains a scripted or declarative Jenkins pipeline. It automates the CI/CD flow: pulls code from GitHub, builds the Go app, builds a Docker image, and runs the container on the VPS.

README.md : A markdown file that explains the project purpose, setup steps, technologies used, and how to build/run the app. Acts as the homepage for your repo

templates/ This folder holds all the HTML files used by the app

Instead of writing plain text in main.go, we use these files to render full, styled web pages with structure (like headings, buttons, layouts).

Inside this folder:

  • layout.html is the master layout that wraps every page (like a frame with header/footer).

  • home.html, about.html, contact.html, and admin.html are the content pages. Each one gets "injected" into layout.html

Static: If you plan to add custom images, CSS files (for design), or JavaScript in the future, they will go here.

Please Note : This project was designed and implemented by me using real DevOps workflows. I used AI as an assistant for infrastructure generation and syntax accuracy, but I customized, deployed, and documented everything manually as part of my learning and real-world simulation.

Let's Get Started.

Step 1 : Upload car-hire-app Folder to VS Code

Open your VSCODE from your local host Click on file -----> Open Folder Select your Unzipped car-hire-app folder , then click select folder to open it on the VSCODE, you will see your well structured files showing on your VSCODE like in the Screenshot Below.

Step 2: Initialize Git & Push Project to GitHub (Version Control)

Before you run this commands Make sure you have already Created a Repository on GitHub GUI to push your codes into.

On your VSCODE open your terminal and run this command "git init" This creates a .git folder in your project root, now it’s a Git repo.

Then next thing is to stage all files for commit , with this command " git add . " This command tells Git to track all files.

Then the 3rd version Control command to run is " git commit -m " Followed by our commit message which is "Initial commit for Project Car Hire App with Go, Docker, and Jenkins CI/CD"

What i am saying is you will run this command like this git commit -m "Initial commit for Project Car Hire App with Go, Docker, and Jenkins CI/CD"

once you are done running this above command your code is now safely stored in your local Git repo.

Run the next command to Connect Remote GitHub Repository , My remote GitHub repository i created for this project is github.com/stillfreddie/car-hire-app

Run command " git remote add origin https://github.com/stillfreddie/car-hire-app.git "

Finally to Push code to GitHub run these commands:

git branch -M main

git push -u origin main

What does these commands do? git branch -M main , this rename my current branch to main because lately GitHub now uses main instead of master as the default branch name, and make it the primary one I’ll be working with.

git push -u origin main this command says Push my code to GitHub, into the main branch on the remote repo I called origin

Once Done, Visit this Link https://github.com/stillfreddie/car-hire-app to view the Codes Pushed to GitHub for version Control.

Step 3: Automating the CI/CD Pipeline with Jenkins

The Goal of this step is to Automatically pull your code from GitHub → build the Go app → create a Docker image → run the container on your VPS.

Prerequisites Checklist for this Step .

Make sure you’ve already:

  1. Installed Jenkins and it’s accessible at http://:8081

  2. Installed Docker on the VPS

  3. Installed the Go plugin on Jenkins

  4. Git is installed on the VPS

  5. Your project is pushed to GitHub (https://github.com/stillfreddie/car-hire-app )

After pushing the project to GitHub, it was time to automate the build and deployment process using Jenkins, the open-source CI/CD powerhouse.

Let me give a Brief explanation of what is Jenkins , so that my readers can understand what they are doing up to this point.

Jenkins is a popular automation tool used to build, test, and deploy applications. It integrates perfectly with GitHub, Docker, and other DevOps tools, making it a top tier pick for managing CI/CD pipelines.

For my Project I have installed Jenkins on my VPS and expose it to 0.0.0.0 to run on port 8081

Docker and Go (v1.24.4) were already installed on the server. So i am good to go.

Also For this Project i am using Jenkins Pipeline , i chose to use pipeline because it Works just like real-world production pipelines, all my pipeline instructions were placed inside a file named Jenkinsfile, located inside the jenkins/ folder in my project folder named car-hire-app.

How the Pipeline Works

Stage 1: Clone Repository

Jenkins clones the latest version of the project directly from GitHub into the workspace.

Stage 2: Build

It compiles the Go application and creates a binary called car-hire-app.

Stage 3: Build Docker Image

Jenkins builds a Docker image using the Dockerfile in the project folder.

Stage 4: Deploy

The old container (if running) is stopped and removed. Then a new Docker container is started on port 8080, making the app live.

Now open your browser and visit the public IP of your server, followed by port 8081 (e.g., http://VPS-SERVER-IP:8081). This works because my Jenkins was configured to listen on port 8081. Once the page loads, log in using the username and password you created during the Jenkins setup.

Step 3 i.

Click: “New Item” (Top-left menu) for Item Name: car-hire-pipeline then type we select Pipeline and Click OK.

Step 3

i. Click: “New Item” (Top-left menu) In the text field, enter a name like car-hire-pipeline Then select “Pipeline” as the project type and click OK

This step creates a new Jenkins job that will automate the build and deployment of your Go web app.

ii. ON the Configure Page

Scroll down to the Pipeline section , Under Definition, change from Pipeline script to Pipeline script from SCM, Under SCM, change from None to Git .

This tells Jenkins:

Don’t ask me to type the pipeline steps here manually instead, fetch the build instructions from my GitHub repository.

SCM Stands for Source Code ManagementGIT : This is saying that we should Pull the pipeline instructions from a Git repository ,this allows Jenkins to Clone the GitHub repo (like https://github.com/stillfreddie/car-hire-app.git) .

Find the Jenkinsfile inside, Read the steps and run the build automatically.

iii. In the Repository URL field, enter https://github.com/stillfreddie/car-hire-app.git , This tells Jenkins exactly where to pull your Go app code and the Jenkinsfile that contains your build instructions.

iv. Under Branch Specifier: By default, Jenkins looks for /master change it to /main This tells Jenkins to target the main branch in your GitHub repo because that’s where your app and build instructions live.

v. In the Script Path field, enter: jenkins/Jenkinsfile you’re telling Jenkins: “When you fetch my repo, go to the main branch and look inside the jenkins folder. That’s where my pipeline script (Jenkinsfile) is located.”

Then Click Save.

Vi . Click: “Build Now” (left sidebar)

Once you click Build now Jenkins will: Clone the GitHub repo and Run the pipeline stages inside the Jenkinsfile.

Then you’ll see a build appear under “Build History” Green Ball Signifies Successful Build while Red Ball Signifies Error.

Please Note: I had to Build few times, because i did some Updates on my Configurations and Codes , Below are the Changes i made after my First Build.

1. Updating the Web App (Switching from Plain Text to HTML Templates)

After confirming that our Jenkins pipeline successfully built and deployed the app, we decided to improve the user interface. Initially, all the page content was returned as plain text via fmt.Fprintln, which looked basic and unattractive. Here's how we upgraded it to use proper HTML templates.

2. Adding templates/ Folder for HTML Pages

We created a new folder named templates inside our project directory. This is where all the .html files that define the layout and page structure are stored. Each page (Home, About, Contact, Admin) has its own HTML file:

layout.html: Shared layout used by all pages.

home.html: Homepage content.

about.html: About page content.

contact.html: Contact page content.

admin.html: Admin dashboard content.

The layout file provides a common structure (like navigation and footer), while the individual pages insert their unique content.

3. Adding static/ Folder for Assets

We also created a static/ directory that holds public assets such as:

CSS files: For styling the HTML pages.

Images: Company logo, icons, etc.

JavaScript (optional): For interactive behavior.

We configured the Go server to serve static files using:

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

This makes all assets inside the static folder accessible via URLs like /static/styles.css.

4. Updating main.go to Use Templates

We refactored the main.go file to load and render HTML templates instead of printing text directly. Each route now calls a function that parses the relevant .html file and injects it into the shared layout.html.

Example:

tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/home.html")) tmpl.ExecuteTemplate(w, "layout", nil)

Each handler function was updated similarly for About, Contact, and Admin pages.

5. Rebuilding via Jenkins

Once all files were updated and tested locally on VSCODE Terminal by running “ go run main.go “, we:

Pushed the updated code to GitHub

Went back to Jenkins and clicked "Build Now" again

Jenkins pipeline cloned the latest code, built the Go binary, built a new Docker image, and redeployed the container

A green ball appeared, signaling a successful deployment.

When we visited the server IP in a browser, the new HTML-based layout appeared beautifully formatted with proper sections and navigation.

Conclusion

Completing this project has been a major step forward in my DevOps engineering journey. From designing the Go-based web app to building and deploying it using Jenkins CI/CD, every stage taught me something practical and valuable.

What started as a simple idea for a car hire service website evolved into a fully automated pipeline that:

  • Fetches code from GitHub

  • Builds it using Go

  • Packages it into a Docker container

  • Deploys it seamlessly on a Linux VPS

Along the way, I tackled real-world challenges like:

  • Layout separation for cleaner templating

  • Static file and image integration

  • Jenkins executor and disk space issues

  • Live build troubleshooting and production readiness

This wasn’t just about achieving a green build, it was about understanding how DevOps truly works when code meets infrastructure.

If you’ve followed this series or you’re just beginning your DevOps journey, I hope this shows that learning-by-doing is the most powerful approach. Every bug was a lesson. Every fix was a step forward.

“Per aspera ad astra.”

Through hardships to the stars.

Thanks for reading.
Tech Bro
🔗 GitHub: stillfreddie

⚠️ Disclaimer

This project was designed and implemented by me using real DevOps workflows.
I used AI as an assistant for infrastructure generation and syntax accuracy,
but I customized, deployed, and documented everything manually as part of my learning
and real-world simulation.

10
Subscribe to my newsletter

Read articles from Stillfreddie Techman directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Stillfreddie Techman
Stillfreddie Techman