Documentación técnica centralizada

El mapa operativo de denkenlab.com.mx

Accesos, arquitectura, permisos y publicación de proyectos en un solo lugar. Diseñado para consulta rápida durante despliegues y soporte.

Servidor activoDNS operativoTest publicado
4guías integradas
22SSH / SFTP
80 · 443HTTP / HTTPS
3306MySQL solo local
Operación diaria

PuTTY, SQLyog y SFTP

Parámetros de conexión, túnel SSH, carga de archivos y diagnóstico.

Diseño

Un subdominio por proyecto

Separación de aplicaciones, carpeta public y archivos sensibles.

Linux

Propietarios, grupos y modos

Modelo 2750/0640 y áreas de escritura controlada 2770/0660.

Publicación

DNS y VirtualHosts

Procedimiento probado con test.denkenlab.com.mx y reutilizable para Eventos.

Guía 01

Acceso de desarrollo

PuTTY mantiene la sesión SSH y el túnel de MySQL; SQLyog utiliza ese túnel y SFTP viaja por el mismo puerto 22.

1. Datos del entorno
ElementoValor
Servidor público159.54.154.87
Dominiodenkenlab.com.mx
SistemaUbuntu 24.04 ARM64
WebApache + PHP 8.5 mediante PHP-FPM
BaseMySQL 8.0.46
Puertos públicos22, 80 y 443
MySQL públicoNo disponible; solamente por túnel SSH
2. Conexión SSH con PuTTY
CampoValor
Host Name159.54.154.87
Port22
Connection typeSSH
Auto-login usernameubuntu o usuario individual
Private keyLlave .ppk asignada

Túnel obligatorio

  1. Cargar la sesión guardada.
  2. Ir a Connection → SSH → Tunnels.
  3. Source port: 3307.
  4. Destination: 127.0.0.1:3306.
  5. Seleccionar Local, pulsar Add y confirmar L3307 127.0.0.1:3306.
  6. En Connection, configurar keepalive en 30 segundos y activar TCP keepalives.
  7. Regresar a Session y guardar.
La ventana de PuTTY debe permanecer abierta.Si se cierra la sesión, el túnel desaparece y SQLyog deja de conectar por diseño.
3. SQLyog mediante túnel SSH
SQLyog127.0.0.1:3307
en la PC
PuTTY / SSH127.0.0.1:3306
en el servidor
MySQL
Campo SQLyogValor
MySQL Host Address127.0.0.1
Port3307
UsernameUsuario MySQL individual
PasswordEntregada por separado
SSH tabNo usar; PuTTY ya proporciona el túnel
  1. Abrir PuTTY y conectar.
  2. Mantener PuTTY abierto.
  3. Abrir SQLyog y conectar a 127.0.0.1:3307.
  4. Al terminar, cerrar SQLyog y después PuTTY.
4. Carga por SFTP

Se usa SFTP, no FTP tradicional. WinSCP o FileZilla deben configurarse explícitamente como SFTP.

CampoValor
ProtocoloSFTP
Host159.54.154.87 o denkenlab.com.mx
Puerto22
Usuarioubuntu o usuario individual
Llave.ppk asignada
Destino/var/www/NOMBRE_PROYECTO, una vez preparado
5. Seguridad implementada
  • MySQL escucha únicamente en 127.0.0.1.
  • La administración remota de MySQL viaja cifrada en SSH.
  • root de MySQL utiliza auth_socket y no tiene acceso remoto por contraseña.
  • Solo se publican 22, 80 y 443.
  • Las reglas iptables son persistentes.
  • SSH utiliza llaves y SFTP no requiere puertos adicionales.
  • PHP se ejecuta mediante PHP-FPM.
6. Reglas operativas
  • Asignar a cada desarrollador su propio usuario y llave.
  • No abrir 3306 en Oracle Cloud ni en iptables.
  • No guardar llaves, contraseñas ni .env en repositorios, tickets o este portal.
  • Definir grupo y permisos antes de subir código productivo.
  • Revocar llave y usuario MySQL cuando alguien deje el proyecto.
