DEV Community

Cover image for 🚚 How to deploy Golang application on any GNU/Linux system, but without Docker?
Vic Shóstak
Vic Shóstak

Posted on • Updated on

🚚 How to deploy Golang application on any GNU/Linux system, but without Docker?

Introduction

Hey, hey! 👋 Another interesting article about deploy and Golang is here.

Let's imagine that we need to run an application written on Go on a remote server, but configure Docker too long (or just lazy).

What should we do? Learn from this article! 😉

📝 Table of contents

Why may I need this?

First, it is just important to know how service applications work on GNU/Linux. Also, it will be interesting for very small projects, that are too early to think about Docker and deployment automation (startups, REST API micro services, etc).

↑ Table of contents

The basis of our service

Okay, time to write a simple web service, that will give us something, when sending a request to it. For example, I'll take my favorite web framework Fiber (v2), which works extremely fast and easy to learn.

If you are not yet familiar with it, follow the comments in the code:

package main

import (
    "log"

    "github.com/gofiber/fiber/v2"
)

func main() {
    // Create new Fiber instance
    app := fiber.New()

    // Make path with some content
    app.Get("/hello", func(c *fiber.Ctx) error {
        // Return a string with a dummy text
        return c.SendString("Hello, World 👋!")
    })

    // Start server on http://localhost:3000 or error
    log.Fatal(app.Listen(":3000"))
}
Enter fullscreen mode Exit fullscreen mode

Save this file as main.go and build binary for GNU/Linux x64 within a similar folder with hello_world name:

GOOS=linux GOARCH=amd64 go build main.go -o ./hello_world
Enter fullscreen mode Exit fullscreen mode

OK. Now, just copy this binary to your remote server inside /root/go folder.

↑ Table of contents

A few words about Fiber

Perhaps, you are asking yourself, so why do I love Fiber web framework so much? The answer is in its main features:

  1. Robust routing
  2. Extreme performance
  3. API-ready web framework
  4. Flexible middleware support
  5. Low memory footprint

And, especially, I'd like to mention the extremely friendly community in Discord and detailed documentation (translated into different World languages)!

↑ Table of contents

Creating systemd service

The systemd is a software suite that provides an array of system components for Linux operating systems.

[...] Its main aim is to unify service configuration and behavior across Linux distributions; systemd's primary component is a "system and service manager"—an init system used to bootstrap user space and manage user processes.

— Wikipedia

Perfect! Now let's create a new service.

  • Connect to your remote server as root (super user)
  • Create a file with the extension *.service within the systemd folder:
nano /etc/systemd/system/hello_world.service
Enter fullscreen mode Exit fullscreen mode
  • Copy this code to it:
[Unit]
Description=Go sample web app
After=multi-user.target

[Service]
User=root
Group=root
ExecStart=/root/go/hello_world

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode
  • Hit Ctrl+O to save and Ctrl+X for close editor
  • Next, start and enable this service:
systemctl start hello_world.service
systemctl enable hello_world.service
Enter fullscreen mode Exit fullscreen mode

☝️ Service will start automatically, even after the remote server reboots.

↑ Table of contents

Setting up a reverse proxy server

I will use Nginx as a reverse proxy server, but you can choose any other one.

  • Install nginx using the package manager. For Debian-like systems it will look like this:
apt install nginx -y
Enter fullscreen mode Exit fullscreen mode
  • Start nginx service:
systemctl start nginx
Enter fullscreen mode Exit fullscreen mode
  • Create a config in /etc/nginx/sites-available/hello_world file:
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;

    location /root/go/hello_world {
            proxy_pass http://localhost:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create a symbolic link of our config file to the sites-enabled folder:
ln -s /etc/nginx/sites-available/hello_world /etc/nginx/sites-enabled
Enter fullscreen mode Exit fullscreen mode
  • Finally, reload nginx to apply config:
nginx -t && nginx -s reload
Enter fullscreen mode Exit fullscreen mode

🔥 Sometimes it can be a problem that port 3000 is not available on your remote server. Please check the firewall settings.

↑ Table of contents

Final result

Yep, that's it! Go to http://your_server_ip:3000 and see result 🎉

result

↑ Table of contents

Photos by

P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

  • 🔥 gowebly: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
  • create-go-app: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
  • 🏃 yatr: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
  • 📚 gosl: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
  • 🏄‍♂️ csv2api: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
  • 🚴 json2csv: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

Top comments (2)

Collapse
 
yoursunny profile image
Junxiao Shi

I find it easier to run Go programs with pm2, together with Node.js programs.

As for the reverse proxy, I use nginx mostly but am doing trial deployments with Caddy.

If the service doesn't need to be on port 443 (backend API), I may skip the reverse proxy altogether and let the Go program listen on port 8443 of an IPv6 address using a self-signed certificate, and then enable Cloudflare in front of it.

Collapse
 
koddr profile image
Vic Shóstak

Hello! Yes, of course, you can choose this path.

In this article I showed you a way to do this on the built-in tools (almost every distribution already has Nginx installed, for example) and with a minimum of configuration effort... 😉