Ir directamente al contenido

Ajustes de cookies

Elija por tipo qué cookies permite. Puede cambiar su elección en cualquier momento en Ajustes de cookies, al pie de cada página. Declaración de privacidad

Necesarias

Siempre activadas

Necesarias para iniciar sesión, conservar su carrito y recordar sus preferencias. Siempre están activadas.

¿Qué cookies?
  • weboke_sessie, weboke_klant, weboke_remember: su sesión y mantener la sesión iniciada
  • weboke_basket: su carrito
  • wkBtwIncl: mostrar los precios con o sin IVA
  • wok_cookies: su elección de cookies, 12 meses

Mide qué anuncio lleva a una visita o a un pedido, para no pagar por anuncios que no sirven de nada.

¿Qué cookies?
  • Google Ads a través de Google Tag Manager (_gcl_au, _gcl_aw), hasta 90 días
  • OpenAI Ads, anuncios en ChatGPT
  • wok_aff: a través de qué socio llegó a nosotros (programa de afiliados), 60 días

4,6

País e idioma

Cada país tiene su propio sitio, con los precios y el IVA de ese país.

Ver

Servicios propios y temporizadores

Módulo 6: Servicios y registros · Tiempo de lectura: 11 minutos

Objetivo de aprendizaje: Después de esta lección, podrá ejecutar su propio programa como servicio systemd con un usuario propio y algunas opciones de seguridad, y planificar tareas con un temporizador systemd o con cron.

Conceptos clave: archivo de unit, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, temporizador, OnCalendar, Persistent, crontab

¿Por qué no simplemente "nohup" o "screen"?

Quien instala un programa propio en un servidor (una pequeña aplicación web, un bot, un script que hace algo cada noche) a menudo lo inicia a mano la primera vez: node server.js &, o en una sesión de screen. Eso funciona hasta que usted cierra la sesión, el servidor se reinicia o el programa se bloquea. Entonces desaparece, y nadie se da cuenta.

Un programa que debe funcionar siempre tiene que ser un servicio systemd. Así:

  • se inicia solo al arrancar el sistema;
  • systemd lo vuelve a iniciar si se bloquea;
  • su salida va al journal (lección 6.2);
  • se ejecuta con el usuario que usted elija, con los permisos que usted permita.

Un archivo de unit propio

Supongamos que tiene una pequeña aplicación Node.js en /opt/facturacion, que escucha en 127.0.0.1:3000. Más adelante, nginx o Caddy la publicarán hacia fuera (módulo 7).

Paso 1: un usuario propio sin shell (lección 3.2). La aplicación no necesita ser root ni iniciar sesión:

anna@web1:~$ sudo adduser --system --group --home /opt/facturacion --no-create-home facturacion
anna@web1:~$ sudo chown -R facturacion:facturacion /opt/facturacion/data

El código en sí puede seguir perteneciendo a root (la aplicación no necesita modificarse a sí misma); solo la carpeta en la que escribe pertenece al usuario del servicio.

Paso 2: el archivo de unit. Las units propias se colocan en /etc/systemd/system/:

# /etc/systemd/system/facturacion.service
[Unit]
Description=Facturacion (Node.js)
After=network-online.target
Wants=network-online.target

[Service]
User=facturacion
Group=facturacion
WorkingDirectory=/opt/facturacion
EnvironmentFile=/etc/facturacion/env
ExecStart=/usr/bin/node /opt/facturacion/server.js
Restart=on-failure
RestartSec=5s

NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/opt/facturacion/data

[Install]
WantedBy=multi-user.target

Los tres bloques:

  • [Unit]: descripción y orden. After=network-online.target junto con Wants= hace que el servicio no se inicie hasta que la red esté disponible.
  • [Service]: cómo se ejecuta el programa. ExecStart con la ruta completa (systemd no usa una ruta de búsqueda como su shell). User= y Group= determinan con qué usuario. EnvironmentFile lee ajustes como una contraseña de base de datos desde un archivo aparte, para que no estén en la unit.
  • [Install]: lo que hace enable. WantedBy=multi-user.target significa: iniciar junto con un arranque normal.

Paso 3: los secretos aparte, con permisos estrictos.

anna@web1:~$ sudo mkdir /etc/facturacion
anna@web1:~$ sudo install -m 600 -o root -g root /dev/null /etc/facturacion/env
anna@web1:~$ sudoedit /etc/facturacion/env

Contenido, por ejemplo, DATABASE_URL=postgres://facturas:...@127.0.0.1/facturas. systemd lee el archivo como root antes de cambiar al usuario del servicio, así que 600 de root es suficiente.

Paso 4: cargar, iniciar y comprobar.

anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now facturacion
anna@web1:~$ systemctl status facturacion
anna@web1:~$ journalctl -u facturacion -f

Opciones de seguridad: poco esfuerzo, gran diferencia

Las cuatro líneas bajo RestartSec en el ejemplo limitan lo que puede hacer el servicio, también si alguien encuentra una vulnerabilidad en su aplicación:

OpciónEfecto
NoNewPrivileges=trueel proceso y sus hijos nunca pueden obtener más permisos (tampoco mediante sudo o programas setuid)
ProtectSystem=stricttodo el sistema de archivos es de solo lectura para el servicio, salvo lo que usted permita con ReadWritePaths=
ProtectHome=true/home, /root y /run/user son invisibles
PrivateTmp=trueun /tmp propio y vacío que otros programas no ven

systemd puede evaluar su unit:

anna@web1:~$ systemd-analyze security facturacion
...
→ Overall exposure level for facturacion.service: 4.9 OK 🙂

