How to Deploy Go with Templ, HTMX and TailwindCSS

Discover how to deploy the GoTTH stack (Go, Templ, HTMX, Tailwind) in production with an optimized configuration that includes Cloudflare Tunnels, Nginx and systemd for an efficient and secure implementation.

domingo, 9 de marzo de 2025 • 3 min read • Q2BSTUDIO Team

Software-Apps-Company

In this article, we will show you how to deploy the GoTTH stack (Go, Templ, HTMX, Tailwind) in production.

Recently, we developed an aggregation platform for cryptocurrency exchange that finds the best exchange rates among different partner providers.

The project consists of two parts:

  1. An API written in Go using the Gin framework to interact with the exchanges.

  2. A web interface developed in Go that uses HTML, HTMX, TailwindCSS, CSS and JavaScript in Templ templates, which makes up the GoTTH stack.

One of the main advantages of this setup is that we can generate a single compiled binary with all the necessary elements for each part of the system and easily deploy it on the server. In the case of the web interface, this is possible because the HTML templates are converted into Go code and integrated into the final binary.

In this article, we detail our configuration to facilitate its implementation.

Server Configuration

We use a Debian 12 server to host our application, which is exposed through Cloudflare Tunnels. Static files are served via Nginx and both the API and the web application run as services managed by systemd.

The project structure in the development environment is as follows:

api/
web/
builds/

The `api/` directory contains the API source code, `web/` houses the web interface source code, and `builds/` stores the binaries ready for deployment on the server.

Tailwind Configuration

To manage TailwindCSS, we have a `static/` folder inside the `web/` directory, where two files are located:

/web/static/
    styles.css
    tailwind.css

The `styles.css` file simply imports TailwindCSS:

@import 'tailwindcss';

While `tailwind.css` is generated by TailwindCLI using the following command:

npx @tailwindcss/cli -i ./static/styles.css -o ./static/tailwind.css --watch

Both files are referenced in the main HTML template using:



To serve these static files on the server, we use Echo in our `main.go`:

func main(){
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Secure())

    e.Static('/static', 'static') // Serve static content.

    // Rest of handlers
}

Service Configuration on the Server

On the server, we have a folder structure similar to:

cyphergoat/
+-- api
+-- static/
+-- web

The `api` and `web` binaries are managed by systemd through the following services:

cg-api.service:

[Unit]
Description=CypherGoat API
After=network.target

[Service]
User=user
Group=www-data
WorkingDirectory=/home/user/cyphergoat
ExecStart=/home/user/cyphergoat/api
Restart=always
RestartSec=1

[Install]
WantedBy=multi-user.target

cg-web.service:

[Unit]
Description=CypherGoat Web Interface
After=network.target

[Service]
User=user
Group=www-data
WorkingDirectory=/home/user/cyphergoat
ExecStart=/home/user/cyphergoat/web

[Install]
WantedBy=multi-user.target

Nginx Configuration

To serve the user interface via Nginx, we use the following configuration:

server {
    server_name domain.com;

    location / {
        proxy_pass https://127.0.0.1:4200;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /var/www/static/;
        expires 30d;
    }

    listen 80;
}

To enable HTTPS, we use Certbot with:

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d domain.com

Deployment

To automate the generation and transfer of binaries, we created a bash script:

cd api
go build -o ../builds/

cd ../web
templ generate && go build -o ../builds/web cmd/main.go

cd ..
rsync -urvP ./builds/ user@SERVER:/home/user/cyphergoat
rsync -urvP ./web/static user@SERVER:/home/user/cyphergoat/
rsync -urvP ./api/coins.json user@SERVER:/home/user/cyphergoat/

Then, we access the server and restart the services:

ssh user@ip
sudo systemctl restart cg-api cg-web

At Q2BSTUDIO we specialize in the development and deployment of technological solutions, offering custom services to implement efficient and scalable infrastructures. If you are looking for experts in modern application development and deployment, contact us.

A BREAK?

Play for a moment before you go

OUR SERVICES

How we can help you

Do you have a project in mind?

Tell us your vision and we'll turn it into a software solution. Whatever the scope, we make your idea real.