Etiqueta: Infraestructura

  • ¿Cómo direccionar un dominio a un contenedor Docker?

    ¿Cómo direccionar un dominio a un contenedor Docker?

    Tenés tu entorno local funcionando perfecto con Docker.

    Llevar la imagen al hosting y crear el contenedor no es un problema pero, cuando querés que los clientes vean el sitio… ¿qué les tenés que pasar? ¿No sería genial poder pasarles una URL con tu propio dominio?

    Veamos qué necesitarías para hacerlo.

    1. Un servidor donde alojar tus contenedores
    2. Un dominio que puedas direccionar a tu servidor
    3. La configuración de DNS
    4. La configuración del webserver dentro de Docker

    Asumiré que los puntos 1, 2 y 3 los tenés resueltos y me concentraré en el punto 4.

    Cómo configurar Docker para que responda a un dominio único

    Si se trata de un único contenedor corriendo en el servidor no es necesario hacer demasiado. Basta con asegurarse de que el contenedor esté conectado al puerto 80 del servidor.

    Por ejemplo, si se inicia en un servidor un contenedor usando algo como:

    docker run --restart=always -p  80:80 imagen -d

    Será suficiente para dejar el contenedor corriendo en background en forma constante.

    Con una configuración estándar de Apache como por ejemplo:

    <VirtualHost *:80>
    	# The ServerName directive sets the request scheme, hostname and port that
    	# the server uses to identify itself. This is used when creating
    	# redirection URLs. In the context of virtual hosts, the ServerName
    	# specifies what hostname must appear in the request's Host: header to
    	# match this virtual host. For the default virtual host (this file) this
    	# value is not decisive as it is used as a last resort host regardless.
    	# However, you must set it for any further virtual host explicitly.
    	ServerName www.example.com
    
    	ServerAdmin webmaster@localhost
    	DocumentRoot /var/www/html
    
    	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
    	# error, crit, alert, emerg.
    	# It is also possible to configure the loglevel for particular
    	# modules, e.g.
    	#LogLevel info ssl:warn
    
    	ErrorLog ${APACHE_LOG_DIR}/error.log
    	CustomLog ${APACHE_LOG_DIR}/access.log combined
    
    	# For most configuration files from conf-available/, which are
    	# enabled or disabled at a global level, it is possible to
    	# include a line for only one particular virtual host. For example the
    	# following line enables the CGI configuration for this host only
    	# after it has been globally disabled with "a2disconf".
    	#Include conf-available/serve-cgi-bin.conf
    </VirtualHost>
    
    # vim: syntax=apache ts=4 sw=4 sts=4 sr noet

    Es suficiente.

    En definitiva, casi que es más difícil lograr que el contenedor no quede asociado al dominio que lo contrario.

    Cómo configurar Docker para que responda a diferentes dominios

    Distinto, y más interesante, es el caso de querer alojar en un mismo servidor varios sitios diferentes, cada uno con su propio contenedor.

    Para lograr eso se requiere algo más de maña a nivel de infraestructura.

    Un webserver como Apache permite, por ejemplo, usar múltiples hosts virtuales (VirtualHost) pero, obviamente, el puerto 80 del servidor es uno solo. Esto quiere decir que hay un único proceso escuchando en el puerto 80 y, de todo el tráfico que se recibe a través de él, es su responsabilidad decidir cómo responder.

    Para que a cada sitio le llegue el tráfico que le corresponde, y sólo ese tráfico, es necesario definir algún tipo de mapeo entre la petición que recibe el webserver y el host virtual que lo atenderá.

    Una forma de hacer esto es asociar diferentes hosts a diferentes puertos.

    <VirtualHost *:80>
    	...
    </VirtualHost>
    <VirtualHost *:81>
    	...
    </VirtualHost>
    <VirtualHost *:82>
    	...
    </VirtualHost>

    Claro que, si la idea es que a todos los sitios se acceda a través del puerto estándar, esta opción queda descartada.

    Otra opción disponible es desambiguar por IP:

    <VirtualHost 172.21.0.1:80>
    	...
    </VirtualHost>
    <VirtualHost 137.184.122.59:80>
    	...
    </VirtualHost>
    <VirtualHost 93.184.216.34:80>
    	...
    </VirtualHost>

    Esto puede funcionar si hay más de una IP pública asociada al servidor.

    Lo más común, sin embargo, es desambiguar a través del ServerName:

    <VirtualHost *:80>
    	ServerName dominio1.com
    </VirtualHost>
    <VirtualHost *:80>
    	ServerName dominio2.com
    </VirtualHost>
    <VirtualHost *:80>
    	ServerName dominio3.com
    </VirtualHost>

    En este esquema, Apache determinará qué VirtualHost es el requerido analizando la URL. Un request de tipo http://dominio1.com será atendido siguiendo la primera definción, http://dominio2.com la segunda y http://dominio3.com la tercera.

    El primer paso es claro: definir un VirtualHost por cada dominio que se quiera usar.

    Segundo paso: conectar el tráfico del host al contenedor que le corresponde.

    Para lograr esto es necesario contar con el módulo proxy de Apache. En el caso de Ubuntu basta con el comando sudo a2enmod proxy_http; sudo service apache2 restart para tenerlo todo listo.

    Luego, por cada sitio que se quiera servir, se debe crear la configuración del VirtualHost:

    <VirtualHost *:80>
        ServerName dominio1.com
        ProxyPass / http://127.0.0.1:5000/
        ProxyPassReverse / http://127.0.0.1:5000/
    </VirtualHost>

    De esta forma, todo el tráfico que se reciba a través de http://dominio1.com será redirigido automáticamente hacia el puerto 5000 dentro del mismo servidor (De ahí el 127.0.0.1).

    Por último, para cerrar el círculo se necesita contar con un contenedor Docker escuchando en el puerto seleccionado, en este caso, el 5000. Con esto será suficiente para la prueba.

    docker run -p 5000:80 -v $(pwd):/var/www/html php:7.4-apache

    Asumiendo que el directorio actual contiene un archivo como este:

    <?php
    
    echo phpversion();

    Al abrir el navegador en http://dominio1.com/ se verá algo como:

    Si aún no tenés los dominios apuntados al servidor o querés hacer pruebas en tu entorno local basta con que modifiques tu archivo /etc/hosts apuntando todos los dominios a 127.0.0.1.

    El caso del segundo dominio será prácticamente igual:

    <VirtualHost *:80>
        ServerName dominio2.com
        ProxyPass / http://127.0.0.1:5001/
        ProxyPassReverse / http://127.0.0.1:5001/
    </VirtualHost>

    La diferencia está en el puerto. El contenedor para el segundo dominio deberá estar escuchando a un puerto diferente en el host, pero éste deberá estar mapeado al puerto 80 dentro del contenedor. Por ejemplo:

    docker run -p 5001:80 -v $(pwd):/var/www/html php:8.2-apache

    Y, nuevamente, al abrir el navegador en http://dominio2.com verás:

    Y así continúa por cada uno de los dominios que necesites apuntar

  • Por qué NO deberías usar XAMPP

    Por qué NO deberías usar XAMPP

    Me llegó esta pregunta que me pareció interesante compartir:

    Estoy usando PHPStorm, y como sólo me pide el intérprete cuando trato de ejecutar en el navegador, todavía no lo he instaldo, quisiera saber si ya es mejor instalar el Xampp, si es recomendable y en caso de que no lo sea ¿por que?

    Por si no sabés de qué se trata XAMPP, es un paquete que trae, todo lo que típicamente se requiere para desarrollar con PHP:

    La X del comienzo puede ser reemplazada por L (Linux), W (Windows) o M (Mac).

    A primera vista parece la panacea, ¿no?

    «Es lo más fácil!»

    «Un par de clics y listo!»

    «¿Para qué complicarme instalando todo por separado si puedo tenerlo en un solo paquete»?

    Seguramente habrás escuchado este tipo de argumentos a su favor.

    Y sí, todo eso es verdad: XAMPP es un paquete sumamente cómodo… al principio.

    Los problemas llegan cuando:

    • Es momento de ir a producción
    • Necesitás trabajar con diferentes proyectos a la vez.

    Son estos los momentos en te das cuenta que el salvavidas estaba hecho de plomo.

    Cuál es el problema con XAMPP

    La sencillez que aporta XAMPP lo hace la opción más difundida entre los desarrolladores menos experimentados. Pero esa sencillez tiene un costo.

    El primero de los problemas es que, al ocultar la complejidad real que implica montar un servidor, se propicia el efecto «¡Te juro que en mi casa andaba!». Como no sabés realmente qué tenés instalado es difícil verificar que el hosting tenga lo mismo (Más detalle de qué es exactamente lo que deberías mirar acá).

    El segundo de los problemas es que hace muy difícil trabajar en diferentes proyectos donde cada uno tiene requerimientos de infraestructura diferentes (Por ejemplo, versiones diferentes del intérprete de PHP).

    Por supuesto que, si sos conciente de estas limitaciones y sabés trabajar con ellas XAMPP puede ser una opción aceptable.

    Qué usar en lugar de XAMPP

    Las opciones son varias, hay algunas mejores que XAMPP y otras peores:

    En general, docker es la mejor opción cuando se trata de montar entornos locales ya que es muy simple luego llevarlos a producción y/o compartir con tu equipo.

    Pero bueno, es cierto también que dominarlo no es una tarea muy sencilla.

    Si recién estás empezando (Y quiero decir que apenas estás dando tus primeros pasos), está bien que uses XAMPP pero es importante que tengas la idea de migrar lo antes posible.

  • «Mi sitio funcionaba bien hasta que el hosting actualizó PHP»

    «Mi sitio funcionaba bien hasta que el hosting actualizó PHP»

    Hace poco me contactó un colega por una situación algo complicada que le tocó enfrentar.

    La historia comienza así:

    Nuestro sitio está programado con PHP 5.5 y usa memcached. Estamos queriendo migrarlo a una versión más alta de PHP y tenemos un problemita.

    Y sigue:

    …guardamos la sesión en memcache porque tenemos varios fronts y dependiendo de la versión el error es diferente

    Se va poniendo interesante, ¿no? Veamos un poco más:

    …con php 5.5 todo andaba perfecto, tanto en Windows con WAMP para desarrollar como con Linux/Centos

    El resto te lo podrás imaginar supongo.

    En general no soy muy partidario de desarrollar en Windows y desplegar en Linux (Una de las razones que llevan a la falsa idea de que todo va a funcionar bien).

    Vayamos a lo importante: ¿cómo tomaron la decisión de migrar a una versión más actualizada?

    …la gente que instala los servidores sugirió ir a la última versión de PHP y Apache y Centos y postgresql pero no va

    Bien, ahora está más claro.

    Llegados a este punto estamos realmente en un problema: por un lado, el sitio tiene que seguir funcionando.

    Por el otro, no podemos pedirle al hosting que habilite una versión de PHP que sabemos que es compatible con nuestro sistema.

    ¿Qué se puede hacer?

    Lo mejor sería buscar una imagen de docker que tenga la versión que buscamos, instalarla en el servidor y seguir la vida como si tal cosa.

    Si esa no es una posibilidad, habrá que hacerse a la idea de que la solución tomará algún tiempo… con todo lo que ello implica.

    Saltarse versiones de php puede ser bastante arriesgado.

    En este caso, ir de la 5.5 directo a la 8.1 implica dejar de lado una serie de cambios que se realizaron al intérprete a tavés de los años, algunos para hacerlo más eficiente y otros para quitarle funciones que ya pueden seguir soportándose.

    El camino más seguro llegados a este punto sería ir bajando de versión del lado del hosting (8.1., 8.0, 7.4 y así) hasta llegar a una que, o bien sea compatible con el sistema, o sea la más antigua soportada por el proveedor.

    Si se llega al primer escenario (Una versión superior a la que veníamos usando pero en la que el sistema funciona bien) perfecto, tema resuelto.

    Si, en cambio, la versión más antigua con la que podemos contar no es compatible con el sistema, tenemos trabajo por delante.

    Supongamos por tomar un ejemplo que la versión más baja que nos permite usar el proveedor es la 7.1.

    Entre la versión 5.5 y la 7.1 hubo tres versiones intermedias (5.6, 7.0 y la propia 7.1).

    La manera más segura de llegar de una versión de php a otra es pasar por todas las intermedias.

    Antes de que me lo digas, sí, es un trabajo arduo y molesto, lo sé… pero me temo que es la posibilidad menos riesgosa, así que… más vale empezar a trabajar.

    Lo que vas a necesitar es seguir este proceso:

    1. Instalar en un ambiente de pruebas la versión a la que vas a intentar migrar (5.6 sería la primera en este caso)
    2. Instalar y configurar el sistema en dicho ambiente de pruebas
    3. Ejecutar las pruebas
    4. Hacer los ajustes correspondientes al código
    5. Pasar a la siguiente versión y volver al paso 1

    Algunas herramientas que te van a ayudar

    Existen algunas herramientas en las que te podés apoyar para hacer este proceso algo menos laborioso:

    En general, migrar a una nueva versión de php no es precisamente una tarea sencilla pero si encima lo tenés que hacer a las apuradas… puede volverse una verdadera pesadilla.

    Esto es algo que difícilmente puedas prevenir si estás en ambientes de hosting que no controlás.

    Si este es tu caso tal vez te convenga evaluar migrarte hacia tu propio servidor.

  • 8 razones por las que falla una aplicación PHP

    Es una historia que se repite una y otra vez: el sistema funciona perfecto en tu XAMPP pero cuando lo subís al hosting misteriosamente nadie puede registrarse ni logearse.

    Es el mismo codigo en el webserver y en localhost, no entiendo por qué da error en uno sí y otro no

    Dentro de xampp no me presenta problema, sólo en el hosting

    Estoy trabajando con laravel y estoy tratando de generar un sitemap.xml automatico, pero cuando lo genero no me lo guarda en la carpeta publica, solo logre que me lo guarde en el raiz del cpanel y no puedo hacer que me lo genere dentro del public_html

    ¿Qué pasó? El código es exactamente el mismo, lo viste funcionar con tus propios ojos.

    La única diferencia es que la URL, en lugar de empezar por http://localhost empieza por http://dominio.com, ¿cierto?

    Me temo que las diferencias pueden ir bastante más allá de eso.

    Para evitarte unas cuantas vueltas y dolores de cabeza te voy a contar las razones más frecuentes que llevan a este comportamiento.

    Intentaré ir de lo más frecuente hacia lo menos.

    Aquí voy.

    La versión de PHP

    La primera gran dependencia que toda aplicación php tiene es el propio intérprete.

    Si desarrollás en forma local tenés instalado algún paquete que permite transformar esto:

    <html>
      <body><p><?php echo "Hola mundo!"; ?></p></body>
    </html>

    En

    <html>
      <body><p>Hola mundo!"</p></body>
    </html>

    Generalmente esta responsabilidad le corresponde al servidor web que tenés instalado en tu computadora (¿XAMPP tal vez?).

    En tu hosting hay otro servidor web con una configuración similar pero no necesariamente idéntica.

    PHP es un lenguaje que está en constante evolución, año a año salen nuevas versiones y, si bien se hace un esfuerzo muy grande por mantener la compatibilidad con versiones viejas, esto no siempre se logra.

    Es por eso que algunas cosas que funcionan en una versión dejan de funcionar en las siguientes.

    En conclusión: lo primero que deberías verificar es que tu versión de PHP local es igual a la que tiene tu hosting.

    El archivo php.ini

    Además del intérprete, php dispone de un archivo de configuración especial: php.ini.

    En este archivo se definen ciertos parámetros que determinan detalles de cómo el intérprete realiza esa transformación.

    Las variables que pueden configurarse a través de este archivo son ciertamente muchas. Algunas son más críticas que otras.

    Un ejemplo muy simple es el de la directiva short_open_tag. Si su valor es "1" php no tendrá problemas en interpretar algo como:

    <html>
      <body><p><? echo "Hola mundo!"; ?></p></body>
    </html>

    Sin embargo, si este no es el caso, php dejará el texto tal como está, con lo cual, en lugar de transformarlo al HTML que esperás, el visitante de tu sitio verá el código.

    En conclusión: si las cosas no funcionan vale la pena comparar los cotenidos de tu php.ini y los de tu hosting.

    Las extensiones php

    PHP como tal trae una cantidad de funcionalidad incorporada pero es muy común que ciertas funciones se dejen como opcionales por razones de eficiencia.

    Para esos casos en los que se necesitan funcionalidades extras, php cuenta con el mecanismo de extensiones.

    Si tu aplicación depende de alguna en particular, por ejemplo si necesita generar gráficos, es muy probable que requiera de la presencia de una extensión en particular en el ambiente de ejecución.

    Si tu hosting no tiene instalada dicha extensión las cosas no van a funcionar como lo esperás.

    En conclusión: verificá si tu aplicación requiere alguna extensión especial y, en tal caso, asegurate de que esté presente en tu hosting.

    Los permisos

    Para que una aplicación php pueda ejecutarse es preciso que el usuario que ejecuta el servidor web tenga ciertos permisos sobre el sistema de archivos.

    Como mínimo, debe ser capaz de leer los archivos .php que componen tu aplicación.

    En muchos casos también será necesario que pueda escribir en ciertos directorios.

    En conclusión: validá que el usuario que ejecuta el webserver tenga los permisos necesarios para realizar las tareas que debe.

    La topología de red

    Típicamente cuando desarrollas en forma local la red donde tu aplicación vive es bastante sencillita: sólo existe localhost.

    Esto quiere decir que todos los servicios de los que depende son accesibles a través de la dirección de red 127.0.0.1 (O el nombre localhost, lo que es lo mismo).

    Más en concreto, si tu aplicación usa un MySQL como base de datos, es casi seguro que en algún lugar de tu código habrá una línea que se parece a:

    $link = mysqli_connect("127.0.0.1", "mi_usuario", "mi_contraseña", "mi_bd");

    Y esto funcionará sin problemas.

    El tema es que, en un entorno de hosting compartido donde hay muchos sitios hosteados en una misma computadora, es muy común que los servicios estén distribuidos en diferentes nodos de la red del proveedor.

    Esto quiere decir que, al intentar conectar al servidor de MySQL a través de la dirección 127.0.0.1 se producirá un fallo.

    En conclusión: verifica que las conexiones a servicios satélites se estén realizando utilizando las direcciones que correspnden a la red de tu hosting.

    Las rutas absolutas

    Un problema similar al anterior se da cuando se utilizan rutas absolutas.

    Por ejemplo:

    <?php
    
    require_once '/var/www/html/libreria.php';

    Puede funcionar en tu computadora porque existe en tu disco un archivo llamado libreria.php en un directorio /var/www/html/

    Si bien es posible que dicho directorio exista también en tu hosting, es bastante probable que no sea así.

    Si ese archivo está dentro del árbol de directorios de tu aplicación, una mejor forma de lograr el mismo objetivo es utilizar rutas relativas:

    <?php
    
    require_once __DIR__.'/libreria.php';

    En conclusión: usá rutas relativas en lugar de absolutas.

    La configuración del Apache

    Otro elemento que puede afectar negativamente al funcionamiento de la aplicación es la configuración del servidor web. No es que necesariamente se trate a Apache pero lo más probable es que así sea, especialmente en un ambiente de hosting compartido.

    Estas directivas afectan la forma en que el servidor web atiende los pedidos de tus visitantes.

    Muchas aplicaciones php dependen de ciertas configuraciones existentes en el archivo .htaccess (Reglas de re-escritura por ejemplo).

    Para que esto funcione, el webserver debe tener habilitado el procesamiento de este tipo de archivos

    En conclusión: valida que la configuración de tu Apache coincida con la de tu hosting.

    El sistema operativo

    El último de los sospechosos, que muchas veces es pasado por alto, es el sistema operativo sobre el que está montado el servidor.

    Si estás desarrollando en Windows y tu hosting es un Linux hay buenas chances de que no todo funcione a la primera.

    La diferencia para referenciar archivos (Cosas como c:\progams\file.php vs. /var/www/html/file.php) o el hecho de que para Linux un archivo llamado file.php no es el mismo que File.php mientras que para Windows sí son sólo algunas de las sutiles diferencias que pueden darte la idea de que el sistema está listo para subirse cuando en realidad estás a punto de abrir la caja de Pandora.

    En conclusión: verificá que tu código no dependa de características particulares de un sistema operativo.

    Cómo usar esta información

    A lo largo de este post te conté las razones que más comúnmente hacen que un despliegue de una aplicación PHP sea más traumático de lo que debería.

    Ahora que las conocés te recomiendo que las revises nuevamente y las uses a modo de lista de verificación para planificar tus próximas entregas.

  • Cómo ejecutar varias versiones de PHP en mismo NginX

    Cómo ejecutar varias versiones de PHP en mismo NginX

    Trabajando con un cliente me encontré ante este escenario:

    En un mismo servidor (Una instancia de AWS) había una aplicación desarrollada usando CodeIgniter y otra basada en Symfony.

    Al momento de comenzar mi intervención ambas aplicaciones compartían un mismo servidor web (NginX) y el binario de php para ejecutar algunos scripts de línea de comandos.

    El problema era que la versión de CodeIgniter en la que se había realizado el desarrollo (2.2.6) no podía actualizarse a la más reciente (4.1.5) sin re-escribir casi por completo la aplicación.

    Mientras tanto, la aplicación Symfony fue siguiendo la evolución del framework bastante de cerca.

    Para continuar el mantenimiento de la aplicación Symfony, y aprovechar nuevas caracterísitcas de rendimiento y seguridad, se hacía conveniente actualizar la versión de PHP y, difícilmente este cambio sería soportado por la aplicación vieja.

    La mejor solución sería darle a cada aplicación su propio entorno de ejecución de modo de que ninguna se vuelva un cuello de botella para la otra.

    La decisión fue mantener ambas versiones del lenguaje disponibles y que cada sitio utilizara la que le correspondiera (Al menos hasta definir qué hacer con la aplicación CodeIgniter).

    Pensé en pasar ambas a Docker y no descarto hacerlo más adelante pero, por el momento, me pareció demasiado esfuerzo para poco beneficio.

    Para tener dos versiones diferentes de PHP ejecutando en un mismo servidor es necesario:

    1. Instalar la nueva versión
    2. Modificar la configuración del WebServer
    3. Modificar la configuración de los cronjobs

    Cómo instalar una nueva versión de PHP

    El servidor en cuestión es un Ubuntu, de modo que instalar una nueva versión de PHP (8.0 en mi caso) requiere estos comandos:

    sudo add-apt-repository ppa:ondrej/php
    sudo apt install php8.0

    Con esto queda instalado el binario de php en su versión 8, luego hay que tener en cuenta instalar las extensiones que sean necesarias.

    Una vez finalizado el proceso, con este comando:

    update-alternatives --display php

    Vemos que se ha instalado la nueva versión:

    php - manual mode
      link best version is /usr/bin/php8.0
      link currently points to /usr/bin/php7.3
      link php is /usr/bin/php
      slave php.1.gz is /usr/share/man/man1/php.1.gz
    /usr/bin/php7.3 - priority 73
      slave php.1.gz: /usr/share/man/man1/php7.3.1.gz
    /usr/bin/php8.0 - priority 80
      slave php.1.gz: /usr/share/man/man1/php8.0.1.gz

    Notá como el comando php es un link simbólico que está alojado en /usr/bin/php y apunta a /usr/bin/php7.3. Es por eso que php -v muestra:

    PHP 7.3.19-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Jun 12 2020 07:48:30) ( NTS )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.3.19, Copyright (c) 1998-2018 Zend Technologies
        with Zend OPcache v7.3.19-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies

    Es decir, si queremos asegurarnos de estar ejecutando la versión 8.0 el comando que nos da más certeza es /usr/bin/php8.0 -v:

    PHP 8.0.13 (cli) (built: Nov 22 2021 09:50:24) ( NTS )
    Copyright (c) The PHP Group
    Zend Engine v4.0.13, Copyright (c) Zend Technologies
        with Zend OPcache v8.0.13, Copyright (c), by Zend Technologies 

    Perfecto. Tengamos esto en cuenta para dentro de un rato cuando veamos lo que pasa con los cronjobs.

    Cómo especificar la versión de PHP para cada sitio

    Para este punto viene muy bien el hecho de estar usando NginX como servidor web. A diferencia de Apache que puede tener PHP incorporado, NginX se limita a servir contenido estático y delega la ejecución de PHP en otro proceso (php-fpm).

    Si miramos el archivo de configuración de cada sitio veremos algo como:

    server {
        ...
        location ~ ^/index\.php(/|$) {
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    
            fastcgi_intercept_errors off;
            fastcgi_buffer_size 16k;
            fastcgi_buffers 4 16k;
        }
    
        ...
    }

    En particular la línea que nos interesa en este caso es:

    fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;

    Aquí se está definiendo el canal de comunicación entre el servidor web y el proceso que atenderá las peticiones php.

    De modo que lo que debemos cambiar es el 7.3 por 8.0 en el archivo que corresponde a la aplicación más nueva.

    Claro que, para que esto funcione debemos contar con php8.0-fpm.

    Para instalarlo puede usarse el comando:

    sudo apt install php8.0-fpm

    Y con eso ya contaremos con el proceso FastCGI que necesitamos.

    Por supuesto que, antes de aplicar estos cambios en producción es prudente realizar pruebas en un ambiente controlado. Asumiendo que ya se realizaron dichas pruebas y se corrigieron eventuales inconvenientes, con los cambios realizados la aplicación web está lista.

    Resta ver qué hacer con las tareas programadas y/o scripts de línea de comandos que se utilicen.

    En este caso lo que hay son algunas tareas programadas vía cron.

    Cómo especificar la versión de PHP para cada cronjob

    Usando el comando crontab -l obtenemos algo como:

    # Edit this file to introduce tasks to be run by cron.
    # 
    # Each task to run has to be defined through a single line
    # indicating with different fields when the task will be run
    # and what command to run for the task
    # 
    # To define the time you can provide concrete values for
    # minute (m), hour (h), day of month (dom), month (mon),
    # and day of week (dow) or use '*' in these fields (for 'any').# 
    # Notice that tasks will be started based on the cron's system
    # daemon's notion of time and timezones.
    # 
    # Output of the crontab jobs (including errors) is sent through
    # email to the user the crontab file belongs to (unless redirected).
    # 
    # For example, you can run a backup of all your user accounts
    # at 5 a.m every week with:
    # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
    # 
    # For more information see the manual pages of crontab(5) and cron(8)
    # 
    # m h  dom mon dow   command
    
    MAILTO=mauro.chojrin@leewayweb.com
    0 6 1 2,5,8,11 * /usr/bin/php /home/ubuntu/followapp/bin/console app:agents:send-transaction-summary

    Esto significa que todos los 1 de los meses de Febrero, Mayo, Agosto y Noviembre a las 6:00 AM se ejecuta el script PHP /home/ubuntu/followapp/bin/console pasándole como argumentos app:agents:send-transaction-summary.

    El script es el que Symfony dispone para la ejecución de comandos diseñados utilizando el framework.

    El argumento especifica cuál de todos los comandos disponibles es el que se desea ejecutar (En este caso se trata de uno diseñado a efectos de enviar a los vendedores un resumen de las transacciones realizadas durante el trimestre anterior).

    Y la parte de la línea que dice /usr/bin/php es la que especifica cuál será el binario que deberá invocarse cuando sea el momento indicado. En este caso se trata del binario de PHP.

    Claro que, en este servidor donde hay más de una versión de PHP, esta definición puede resultar ambigua (A los ojos humanos claro, para la computadora está muy claro que /usr/bin/php es un alias de /usr/bin/php7.3).

    Lo conveniente para evitar confusiones es hacer explícita la versión del intérprete que se requiere, dejando la línea del crontab de esta forma:

    0 6 1 2,5,8,11 * /usr/bin/php /home/ubuntu/followapp/bin/console app:agents:send-transaction-summary

    Y ahora sí, con este último cambio está todo listo para tener ambas versiones conviviendo en armonía.

    Unas últimas notas

    Como habrás podido apreciar, no es realmente complejo lograr esta configuración, sin embargo, siendo que el servidor ya se encuentra virtualizado, lo más conveniente sería tener una instancia separada para cada aplicación.

    La desventaja de este enfoque es que, además de los costos propios de la infraestructura, la administración puede hacerse un poco más compleja.

    Lo que debe evaluarse para decidir es el riesgo de que una aplicación falle y, al competir por los recursos con la otra, deje fuera de línea un sitio que, en principio, podría continuar operativo.

  • Cómo mostrar tu proyecto PHP sin usar un hosting

    Cómo mostrar tu proyecto PHP sin usar un hosting

    Listo. Terminado. Finito.

    Ah… qué placer, ¿no?

    Después de horas frente a la pantalla, incontables tazas de café y miles de bugs resueltos, por fin llegará el merecido descanso… sólo falta hacer la demo para el cliente.

    Es que si no se hace el cliente no podrá dar su visto bueno y sin él… difícil que haga el último pago :p

    Podrías hacer un despliegue completo en su servidor pero… ¿y si algo sale mal?

    O peor, ¿qué tal si sale todo bien y el código ya está fuera de tu control?

    ¿Cómo hacer para que otra persona vea tu trabajo sin entregarle el código?


    Existen varias opciones según cuál sea tu modo de trabajar.

    Para este artículo asumiré que desarrollas en un servidor local (XAMPP o similar).

    Usar un servidor de pruebas

    Una opción perfectamente válida es utilizar un servidor intermedio en el cual puedas desplegar tu código.

    Idealmente este servidor será tuyo, con lo cual no tendrás que entregar tu código en forma prematura.

    La principal desventaja de este método es que puede tener un costo asociado: el del hosting.

    Por otra parte, preparar este espacio puede no ser una tarea trivial y hacerlo cada vez que tengas que realizar una demostración puede ser una pérdida de tiempo significativa.

    Abrir temporalmente el acceso a localhost

    Otra opción que puede resultar mucho más económica y sencilla es abrir temporalmente el acceso a tu computadora a través de internet.

    Existen diversas herramientas que puedes utilizar para asociar un nombre de dominio a tu dirección IP, de modo de evitarle a tu cliente tener que tipearla en su navegador.

    Un ejemplo de ese tipo de solución es No-IP.

    No es una mala opción, aunque puede ser un poco compleja de administrar (amén de requerir la instalación y ejecución constante de un cliente).

    Otra posiblidad bastante más atractiva es utilizar ngrok.

    Se trata de una utilidad muy sencilla que te permite levantar un túnel hacia tu computadora y pasarle a tu cliente una URL a la cual conectarse.

    Basta con ejecutar un comando como ngrok http 80 para obtener una pantalla como esta:

    Información de ngrok ejecutándose

    Aquí puedes ver claramente cómo la dirección http://7da0fd4f278a.ngrok.io apunta al puerto 80 en mi computadora local.

    Sólo se necesita ingresar a http://7da0fd4f278a.ngrok.io para ver lo mismo que yo veo usando http://localhost.

    No está mal, ¿cierto?

    Nada de FTP, nada de crear servidores temporales ni cosas parecidas.

    ¿Lo más interesante? Al terminar la prueba sólo se necesita dar Ctrl+C y asunto finalizado.

    Terminó la demo y terminó el acceso remoto.

    Simple, rápido y económico (o BBB si lo prefieres :))

    Adelante, la próxima demo que vayas a hacer no te compliques, crea ahora mismo una cuenta en ngrok, configura el cliente y olvídate del problema de los despliegues temporales

  • ¿Qué son las extensiones de PHP?

    ¿Qué son las extensiones de PHP?

    Quién no se cruzó con mensajes como:

    Debes tener instalada/habilitada la extension en PHP sobre GD

    Pero… ¿qué es exactamente una extensión de PHP?

    Para comprenderlo debes conocer un poco cómo funciona PHP internamente.

    A continuación te daré una visión algo simplificada, si quieres una explicación completa y detallada te recomiendo este excelente tutorial de Diego Lázaro.

    PHP es un lenguaje interpretado, lo que significa que para ejecutar una aplicación escrita en PHP se requiere de un proceso auxiliar llamado intérprete (Si usas Windows ese proceso será php.exe, si usas Linux o similares será el binario php).

    Este binario se ha generado a partir de la compilación de una base de código C, la cual, como es abierta, cualquiera con los conocimientos necesarios puede leer y alterar a su antojo.

    Si bien el lenguaje incluye muchas características (funciones, variables, constantes, etc…), si tuviese que englobar TODAS las posibles necesidades se volvería algo sumamente pesado.

    Es por esta razón que los desarrolladores del lenguaje definieron un conjunto de características como parte del núcleo (o core) de PHP y otras como adicionales.

    Esto significa que cualquier instalación de PHP contará con las funcionalidades básicas mientras que, para utilizar las demás será necesario instalar y configurar algunas librerías de enlace dinámico (Archivos .dll en el caso de Windows o .so en el caso de Linux).

    Este mecanismo permite a su vez crear nuevas funciones para extender PHP (El único problema es que estas extensiones deben ser escritas también en lenguaje C).

    Por qué crear extensiones si puedo crear funciones PHP

    La razón principal es la eficiencia: el código binario, al no requerir la intervención del intérprete, ejecuta más rápido de lo que lo hace su par interpretado.

    Por supuesto que escribir una función directamente en PHP es mucho más simple que hacerlo en C, pero si la performance es un factor crítico no debe pasarse por alto esta posibilidad.

    Cómo instalar una extensión PHP

    Instalar una nueva extensión de php supone contar con un nuevo binario en nuestro servidor, con lo cual, los comandos efectivamente necesarios dependerán del sistema operativo que utilices.

    Si estás en un entorno tipo Ubuntu instalar una extensión de PHP será tan simple como escribir:

    sudo apt install php-NOMBRE_EXTENSION

    En otros entornos algo menos amigables el proceso puede incluir descargar los fuentes de la extensión y re-compilar php con algún modificador.

    Otra forma de instalar extensiones es utilizar la utilidad PECL

    Cómo activar una extensión PHP

    La activación de una extensión supone su incorporación al archivo de configuración de PHP (php.ini).

    Es muy común que las extensiones definan su propio archivo .ini, dentro del cual se agregarán variables específicas para configurar dicha extensión.

    Este es un ejemplo del archivo xdebug.ini que tengo en mi computadora:

    zend_extension=xdebug.so
    xdebug.remote_autostart=1
    xdebug.remote_connect_back=1
    xdebug.remote_enable=1

    Algunas extensiones PHP comúnmente utilizadas

    Las extensiones de PHP pueden ser desde utilidades simples hasta frameworks FullStack completos (Como Phalcon).

    Aquí un breve listado de las más utilizadas:

    • MySQLi para el acceso a bases de datos MySQL
    • cURL para la realización de peticiones HTTP
    • Zip para trabajar con archivos comprimidos
    • SimpleXML para trabajar con XML
  • Cómo migrar un sitio web sin interrumpir el servicio

    Cómo migrar un sitio web sin interrumpir el servicio

    La tarea de migrar un sitio web no es particularmente sencilla.

    Obviamente, no todos los sitios tienen la misma infraestructura, con lo cual, lo que te voy a contar no necesariamente aplica a tu caso, pero espero que te lleves algunas ideas que puedan ayudarte.

    Voy a suponer por el momento que tu sitio tiene los componentes típicos:

    1. Una base de datos
    2. Un paquete de código

    El hecho de que tu sitio esté online significa que existe, al menos, un servidor donde está alojado.

    Y por último, hay un par de componentes muy importantes si el sitio es accesible para todo público:

    1. Un dominio
    2. Una serie de registros de DNS

    Supongamos que el servidor donde está la base de datos no es el mismo que donde reside la aplicación, es decir, lo que querés hacer en principio es migrar tu código a algún otro servidor (dentro o fuera del hosting actual).

    Mi recomendación es que antes de migrar hagas un relevamiento detallado de qué infraestructura estás usando (y, esperablemente, está funcionando):

    • ¿Qué versión de PHP estás usando? ¿Qué paquetes tiene instalado?
    • ¿Qué tipo de webserver? ¿Qué versión?
    • ¿Qué motor de base de datos? ¿Qué versión?
    • ¿Qué permisos tienen los directorios de la aplicación?
    • Etc…

    Una vez tengas claro este panorama, lo siguiente es armar un plan de pruebas básico que permita detectar rápidamente si algo no quedó 100% bien durante el traspaso.

    No hay que hacer mucho acá, sólo saber cuáles son las funcionalidades críticas del sitio y qué experimentos permitirán determinar que están ok.

    La estrategia general va a ser clonar tu sitio actual y, por un tiempo lo más breve posible, tener el original y el clon conviviendo lo más armoniosamente que se pueda… y luego matar al clon.

    Por qué migrar de servidor

    Empecemos pensando en qué razones tendrías para migrar de servidor.

    Se me ocurren varias:

    • Conseguiste uno más barato
    • El hosting actual no te da el soporte que necesitás
    • El hardware te quedó chico

    O, como le ocurrió a un cliente mío recientemente, el tráfico te superó y tenés que implementar balanceo de carga.

    Cómo migrar el código de tu sitio

    Migrar el código suele ser la parte más fácil.

    Si lo tenés versionado simplemente se trata de hacer un checkout (o un git clone o similar) en tu nuevo servidor.

    Si no lo tenés versionado vas a necesitar subirlo de alguna forma… ftp, scp, rsync… la que prefieras.

    Una vez tengas el código presente en tu nuevo servidor te va a tocar modificar las configuraciones para dejar andando.

    Algo a lo que tenés que prestar atención es que el usuario de tu aplicación esté habilitado para realizar consultas desde la nueva IP (Al menos en el caso de MySQL esto puede ser un problema).

    Cómo migrar la configuración de tu sitio

    Nuevamente, esto dependerá en gran medida de cómo lo tengas montado actualmente.

    Lo ideal sería que la dependencia respecto del webserver sea mínima para evitar problemas de incompatibilidades.

    Por ejemplo, algo que suele hacerse con los sitios montados sobre Apache es usar el archivo .htaccess… claramente, si vas a migrar hacia un servidor con NginX la cosa se va a complicar.

    Si la configuración no está versionada vas a tener que asegurarte de que el hosting de destino tenga la misma configuración (idealmente) o que las configuraciones del nuevo servidor sean compatibles con tu aplicación.

    Cómo migrar un dominio a un nuevo servidor

    Acá se trata de cambiar los registros de DNS para que apunten a la IP del nuevo servidor.

    En tu servidor de nombres vas a encontrar un registro tipo A que apunta a la IP de tu servidor actual (Y tal vez encuentres uno tipo AAAA con la dirección IPv6).

    Cuando cambies ese valor cada vez que alguien escriba http://tusitio.com ingresará al servidor que responda a la nueva IP.

    El problema es que los cambios de DNS no son inmediatos (Pueden tomar hasta 48 hs!).

    Y otro pequeño problema es cómo probar todo antes de darle al botón rojo.

    Un truco que podés usar es hacer el cambio en forma local antes de tocar los DNS.

    El tema es simple: tu computadora tiene una serie de definiciones de nombres en un archivo y esa definición toma prioridad sobre cualquier otra información que se encuentre en Internet (Por un tema de optimización principalmente).

    Ese archivo está en /etc/hosts si usás Linux o similar o en C:\Windows\System32\drivers\etc\hosts si usás Windows.

    Se ve más o menos así:

    Lo que podés hacer es agregar una línea tipo:

    XX.YY.ZZ.WW     tusitio.com

    Y a partir de ahí, cualquier petición que hagas, no importa si es a través de un navegador, cURL o lo que fuera, va a ir a la IP XX.YY.ZZ.WW (No importa lo que diga el DNS).

    Una vez hayas hecho todas las pruebas y tengas confianza en que todo está en su lugar podrás efectivizar el cambio de los DNS.

    Por precaución te recomiendo no dar de baja el hosting original por un tiempo prudencial (Una semana, un mes… depende qué tan conservador quieras ser) pero claramente la prueba de fuego llegará cuando lo hagas 🙂

    En conclusión: no es una magia oculta pero para no tener sorpresas desagradables más vale dedicar algo de tiempo a planificar la mudanza.

  • Cómo usar Docker en proyectos PHP

    Cómo usar Docker en proyectos PHP

    Hace tiempo que vengo usando (¡y abogando por su uso!) máquinas virtuales para mis proyectos PHP.

    Hasta ahora me venía manejando con Vagrant y debo decir que me ha dado unas cuantas satisfacciones.

    Sin embargo, hay algunos problemas derivados de su uso:

    1. Las VM se pueden volver muy pesadas
      • Ocupan mucho espacio en el disco
      • Son lentas de levantar
      • No es sencillo tener muchas corriendo a la par (Consumen muchos recursos de hardware)
    2. No es fácil asegurarme de que en Producción y en Desarrollo tengo exactamente el mismo software instalado.

    Investigando un poco y, hay que decirlo también, por consejo de algunos colegas me metí con docker.

    Qué es Docker

    Docker es una herramienta de virtualización basada en un concepto algo diferente al que usa Vagrant: los contenedores.

    No me voy a meter acá en los detalles técnicos, simplemente diré que un contenedor hace un uso mucho más eficiente de los recursos del hardware y, a los fines prácticos, cumple la misma función que una VM.

    Cómo se usa Docker

    Docker se basa en el docker daemon corriendo constantemente y luego en un cliente que le envía comandos.

    Lo primero que necesitás es tener algún contenedor levantado… y para eso, lo primero que necesitás es tener algún contenedor creado.

    Los contenedores se crean en base a imágenes.

    Qué es una imagen de Docker

    Una imagen de docker es una definición de un entorno de ejecución completo (algo así como una VM de Vagrant).

    Un contenedor es una imagen en ejecución.

    Podrías pensarlo como la diferencia entre un programa y un proceso.

    Las imágenes docker se definen en un archivo de texto llamado Dockerfile (Bastante similar al Vagrantfile).

    Por ejemplo:

    FROM php:7.2-cli
    COPY . /usr/src/myapp
    WORKDIR /usr/src/myapp
    CMD [ "php", "./your-script.php" ]

    Lo que ves es una serie de instrucciones.

    La primera (FROM) es tal vez la más importante: la imagen base.

    Las imágenes docker manejan un concepto similar al de la herencia de POO: Sobre una imagen base es posible crear otras más especializadas.

    Para efectivamente arrancar esta imagen debemos crear un contenedor basado en ella.

    Antes de hacer eso es conveniente crear un archivo llamado your-script.php (Es importante hacerlo antes de crear el contenedor porque el comando COPY se ejecutará durante la creación y no volverá a ejecutarse hasta que el contenedor sea destruido y vuelto a crear).

    En cierto sentido, esto es como quemar una ROM 🙂

    Pues entonces, creemos un archivo your-script.php con este contenido:

    <?php
    
    echo "Estoy en docker!!".PHP_EOL;

    Y ahora sí ¡estamos listos para darle vida a nuestro primer contenedor docker!

    sudo docker build -t my-php-app .

    Con este comando hemos creado nuestro contenedor.

    Para ejecutar algún comando dentro de él usaremos:

    sudo docker run -it --rm --name my-running-app my-php-app

    Y obtendremos la salida:

    Estoy en docker!!

    Cómo correr una aplicación web PHP en docker

    Típicamente para ejecutar una aplicación web PHP vas a necesitar al menos un servidor web y el intérprete de PHP instalado.

    Podrías definir tu propia imagen instalando todos los paquetes y demás, pero… ¿vale realmente la pena?

    No.

    Puedes basar tu imagen en una que ya tenga un poco más allanado el camino.

    Por ejemplo php:7.3-apache está basada en Ubutu 18.04 y ya trae php 7.3, Apache y algún par de utilidades más.

    De modo que usando un Dockerfile como este:

    FROM php:7.3-apache
    COPY . /var/www/html/

    Podremos tener un contenedor que incluya un Apache y nuestro código en el DocumentRoot.

    Un detalle importante que falta es «avisar» a docker que queremos que nuestro contenedor pueda ser accedido desde afuera a través del puerto 80 (Muy parecido al mapeo de puertos que se usa en Vagrant).

    Para eso vamos a usar el comando EXPOSE. El Dockerfile se verá así:

    FROM php:7.3-apache
    COPY . /var/www/html/
    EXPOSE 80

    Para no complicar mucho las cosas renombremos el archivo your-script.php a index.php y usemos este comando para crear nuestro contenedor:

    sudo docker build -t my-php-web-app .

    Para entrar a ver nuestro flamante sitio tenemos que ejecutar:

    sudo docker run -p 80:80 --rm -it --name my-web-app my-php-web-app:latest

    Y, por supuesto, abrir un navegador en http://localhost.

    Si todo salió bien deberías ver algo como:

    Cómo desplegar una imagen Docker en Producción

    Muy bien, ya tenemos todo casi listo, sólo nos falta ver cómo desplegar nuestra imagen en un servidor de producción y concluimos.

    Claramente, esta es la parte que realmente hace una diferencia respecto de usar Vagrant… difícilmente vas a querer montar una VM en un servidor productivo por cada aplicación que tengas… o vas a tener una factura bien abultada en AWS.

    Existen varias opciones para realizar el despliegue. Para mantener este artículo dentro de un alcance acotado me voy a limitar a la que considero requiere menos conocimientos extra:

    1. Grabar la imagen en nuestra máquina local
    sudo docker save -o image.zip my-php-web-app
    1. Subir la imagen al servidor de producción
    scp image.zip <user>@<server-addres>:<target-location>
    1. Agregar la imagen al repositorio de docker
    docker load -i <path-to-image.zip>
    1. Crear el contenedor a partir de la imagen
    docker run -d -p 8888:80 my-php-web-app

    Y listo! Ahora se puede acceder a la aplicación entrando a la dirección pública del servidor y el puerto 8888 (Y si es tu única webapp podrías directamente mapear el puerto 80 de tu servidor al del contenedor).

  • Cómo usar URLs amigables con el Servidor Web Incorporado a PHP

    Cómo usar URLs amigables con el Servidor Web Incorporado a PHP

    Es muy común, desde la versión 5.4 de PHP, usar el servidor que viene incorporado mientras estamos en un ambiente de desarrollo (¿Para qué negarlo? ¡Es sumamente cómodo!).

    Un problema que sucede a menudo al utilizarlo es cómo usar URLs amigables.

    Por ejemplo, a un sitio web productivo no vas a querer que se acceda mediante algo como:

    https://misitio.com/index.php?fecha=2019-06-25&slug_categoria=top10

    Más bien vas a preferir algo como:

    https://misitio.com/articulos/2019-06-25/top10

    ¿O no?

    El problema es que, en el caso de PHP, las variables que se reciben a través de la URL son accesibles a los scripts a través de la variable $_GET.

    Claro que, para que esto suceda, estas URLs deben estar escritas respetando el formato canónico:

    1. La separación entre URLs y parámetros se marca con el caracter «?»
    2. La separación entre nombre del parámetro y valor se marca con el caracter «=»
    3. La separación entre valor de un parámetro y nombre del siguiente se marca con el caracter «&»

    La solución a este problema pasa por aplicar lo que se conoce como reglas de re-escritura.

    Qué son las reglas de re-escritura

    Las reglas de re-escritura son instrucciones que se le dan al servidor web para transformar URLs agradables en otras más útiles.

    Básicamente se trata de reglas de mapeo que establecen a qué URL real le corresponde cada URL amigable.

    Usualmente estas reglas se escriben utilizando expresiones regulares (Claro que la sintaxis exacta dependerá del software de servidor web que estés utilizando).

    Por ejemplo, una regla de re-escritura de Apache se verá de esta forma:

    RewriteRule .? http://www.example.com%{REQUEST_URI} [R=301,L] 

    En un entorno productivo, las reglas de re-escritura se escriben en algún archivo de configuración del webserver, en desarrollo en cambio, el tema puede no ser tan fácil…

    Cómo usar reglas de re-escritura con el servidor incorporado a PHP

    El servidor web incorporado a PHP no tiene un mecanismo explícito de re-escritura de URLs, sin embargo, es perfectamente posible el uso de URLs amigables.

    El truco es iniciar el servidor web dirigiendo todo el tráfico hacia un archivo en particular.

    Por ejemplo:

    php -S localhost:8000 router.php

    Al hacer esto, todos los pedidos que lleguen a http://localhost:8000 serán atendidos por el archivo router.php.

    Nuestra tarea ahora es escribir el código dentro del archivo de modo tal que realice las transformaciones necesarias.

    Para ello vamos a apoyarnos en:

    1. La variable $_SERVER[«REQUEST_URI»]
    2. La función preg_match

    De la variable $_SERVER[«REQUEST_URI»] obtendremos la URL tal como la escribió el usuario.

    Con la función preg_match validaremos si dicha URL tiene una cierta forma y, de ser así, redirigiremos la petición a donde correponda.

    Veamos un ejemplo de router:

    <?php
    
    $matches = $_GET = [];
    
    if (preg_match('/\/([^\/]+)\/([^\/]+)/', $_SERVER["REQUEST_URI"], $matches)) {
        $_GET['resource_type'] = $matches[1];
        $_GET['resource_id'] = $matches[2];
    
        error_log( print_r($matches, 1) );
        require 'server.php';
    } elseif ( preg_match('/\/([^\/]+)\/?/', $_SERVER["REQUEST_URI"], $matches) ) {
        $_GET['resource_type'] = $matches[1];
        error_log( print_r($matches, 1) );
    
        require 'server.php';
    } else {
    
        error_log('No matches');
        http_response_code( 404 );
    }

    En este caso estoy usando la expresión regular /\/([^\/]+)\/([^\/]+)/ para buscar URLs que tengan la forma /algo/otraCosa (O, más concreto: /articulos/deportes) y la expresión /\/([^\/]+)\/?/ para URLs de tipo /algo.

    Si la URL efectivamente coincide con alguno de los patrones buscados tomaré las coincidencias y con eso llenaré el arreglo $_GET lo cual, en definitiva logra la transformación de fragmento de URL en parámetro.

    Y por último, realizaré el require para delegar el control en el archivo que efectivamente sabrá cómo procesar este request.

    No está mal, ¿cierto? 🙂

    Un tip extra, por si te estás enloqueciendo con las expresiones regulares, me ayudó mucho usar este verificador: https://regex101.com/