7. Diagnóstico rápido
SituaciónRevisión
SQLyog no conectaComprobar PuTTY y el túnel L3307 → 127.0.0.1:3306.
Funcionaba y dejó de funcionarReabrir PuTTY; el túnel terminó al cerrar la sesión.
PuTTY se desconectaConfirmar keepalive de 30 segundos.
SFTP no conectaConfirmar SFTP, puerto 22, usuario y llave correcta.

Guía 02

Arquitectura de proyectos

Cada proyecto vive aislado en su carpeta, se publica mediante su subdominio y Apache solamente entrega el contenido de public/.

1. Una URL por proyecto
Modelo anteriorModelo propuesto
denkenlab.com.mx/eventoseventos.denkenlab.com.mx
denkenlab.com.mx/inventarioinventario.denkenlab.com.mx
Todo bajo /var/www/htmlCada proyecto bajo /var/www
El dominio raíz no es un proyecto.denkenlab.com.mx queda como landing; los sistemas usan subdominios independientes.
2. Flujo de una solicitud
Navegadoreventos.denkenlab.com.mxApache VirtualHost/var/www/eventos/publicAplicación PHP

DNS identifica el servidor; Apache identifica el proyecto por ServerName; DocumentRoot limita la superficie web.

3. Qué significa public/
Dentro de public/Fuera de public/
index.php o index.htmlapp/, clases, includes y scripts internos
CSS, JavaScript, imágenes y fuentes.env, credenciales y llaves
Descargas expresamente públicasSQL, ZIP, exportaciones y temporales
Front controller del frameworkLogs, caché y almacenamiento privado
La regla decisivaSi un visitante no debería escribir una URL y descargarlo, ese archivo no vive en public/.
4. Estructura recomendada
/var/www/eventos/
├── public/       # Única carpeta servida por Apache
│   ├── index.php
│   └── assets/
├── app/          # Código PHP no público
├── config/
│   └── .env      # Secretos fuera de la web
├── storage/      # Logs, cache y cargas privadas
└── vendor/       # Dependencias, si aplica

En un proyecto heredado no se moverán archivos a ciegas: primero se revisan entradas, includes, rutas relativas y directorios de cargas.

5. Capas y responsabilidades
CapaResponsabilidad
DNSEl subdominio apunta al servidor.
ApacheVirtualHost y DocumentRoot de cada proyecto.
ProyectoCódigo y datos bajo /var/www/NOMBRE.
MySQL127.0.0.1:3306; acceso remoto solamente por SSH.
TransferenciaSFTP por el puerto 22; sin FTP tradicional.
6. Responsabilidades administrativas
  • Apache, PHP, firewall y paquetes se cambian con sudo y se documentan.
  • El responsable del proyecto administra su código y VirtualHost.
  • Cada proyecto tiene su base y usuario MySQL local.
  • Antes del despliegue se definen propietario, grupo y directorios de escritura.
  • Los administradores con sudo conservan capacidad total; los permisos reducen errores diarios.
7. Alta de un proyecto
  1. Crear DNS del subdominio.
  2. Crear /var/www/NOMBRE y definir public/.
  3. Crear el VirtualHost.
  4. Configurar propietario, grupo y permisos.
  5. Crear base y usuario MySQL propios.
  6. Validar Apache y logs.
  7. Emitir certificado HTTPS.
8. Preparación de Eventos
No subir todavía a /var/www/html.Primero se identifica index.php, includes, configuración de base, librerías, cargas y rutas relativas. Después se crea /var/www/eventos y eventos.denkenlab.com.mx.

Guía 03

Permisos de carpetas y archivos

Modelo reutilizable para Eventos: colaboración controlada, sin 777 y con escritura de PHP solamente donde se necesita.

1. Identidades del proyecto
IdentidadPapel
epadillaResponsable técnico y propietario operativo.
ubuntuAdministrador actual.
www-dataApache/PHP-FPM: lee el proyecto y escribe solo donde se autorice.
web-eventosGrupo compartido para colaboración controlada.
Límite realQuien tiene sudo puede cambiar propietarios y permisos; este estándar evita exposiciones accidentales en la operación diaria.
2. Significado de los modos
ModoUso
2750 / 0640Dueño escribe; grupo lee; otros no acceden. El bit 2 mantiene el grupo en carpetas nuevas.
2770 / 0660Dueño y grupo escriben; se reserva para áreas donde PHP crea o modifica archivos.
Nunca 777Evita que cualquier usuario local modifique el proyecto.