Cuanto más bajo sea el número, mejor. Un servicio sin opciones obtiene alrededor de 9 ("UNSAFE"). No hace falta llegar a cero: cada opción que añade puede romper algo que la aplicación necesita. Añádalas una por una y pruebe después de cada paso. Si algo deja de funcionar, normalmente aparece en el journal ("Read-only file system", es decir, sistema de archivos de solo lectura, o "Permission denied", permiso denegado).

Planificar tareas: temporizadores

Para algo que debe ocurrir a horas fijas (una copia de seguridad, un script de limpieza, un informe) necesita un temporizador (timer). Un temporizador systemd consta de dos units con el mismo nombre: un .service que indica qué debe hacerse y un .timer que indica cuándo.

# /etc/systemd/system/limpieza.service
[Unit]
Description=Limpiar archivos de exportación antiguos

[Service]
Type=oneshot
User=facturacion
ExecStart=/usr/bin/find /opt/facturacion/data/export -type f -mtime +30 -delete
# /etc/systemd/system/limpieza.timer
[Unit]
Description=Limpiar a diario los archivos de exportación antiguos

[Timer]
OnCalendar=*-*-* 03:15:00
RandomizedDelaySec=10m
Persistent=true

[Install]
WantedBy=timers.target

Type=oneshot significa: el programa se ejecuta y después termina. OnCalendar es la programación: todos los días a las 03:15. También puede escribir daily, weekly o Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" muestra cuándo será la próxima vez. Persistent=true es importante: si el servidor estaba apagado a las 03:15, la tarea se ejecuta igualmente nada más arrancar. RandomizedDelaySec reparte un poco el momento de inicio.

Se activa el temporizador, no el servicio:

anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now limpieza.timer
anna@web1:~$ systemctl list-timers limpieza
NEXT                        LEFT     LAST PASSED UNIT           ACTIVATES
Tue 2026-11-10 03:19:42 CET 15h left -    -      limpieza.timer limpieza.service
anna@web1:~$ sudo systemctl start limpieza.service    # probar ahora una vez manualmente
anna@web1:~$ journalctl -u limpieza.service

¿Y cron?

cron es la herramienta más antigua y sencilla, y sigue funcionando perfectamente. Una línea en el crontab de un usuario (crontab -e):

15 3 * * * /usr/local/bin/limpieza.sh

Los cinco campos son minuto, hora, día del mes, mes y día de la semana. Ventajas e inconvenientes, uno junto a otro:

crontemporizador systemd
Configuraciónuna líneados archivos
Ejecución perdida (servidor apagado)se omitecon Persistent=true se recupera
Salida y errorespor correo, si el servidor puede enviar correo; si no, se pierdenen el journal
Opciones de seguridad, usuarioa través del propio scripttodo lo de systemd (véase más arriba)
Ver cuándo se ejecutódifícilsystemctl list-timers y el journal

Para un servidor que usted administra en serio, los temporizadores son la mejor opción, sobre todo para las copias de seguridad (lección 8.2): usted quiere tener la certeza de que se ejecutaron y de lo que dijeron. Una línea de cron que falla en silencio solo se descubre cuando necesita la copia de seguridad.

En AlmaLinux y Rocky Linux

Las units y los temporizadores funcionan exactamente igual. Una diferencia: SELinux puede bloquear un servicio propio que lee o escribe archivos en un lugar que SELinux no espera, o que escucha en un puerto poco habitual. El aviso aparece en /var/log/audit/audit.log. No desactive SELinux para solucionarlo; busque la etiqueta o la regla correcta (por ejemplo, con semanage).

Resumen

  • Un programa que debe funcionar siempre tiene que ser un servicio systemd: se inicia solo, se reinicia tras un bloqueo y sus registros van al journal.
  • Las units propias van en /etc/systemd/system/, con User= un usuario propio sin shell y los secretos en un EnvironmentFile con permisos 600.
  • NoNewPrivileges, ProtectSystem=strict con ReadWritePaths, ProtectHome y PrivateTmp limitan los daños en caso de vulnerabilidad; systemd-analyze security evalúa la unit.
  • Un temporizador es un .service más un .timer con OnCalendar; Persistent=true recupera las ejecuciones perdidas. Active el temporizador, no el servicio.
  • cron sigue funcionando, pero los temporizadores ofrecen mejores registros y no pierden ejecuciones.

Cuestionario

1. Su aplicación se ejecuta como servicio con User=root. ¿Por qué es mejor un usuario propio?



2. Ha creado un .service y un .timer. ¿Qué activa con enable --now?



3. ¿Qué hace Persistent=true en un temporizador?



4. Añade ProtectSystem=strict y después su aplicación muestra "Read-only file system" al guardar archivos subidos. ¿Cuál es la solución correcta?



5. ¿Dónde guarda la contraseña de base de datos de su propio servicio?



Ejercicio

Ejercicio O6.3: Un servicio propio con temporizador. Cree en su servidor un pequeño servicio propio con temporizador, por ejemplo un script que cada noche escriba el espacio libre en disco y systemctl --failed en un archivo o en el journal. Use un usuario propio, Type=oneshot, al menos dos opciones de seguridad y Persistent=true. Pruébelo con systemctl start, revise la salida en el journal y anote la puntuación de systemd-analyze security. Pegue su .service y su .timer y responda a las preguntas de la lista de comprobación.

Ejercicio O6.3: Un servicio propio con temporizador

Este ejercicio lo hace usted mismo; nadie lo revisa. Marque lo que haya hecho y señale el ejercicio como realizado.




Sus marcas y notas se quedan solo en este navegador; no las enviamos a ningún sitio. Si ha iniciado sesión, en Mis cursos solo guardamos que ha realizado el ejercicio.

Para saber más

Un momento…

Configure sus dominios

Configure para cada dominio los servidores de nombres, la vinculación a su hosting y quién será el titular.

Cargando sus dominios…