En este post voy a describir cómo alojar una aplicación web programada con Go en un VPS usando Nginx. La app se compone de:
- Servidor web Go (backend)
- Archivos lado del cliente (JS, HTML, CSS, assets) servidos igualmente por Go
El servidor web programado con Go va a escuchar en cualquier puerto pero los usuarios no accederán a él directamente, sino que usaremos a Nginx como proxy, aprovechando así el certificado SSL y sin tener que abrir puertos del Firewall.
Para el lado del cliente no importa si usas Vite, Vue o cualquier otro entorno; mientras generes una carpeta dist compuesta de archivos interpretables por el navegador todo funcionará correctamente.
Voy a hacer la guía desde la subida y compilación de archivos, sobre todo cuando hay cambios en el código fuente y queremos actualizarla. Veremos:
- Clonar repositorio
- Compilar
- Crear servicio que mantenga viva nuestra app con systemd
- Configurar Nginx
- Diferencia entre actualizar lado del cliente y servidor
- Compilar cliente en PC local y subir dist. Compilar backend en VPS obligatoriamente
Será una guía que me servirá mucho en el futuro, pues casi todas mis aplicaciones están programadas usando esta arquitectura.
Clonando repositorio por primera vez
Ya tengo mi clave pública en GitHub para que pueda clonar repositorios privados de mi cuenta sin contraseña. Hago lo siguiente la primera vez
git clone git@github.com:parzibyte/detectar-saltos
Compilamos:
cd detectar-saltos/api/
go build -o saltos_backend
La compilación se debe hacer siempre que haya cambios en el backend.
Subimos dist compilado. O sea:
npm run build
rsync -rvniz --delete dist/ user@server.com:/ubicación_proyecto/api/dist/
rsync -rviz --delete dist/ user@server.com:/ubicación_proyecto/api/dist/
Y creamos el servicio como veremos más adelante.
¿Por qué no compilar lado del cliente en VPS?
Si quieres puedes compilar el lado del cliente también en el VPS pero se me hace un desperdicio de recursos.
El ejecutable de Go debe compilarse en la arquitectura donde va a correr, o al menos eso es lo que hago yo. No puedes ejecutar un .exe de Windows en Linux nativamente, por ello es que es obligatorio compilar en la nueva arquitectura.
En cambio JavaScript y los demás archivos del lado del
cliente se van a ejecutar en el navegador, solo necesitan ser servidos. Así
que yo prefiero generar la carpeta dist (normalmente con npm run build)
y luego enviarla al VPS, pero si tú quieres puedes compilar en el VPS, no
es imposible, solo no lo recomiendo.
Creación del servicio
Vamos a crear un servicio que systemd va a administrar. Creamos el archivo, yo prefiero usar vim:
sudo vim /etc/systemd/system/backend_detectar_saltos.service
Es importante que notes que se llama backend_detectar_saltos.service
porque a continuación en el enable vamos a habilitarlo e iniciarlo
por su nombre de archivo
quitando el .service (es decir, backend_detectar_saltos)
Con el contenido:
[Unit]
Description=Detector saltos Backend Go
After=network.target
[Service]
User=parzibyte
Group=parzibyte
# Ruta al directorio donde está el servidor de Go
WorkingDirectory=/ubicación/api
# Comando para iniciar la aplicación
ExecStart=/ubicación/api/saltos_backend
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Luego lo vamos a habilitar, iniciar y revisar su estado
sudo systemctl daemon-reload
sudo systemctl enable backend_detectar_saltos
sudo systemctl start backend_detectar_saltos
sudo systemctl status backend_detectar_saltos
La salida al revisar su estado es:
● backend_detectar_saltos.service - Detector saltos Backend Go
Loaded: loaded (/etc/systemd/system/backend_detectar_saltos.service; enabled; preset: disabled)
Active: active (running) since Thu 2026-02-19 15:33:08 CST; 30s ago
Main PID: 1003231 (saltos_backend)
Tasks: 6 (limit: 48900)
Memory: 11.7M
CPU: 25ms
CGroup: /system.slice/backend_detectar_saltos.service
└─1003231 /ubicación/api/saltos_backend
Feb 19 15:33:08 xd systemd[1]: Started Detector saltos Backend Go.
Actualizando próxima vez
Si solo es el lado del cliente compilamos con npm run build
en la PC local por simplicidad y ahorro de recursos. Luego cuando
tengamos dist generado:
rsync -rvniz --delete dist/ user@server.com:/ubicación_proyecto/api/dist/
No hace falta reiniciar el servidor de Go ni el servicio; los nuevos archivos serán servidos automáticamente
Si es el lado del servidor entonces sí debemos detener el servicio y compilar el backend de nuevo:
cd ubicación_api
sudo systemctl stop backend_detectar_saltos
git pull origin main
go build -o saltos_backend
sudo systemctl start backend_detectar_saltos
sudo systemctl status backend_detectar_saltos
Es importante hacerlo en ese orden porque el binario de Go no puede estar en ejecución cuando compilemos, ya que el anterior siempre es reemplazado por la nueva versión.
Configuración de Nginx
Editamos default.conf que está en:
sudo vim /etc/nginx/conf.d/default.conf
Añadimos dentro de server abajo de
server_name lo siguiente:
location /url_de_la_app/{
proxy_pass http://localhost:8200/;
}
Aquí /url_de_la_app/ es la URL para que los usuarios
accedan a partir de la raíz de Nginx. Si tu sitio es
sitio.com entonces al acceder a sitio.com/url_de_la_app/
en realidad verán lo que haya en http://localhost:8200/
Luego validamos (y reiniciamos si la validación está bien) con:
sudo nginx -t
sudo systemctl reload nginx
Conclusión
Con esto hemos:
- Compilado y levantado un servidor HTTP programado en Go
- Configurado Nginx para que sirva como proxy entre el cliente y nuestra app de Go sin tener que abrir puertos
- Creado un servicio que podemos detener cuando sea necesario, y que también se va a iniciar automáticamente en los reinicios
- Configurado el VPS para bajar los últimos cambios del repositorio y compilar fácilmente