Escribe un servidor web en Go, empaquétalo con un Dockerfile de dos etapas y levántalo con Docker Compose en tu VPS, con reinicio automático.
Con Docker instalado, publicar una aplicación es escribir tres ficheros y un comando. Aquí lo hacemos con un servidor web en Go, que compila a un solo binario y cabe en una imagen de 28 MB.
Antes de empezar
- Para quién es este manual. Para cualquier modalidad de VPS: desplegar tu aplicación, sus repositorios y su configuración es cosa tuya o de tu desarrollador tanto en un VPS autogestionado como en uno administrado o administrado y gestionado. Lo que cambia es quién mantiene el servidor y la plataforma por debajo: en autogestionado, tú; en administrado, nosotros el sistema; en administrado y gestionado, también la plataforma dentro del alcance acordado (¿Cúal es la diferencia entre un VPS administrado y un VPS no administrado?).
- Docker y Compose instalados en el VPS (Cómo instalar Docker y Docker Compose en tu VPS) y acceso SSH como
root. - No hace falta instalar Go en el servidor: se compila dentro del contenedor.
- El puerto 8080 libre. Si ya tienes un servidor web en el 80, mejor así: no chocan.
Paso a paso
- Crea la carpeta del proyecto y entra en ella:
mkdir -p /opt/hola-go && cd /opt/hola-go
- Crea
main.go. Responde con una página en/y con la hora en JSON en/api/hora, y escucha en el puerto que le llegue por la variablePORT(8080 si no hay ninguna):
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"time"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, "<h1>Hola desde Go en tu VPS</h1><p>Servido por un contenedor Docker.</p>")
})
http.HandleFunc("/api/hora", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"hora": time.Now().Format(time.RFC3339)})
})
log.Printf("escuchando en :%s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
- Crea
go.mod, el fichero que identifica el módulo y la versión mínima de Go:
module hola-go
go 1.24
- Crea el
Dockerfile. Tiene dos etapas: la primera compila con la imagen oficial de Go; la segunda copia solo el binario a una imagen Alpine mínima. Así la imagen final no lleva compilador ni código fuente:
# Etapa 1: compilar el binario
FROM golang:1-alpine AS build
WORKDIR /src
COPY go.mod ./
COPY main.go ./
RUN CGO_ENABLED=0 go build -o /hola-go .
# Etapa 2: imagen final, solo el binario
FROM alpine:3
COPY --from=build /hola-go /hola-go
EXPOSE 8080
CMD ["/hola-go"]
- Crea
compose.yaml. Define el servicio, construye la imagen desde la carpeta actual, publica el puerto 8080 y hace que el contenedor vuelva a arrancar solo si se cae o si el servidor se reinicia:
services:
web:
build: .
ports:
- "8080:8080"
restart: unless-stopped
- Construye y arranca en segundo plano:
docker compose up -d --build
La primera vez descarga las imágenes base y compila; tarda alrededor de un minuto. Las siguientes, segundos.
- Mira que el contenedor está arriba:
docker compose ps
La columna STATUS tiene que decir Up y la de PORTS, 0.0.0.0:8080->8080/tcp.
Cómo comprobar que ha funcionado
Abre http://tu-ip:8080 en el navegador, con la IP de tu VPS.
Y curl http://tu-ip:8080/api/hora devuelve un JSON con la hora del servidor. Para cambiar el código: edita main.go y repite docker compose up -d --build. Para parar: docker compose down.
Si algo falla
docker compose uptermina con «port is already allocated»: otro proceso usa el 8080. Cambia el primer número deportsa otro libre, por ejemplo"8081:8080".- La página no carga desde fuera pero
curl localhost:8080funciona en el servidor: un cortafuegos bloquea el puerto. En Ubuntu recién instalado no hay ninguno activo; si has puestoufw, abre el puerto conufw allow 8080/tcp. - El contenedor se reinicia en bucle:
docker compose logs webmuestra el error del programa. - Cualquier otra cosa: abre un ticket desde tu área de cliente (Cómo abrir un ticket de soporte y que se resuelva a la primera). Tu aplicación y su despliegue son tuyos en cualquier modalidad: podemos orientarte, no mantenerlos.