En este artículo, le mostraré cómo implementar la pila GoTTH (Go Templ htmx tailwind) en producción.
Recientemente creé mi propio agregador de intercambio de criptomonedas llamado cyphergoat ; encuentra la mejor tarifa para intercambiar tus criptomonedas desde diferentes intercambios asociados.
Consta de dos partes:
Una API que interactúa con los exchanges. Escrita en Go y que utiliza Gin.
La interfaz web está escrita en Go y utiliza una combinación de HTML, HTMX, tailwindcss, CSS y Javascript en plantillas. También conocida como la pila GoTTH. Interactúa con la API para buscar tarifas, etc.
Lo que es realmente genial de esta pila y configuración es que podemos producir un único binario con todo incluido para cada parte y enviarlo al servidor. En el lado de la interfaz web, esto es posible ya que el HTML se compila en código Go usando templ y luego se envía con el binario.
En este artículo, repasaré mi configuración para que te resulte más fácil hacer algo como esto.
Estoy usando un servidor Debian 12 que expondrá mi aplicación a través de túneles de Cloudflare. Todos los archivos estáticos se envían a través de nginx y los binarios de la API y del sitio web se ejecutan como servicios systemd.
En esta guía te mostraré cómo configuro esto.
Tengo una sola carpeta en mi máquina de desarrollo llamada cyphergoat: Contiene:
api/ web/ builds/
La carpeta API contiene el código fuente de la API. La carpeta web contiene el código fuente del sitio web.
Y las compilaciones albergan todas las compilaciones que se implementan en el servidor.
El primer desafío real consiste en configurar correctamente tailwindcss.
En mi proyecto web, tengo una carpeta estática específicamente para archivos estáticos. Dentro de ella, tengo dos archivos:
/web styles.css tailwind.css
El styles.css
simplemente contiene:
@import "tailwindcss";
El archivo tailwind.css es donde tailwind-cli guardará su material.
Para construir el material de Tailwind, simplemente ejecuto:
npx @tailwindcss/cli -i ./static/styles.css -o ./static/tailwind.css --watch
(suponiendo que tenga instalado tailwind-cli)
En mi archivo header.templ (el encabezado de todas las páginas), en la parte superior tengo:
<link href="/static/tailwind.css" rel="stylesheet"> <link href="/static/styles.css" rel="stylesheet">
Y los archivos se sirven utilizando e.Static de Echo (en mi archivo main.go).
func main(){ e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.Use(middleware.Secure()) e.Static("/static", "static") // Serves content from static folder. // Rest of the handlers }
En el lado del servidor, tengo una máquina virtual Debian 12 ejecutándose en proxmox.
En el directorio de inicio de mis usuarios, tengo una carpeta con el siguiente contenido:
cyphergoat/ ├── api ├── static/ └── web
La carpeta estática contiene todos los archivos estáticos (incluidos tailwind.css y styles.css), y la web y la API son los binarios.
Luego tengo dos servicios systemd para estos ejecutables:
El cg-api.service
/etc/systemd/system/cg-api.service
[Unit] Description=CypherGoat API After=network.target [Service] User=arkal Group=www-data WorkingDirectory=/home/arkal/cyphergoat ExecStart=/home/arkal/cyphergoat/api Restart=always RestartSec=1 [Install] WantedBy=multi-user.target
Y cg-web.service
/etc/systemd/system/cg-web.service
[Unit] Description=CypherGoat Web After=network.target [Service] User=arkal Group=www-data WorkingDirectory=/home/arkal/cyphergoat ExecStart=/home/arkal/cyphergoat/web [Install] WantedBy=multi-user.target
Ambos son propiedad del grupo www-data
(probablemente esto no sea necesario para la API) para facilitar su servicio a través de nginx.
El sitio web se está comunicando con la API, pero aún necesito hacer que la interfaz web sea accesible.
He configurado un sitio nginx con la siguiente configuración: /etc/nginx/sites-available/cg
server { server_name cyphergoat.com; location / { proxy_pass http://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; } # Optional robots.txt location = /robots.txt { root /var/www/static; access_log off; log_not_found off; } listen 80; }
También he configurado certbot para que tenga un certificado SSL.
Puede configurar certbot ejecutando:
sudo apt install certbot python3-certbot-nginx -y
Generar el certificado SSL:
sudo certbot --nginx -d cyphergoat.com
Lea Cómo alojar su propio sitio web para obtener una configuración de nginx más detallada.
Actualmente, estoy haciendo que mi sitio web sea accesible mediante páginas de Cloudflare. Es una solución de reenvío de puertos extremadamente fácil de usar.
Para hacer esto, necesitará una cuenta de Cloudflare y un dominio que apunte a Cloudflare.
Primero, dirígete al Panel de Confianza Cero .
En Networks
, haga clic en Tunnels,
y luego Create a tunnel.
Una vez creado, debe Install and run a connector
; siga las instrucciones de la página para su configuración específica.
Una vez que el conector se esté ejecutando, debe hacer clic en la pestaña Public Hostname
y Add a public hostname
.
Ahora deberías ver algo como esto:
Complete la información tal como la introduje. El tipo de servicio debe ser HTTP
y la URL debe ser 127.0.0.1:80
o localhost:80.
Obviamente, no hay razón para que su API sea accesible públicamente al implementar su sitio web.
Para implementar mis binarios, seguí adelante y creé un script bash rápido:
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:/user/user/cyphergoat/
El script creará la API, generará los archivos de plantilla, creará la interfaz web y luego enviará todo a mi servidor (incluida la carpeta estática).
Luego me conecto a mi servidor por SSH:
ssh user@ip
Y luego reiniciar los servicios.
sudo systemctl restart cg-api cg-web
Y eso es todo.
Limitación de velocidad simple en Go (Gin)
Cómo crear un acortador de URL en Go
Cómo implementar Django en producción
© 2025 4rkal CC BY-SA SUSCRIBIRSE