Snippets — Docker
Histrix
Makefile de gestión
Makefile para operar el contenedor de Histrix sin tener que recordar los comandos de docker exec.
Guardar como Makefile en la raíz del proyecto.
Por defecto asume que el contenedor se llama histrix. Si el tuyo tiene otro nombre:
make pull CONTAINER_NAME=mi-contenedor
# O exportar para toda la sesión
export CONTAINER_NAME=mi-contenedor
Si el usuario necesita sudo para docker, ejecutar con USE_SUDO=true:
Referencia rápida de comandos
| Comando | Qué hace |
|---|---|
make pull |
Git pull dentro del contenedor |
make push |
Git push desde dentro del contenedor |
make restart-php |
Reinicia php-fpm via supervisord |
make restart-nginx |
Reinicia nginx via supervisord |
make restart-all |
Reinicia php-fpm y nginx |
make clean-redis |
Flushea todo Redis |
make composer-install |
composer install |
make composer-dump |
composer dumpautoload |
make composer-update |
composer update |
make logs |
Tail de los últimos 100 logs del contenedor |
make status |
Estado de servicios supervisord |
make sh |
Shell dentro del contenedor |
Makefile
# Configuración principal
CONTAINER_NAME ?= histrix
REDIS_CONTAINER_NAME ?= histrix-redis-1
USE_SUDO ?= false
# Prefijo sudo si está habilitado
SUDO = $(if $(filter true,$(USE_SUDO)),sudo,)
# --- Git dentro del contenedor ---
pull:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) /usr/bin/pull
push:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) /usr/bin/push
# --- Servicios supervisados ---
restart-php:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) supervisorctl restart php-fpm
restart-nginx:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) supervisorctl restart nginx
restart-all: restart-php restart-nginx
# --- Redis (contenedor separado) ---
clean-redis:
$(SUDO) docker exec -t -i $(REDIS_CONTAINER_NAME) redis-cli flushall
# --- Composer (usar composer.phar) ---
composer-install:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) ./composer.phar install
composer-dump:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) ./composer.phar dumpautoload
composer-update:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) ./composer.phar update
# --- Logs del contenedor principal ---
logs:
$(SUDO) docker logs --tail=100 -f $(CONTAINER_NAME)
# --- Estado de servicios ---
status:
$(SUDO) docker exec -t -i $(CONTAINER_NAME) supervisorctl status
# --- Shell dentro del contenedor principal ---
sh:
$(SUDO) docker exec -it $(CONTAINER_NAME) /bin/sh
PostgreSQL + pgAdmin + WebSocket Proxy
Stack de desarrollo local para proyectos que necesitan PostgreSQL con soporte WebSocket (usado por ejemplo en integraciones con Neon o clientes que consumen la DB via WS).
Levanta tres servicios:
- postgres — PostgreSQL 16 con extensión PostGIS
- pgadmin — interfaz web para administrar la base en
http://localhost:5050 - pg_proxy — proxy WebSocket de Neon que expone postgres en el puerto
5433
Uso:
Conectarse desde el cliente:
- Directo: postgresql://root:admin@localhost:5432/started-db
- Via WebSocket: postgresql://root:admin@localhost:5433/started-db
Solo para desarrollo
Las credenciales hardcodeadas (root / admin) son solo para local.
En staging/producción usar variables de entorno reales.
services:
postgres:
image: postgis/postgis:16-3.4
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: admin
POSTGRES_DB: started-db
restart: unless-stopped
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "root"]
interval: 10s
timeout: 5s
retries: 3
pgadmin:
container_name: pgadmin
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin}
PGADMIN_CONFIG_SERVER_MODE: "False"
ports:
- "5050:80"
restart: unless-stopped
depends_on:
- postgres
pg_proxy:
image: ghcr.io/neondatabase/wsproxy:latest
environment:
APPEND_PORT: "postgres:5432"
ALLOW_ADDR_REGEX: ".*"
LOG_TRAFFIC: "true"
ports:
- "5433:80"
depends_on:
- postgres
restart: unless-stopped
volumes:
postgres_data:
Nginx Proxy Automático + SSL
Proxy reverso con generación automática de certificados SSL via Let's Encrypt. Lo usamos en los servidores para exponer múltiples servicios en el mismo host sin tocar configuraciones de Nginx a mano — alcanza con agregar variables de entorno al contenedor que querés exponer.
Setup inicial (una sola vez por servidor)
Antes de levantar el compose, crear la red externa que van a compartir todos los contenedores:
Luego levantar el proxy:
Cómo conectar un servicio al proxy
En el docker-compose.yml del proyecto que querés exponer, agregar las variables
de entorno y conectarlo a la red proxy:
services:
mi-app:
image: mi-imagen
environment:
- VIRTUAL_HOST=midominio.com
- LETSENCRYPT_HOST=midominio.com
networks:
- proxy
networks:
proxy:
external: true
Con eso solo el proxy detecta el contenedor automáticamente, configura el virtual host y gestiona el certificado SSL sin tocar nada más.
Múltiples dominios
Se pueden poner varios dominios separados por coma: VIRTUAL_HOST=midominio.com,www.midominio.com
El dominio tiene que apuntar al servidor
Let's Encrypt valida que el dominio resuelva a la IP del servidor antes de emitir el certificado. Si el DNS todavía no propagó, el certificado no se genera.
docker-compose.yml
services:
nginx-proxy:
image: nginxproxy/nginx-proxy
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- certs:/etc/nginx/certs
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
networks:
- proxy
restart: always
letsencrypt:
image: nginxproxy/acme-companion
container_name: nginx-proxy-letsencrypt
volumes_from:
- nginx-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- acme:/etc/acme.sh
environment:
- DEFAULT_EMAIL=soporte@mundoit.com.ar
depends_on:
- nginx-proxy
networks:
- proxy
restart: always
volumes:
certs:
vhost:
html:
acme:
networks:
proxy:
external: true
ZeroTier Proxy — Acceso a redes privadas de clientes
Compose para conectarse a la red ZeroTier de un cliente y exponer su servidor interno via Nginx como proxy reverso. Lo usamos cuando el cliente tiene servidores en una red local que no son accesibles desde internet directamente.
El contenedor se une a la red ZeroTier del cliente y hace de bridge — el proxy (Nginx o Traefik) lo detecta como cualquier otro servicio y le enruta el tráfico.
Requisitos
- Red
proxyya creada:docker network create proxy - El contenedor tiene que tener acceso a
/dev/net/tun(disponible en la mayoría de VPS) - La IP del cliente (
BACKEND_IP) es la IP que tiene el servidor del cliente dentro de la red ZeroTier
Variables a cambiar por cliente
| Variable | Descripción |
|---|---|
ZEROTIER_NETWORK_ID |
ID de la red ZeroTier del cliente |
BACKEND_IP |
IP del servidor del cliente en la red ZeroTier |
alvarez-zerotier |
Reemplazar por nombre-cliente-zerotier en todo el archivo |
Con Nginx Proxy (el que usamos normalmente)
Agregar las variables de entorno del proxy al servicio:
environment:
- ZEROTIER_NETWORK_ID=xxxxxxxxxxxxxxxx
- BACKEND_IP=xxx.xx.xxx.xx
- VIRTUAL_HOST=cliente.histrix.com.ar
- LETSENCRYPT_HOST=cliente.histrix.com.ar
docker-compose.yml
services:
alvarez-zerotier:
image: mundoit/nginx-zerotier:bc01ad4
container_name: alvarez-zerotier
restart: unless-stopped
networks:
- proxy
environment:
- ZEROTIER_NETWORK_ID=xxxxxxxxxxxxxxxx # <- red ZeroTier del cliente
- BACKEND_IP=xxx.xx.xxx.xx # <- IP del servidor en ZeroTier
devices:
- "/dev/net/tun:/dev/net/tun"
cap_add:
- NET_ADMIN
- SYS_ADMIN
volumes:
- alvarez-zerotier:/var/lib/zerotier-one
networks:
proxy:
external: true
volumes:
alvarez-zerotier:
ZeroTier CUPS — Servidor de impresión remoto
Igual que el proxy ZeroTier pero en vez de Nginx expone un servidor CUPS. Lo usamos cuando el cliente necesita imprimir desde Histrix a impresoras que están en su red local — el contenedor se une a su red ZeroTier y queda accesible como servidor de impresión desde dentro del stack.
A diferencia del proxy Nginx, este no se expone al exterior — usa expose
en vez de ports, así que solo es accesible desde otros contenedores en la
misma red (histrix_backend).
Variables a cambiar por cliente
| Variable | Descripción |
|---|---|
ZEROTIER_NETWORK_ID |
ID de la red ZeroTier del cliente |
mis15 |
Reemplazar por el identificador del cliente en todo el archivo |
El alias mis15-cups.histrix.com.ar |
Es como lo van a llamar los otros contenedores para mandarle a imprimir |
docker-compose.yml
services:
mis15-cups-zerotier:
image: mundoit/cups-zerotier:f811d32
container_name: mis15-cups-zerotier
restart: unless-stopped
networks:
proxy:
histrix_backend:
aliases:
- mis15-cups.histrix.com.ar # <- nombre-cliente-cups.histrix.com.ar
environment:
- ZEROTIER_NETWORK_ID=xxxxxxxxxxxxxxxx # <- red ZeroTier del cliente
expose:
- "631" # puerto CUPS, solo accesible internamente
devices:
- "/dev/net/tun:/dev/net/tun"
cap_add:
- NET_ADMIN
- SYS_ADMIN
volumes:
- mis15-cups-zerotier:/var/lib/zerotier-one
- cups-config-mis15:/etc/cups
- cups-data-mis15:/var/spool/cups
- /var/run/dbus:/var/run/dbus
networks:
proxy:
external: true
histrix_backend:
external: true
volumes:
mis15-cups-zerotier:
cups-config-mis15:
cups-data-mis15:
Al implementar
Al momento de implementar, ahi que hacer un cambio a mano en el docker no recuerdo, por lo cual llegado el momento de implementar, avisar asi se ve el cambio y se deja documentado. Es un cambio menor, pero es importante dejarlo registrado para no olvidarlo.