En carpetas, x significa poder atravesar la ruta. Sin x, Apache no puede llegar a los archivos aunque tengan lectura.

3. Árbol recomendado
/var/www/eventos/
├── public/
│   ├── index.php
│   ├── assets/
│   └── uploads-publicos/      # Solo si se publican por URL
├── app/
├── config/
│   └── .env
├── storage/
│   ├── logs/
│   ├── cache/
│   ├── sessions/
│   └── uploads-privados/
└── vendor/
4. Matriz de permisos
RutaDueño:grupoModo
/var/www/eventosepadilla:web-eventos2750
app/, config/, vendor/epadilla:web-eventos2750 dirs / 0640 files
config/.envepadilla:web-eventos0640
public/ y assets/epadilla:web-eventos2750 dirs / 0640 files
public/uploads-publicos/epadilla:web-eventos2770 dirs / 0660 files
storage/epadilla:web-eventos2770 dirs / 0660 files
VirtualHostroot:root0644
Logs Apacheroot:adm0640
5. Qué cambia dentro de public/

Que una carpeta sea pública por web no significa que deba estar abierta en Unix. Apache lee porque www-data pertenece a web-eventos.

No colocar dentro.env, conexiones, includes, app/, respaldos SQL/ZIP, logs, temporales o cargas privadas.
6. Crear grupo y rutas
Ejecutar después de revisar la estructura real de Eventos.Estos comandos preparan el modelo definitivo.
sudo groupadd -f web-eventos
sudo usermod -aG web-eventos epadilla
sudo usermod -aG web-eventos ubuntu
sudo usermod -aG web-eventos www-data

sudo install -d -o epadilla -g web-eventos -m 2750 /var/www/eventos
sudo install -d -o epadilla -g web-eventos -m 2750 /var/www/eventos/{public,app,config,vendor}
sudo install -d -o epadilla -g web-eventos -m 2770 /var/www/eventos/storage
sudo install -d -o epadilla -g web-eventos -m 2770 /var/www/eventos/storage/{logs,cache,sessions,uploads-privados}
sudo install -d -o epadilla -g web-eventos -m 2770 /var/www/eventos/public/uploads-publicos

Tras agregar usuarios al grupo, deben cerrar y abrir SSH/SFTP. Reiniciar PHP-FPM y Apache para que www-data tome el grupo.

7. Archivos creados por PHP

Si el proyecto necesita escritura compartida, el pool PHP-FPM específico puede usar:

; Pool PHP-FPM específico de Eventos
umask = 0002

sudo systemctl restart php8.5-fpm
sudo systemctl reload apache2
No cambiar la umask global.Se aplica únicamente al pool que realmente necesita crear archivos editables por web-eventos.
8. Comprobación final
  • DocumentRoot apunta exactamente a /var/www/eventos/public.
  • .env está fuera de public y conserva 0640.
  • Revisar eventos-error.log y storage/logs.
  • Las cargas privadas quedan en storage/uploads-privados.
  • No existen SQL, ZIP, .env ni logs descargables por URL.

Guía 04

Crear subdominios

Patrón probado con test.denkenlab.com.mx: DNS explícito, carpeta public, VirtualHost, validación local y comprobación externa.

1. Modelo
ElementoDecisión
Dominio raízLanding o sitio principal.
Proyecto/var/www/NOMBRE_PROYECTO
DirecciónNOMBRE.denkenlab.com.mx
ApacheVirtualHost, DocumentRoot y logs propios.
Web pública/var/www/NOMBRE_PROYECTO/public
Prueba completadatest.denkenlab.com.mx responde desde /var/www/test/public/index.html.
2. DNS en ClouDNS
CampoValor para Test
Hosttest
TipoCNAME
Destinodenkenlab.com.mx
TTL1 minuto

Para Eventos se repite como eventos → CNAME → denkenlab.com.mx. El CNAME sigue al dominio raíz si la IP cambia.

3. Estructura mínima
/var/www/test/
└── public/
    └── index.html
Fuera de public.env, credenciales, SQL/ZIP, logs, código interno y datos privados.
4. Crear prueba HTML
sudo install -d -o ubuntu -g www-data -m 2755 /var/www/test/public
sudo nano /var/www/test/public/index.html
<!doctype html>
<html lang="es">
<head><meta charset="utf-8"><title>Test | denkenlab</title></head>
<body>
  <h1>Subdominio test funcionando</h1>
  <p>Este contenido se sirve desde /var/www/test/public</p>
</body>
</html>
5. VirtualHost de Apache
sudo nano /etc/apache2/sites-available/test.denkenlab.com.mx.conf

<VirtualHost *:80>
    ServerName test.denkenlab.com.mx
    DocumentRoot /var/www/test/public

    <Directory /var/www/test/public>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/test-error.log
    CustomLog ${APACHE_LOG_DIR}/test-access.log combined
</VirtualHost>
6. Activar y validar
sudo a2ensite test.denkenlab.com.mx.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Solo recargar con “Syntax OK”.Si configtest marca error, corregir primero el VirtualHost.
curl -i -H 'Host: test.denkenlab.com.mx' http://127.0.0.1/

Debe devolver HTTP/1.1 200 OK y el HTML esperado, incluso antes de la propagación DNS.

7. Diagnóstico
PruebaRevisión
nslookup test.denkenlab.com.mxDebe resolver al CNAME o a la IP pública.
Página de otro sitioRevisar ServerName, DocumentRoot y a2ensite.
403Permisos de carpetas y Require all granted.
500sudo tail -f /var/log/apache2/test-error.log
8. HTTPS

Después de que DNS resuelva, emitir certificado Let’s Encrypt y forzar redirección de HTTP a HTTPS. El puerto 443 ya está abierto; no se requiere otro puerto.

9. Checklist reutilizable
  • Crear CNAME NOMBRE → denkenlab.com.mx.
  • Crear /var/www/NOMBRE/public.
  • Crear VirtualHost con ServerName y DocumentRoot.
  • Ejecutar a2ensite, configtest y reload.
  • Probar con curl y navegador.
  • Definir permisos, base y usuario MySQL.
  • Emitir HTTPS y validar redirección.

Control de acceso

Protección de este portal

La contraseña no vive en este HTML. Apache autentica antes de entregar el archivo y las credenciales viajan únicamente mediante HTTPS.

1. Diseño de seguridad
UsuarioHTTPSApache solicita credencialeshtpasswd fuera de publicPortal autorizado
No usar una pantalla de contraseña en JavaScript.El HTML se descarga en el navegador y cualquier secreto embebido podría inspeccionarse.
2. Usuarios individuales

Crear un usuario para Willy y otro para Epadilla. Cada contraseña se revoca de forma independiente y no se comparte.

sudo apt install -y apache2-utils
sudo htpasswd -c /etc/apache2/htpasswd-denkenlab-docs willy
sudo htpasswd /etc/apache2/htpasswd-denkenlab-docs epadilla

sudo chown root:www-data /etc/apache2/htpasswd-denkenlab-docs
sudo chmod 0640 /etc/apache2/htpasswd-denkenlab-docs
La opción -c se usa solamente al crear el archivo.Volver a usarla eliminaría los usuarios anteriores.
3. Proteger el VirtualHost

Estas directivas se añaden al bloque <Directory /var/www/test/public>:

AuthType Basic
AuthName "Documentación interna denkenlab"
AuthUserFile /etc/apache2/htpasswd-denkenlab-docs
Require valid-user
AtenciónAl usar Require valid-user, sustituye el Require all granted de la prueba pública.
4. HTTPS antes de usar contraseñas

La autenticación Basic es válida sobre TLS. Sin HTTPS, usuario y contraseña no quedan cifrados de forma segura.

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d test.denkenlab.com.mx

Después se comprueba la renovación:

sudo certbot renew --dry-run
5. Verificación
  • HTTP redirige a HTTPS.
  • Sin credenciales Apache devuelve 401 Unauthorized.
  • Willy y Epadilla ingresan con cuentas separadas.
  • El archivo htpasswd no está bajo /var/www.
  • No hay llaves, contraseñas, .env ni respaldos dentro del HTML.
  • La página no se indexa como contenido público.
curl -I https://test.denkenlab.com.mx
# Esperado sin credenciales: HTTP/2 401
Copiado al portapapeles