systemd: guía práctica para crear y asegurar servicios en Linux en 2026
systemd gestiona el arranque y los servicios de la mayoría de distribuciones Linux. Esta guía cubre desde el primer unit file hasta el endurecimiento de seguridad y las consultas avanzadas al journal. Probada en Debian 12/13, Ubuntu 24.04 LTS y RHEL 9/10.
—
TL;DR — Lo que vas a tener al final
Tiempo de setup: 30 minutos a 2 horas dependiendo de la complejidad del entorno.
Requisitos: Acceso root, Linux moderno, conexión a internet para descargar dependencias.
Resultado: Servicio funcional y estable, documentado paso a paso.
Troubleshooting: Logs estándar en /var/log/, comandos de verificación al final de cada sección.
1. Qué es systemd y por qué seguir usándolo
systemd es el sistema de inicio (PID 1) y gestor de servicios presente en Debian, Ubuntu, Fedora, RHEL, Arch, openSUSE y prácticamente toda distribución moderna. La rama estable actual es v261 (publicada en 2025; mantenimiento estable en v261.x en 2026).
No es solo un sustituto de SysVinit: aporta registro centralizado (journald), dependencias declarativas, activación por socket, por temporizador y por D-Bus, y un modelo de unidades (units) extensible.
Tipos de unit que vas a tocar:
Sufijo
Para qué sirve
.service
Servicios de usuario o demonios
.timer
Equivalente a cron, gestionado por systemd
.mount
Puntos de montaje
.socket
Activación por socket (inetd-style)
.path
Activación por cambios en el filesystem
.target
Agrupación de units (runlevel moderno)
—
2. Anatomía de un unit file
Un unit se compone de secciones ([Unit], [Service], [Install]) y directivas clave=valor. Ejemplo mínimo viable para una API Node:
# /etc/systemd/system/mi-api.service
[Unit]
Description=Mi API en Node
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=apiuser
WorkingDirectory=/opt/mi-api
ExecStart=/usr/bin/node /opt/mi-api/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Pasos para activarlo:
El orden de los cuatro comandos no es accidental: daemon-reload registra la unidad en systemd (sin esto, los cambios en el archivo no se ven hasta el próximo reinicio), enable crea el symlink en /etc/systemd/system/multi-user.target.wants/ para que el servicio arranque en boot, start lo lanza ahora, y status confirma el estado. Correrlos en otro orden suele terminar en errores tipo Unit not found o servicios que no quedan persistentes tras un reboot.
sudo systemctl daemon-reload # relee la unidad tras editar
sudo systemctl enable mi-api.service # habilita en el arranque
sudo systemctl start mi-api.service # arranca ahora
sudo systemctl status mi-api.service # comprueba estado
Si status muestra inactive (dead) justo después de start, el binario de ExecStart falló al arrancar (permisos, ruta inexistente o Type mal elegido). Saltá al journal con journalctl -u mi-api.service -n 50 --no-pager para ver el error exacto. Si enable se queja de symlink already exists, el servicio ya estaba habilitado de un intento previo y puedes saltearte ese paso.
Type=simple es el valor por defecto: systemd considera que el proceso está vivo en cuanto se lanza. Para procesos que se bifurcan (fork), usa Type=forking; para scripts que escriben el PID en un archivo, Type=oneshot con RemainAfterExit=yes.
—
3. Las directivas [Service] que usarás a diario
Directiva
Efecto práctico
ExecStart=
Comando principal. Obligatoria en services.
ExecReload=
Comando para recargar configuración (SIGHUP-friendly).
4. Logs con journalctl: la herramienta que sustituye a tail
El binario journald captura stdout/stderr y mensajes syslog de todos los servicios. Para consultarlo:
Estos seis flags cubren el 90% de las consultas al journal: -u filtra por unidad (clave cuando tienes varios servicios), -f sigue en vivo (reemplazo directo de tail -f), --since permite ventanas temporales con strings humanos, -p err descarta ruido informativo, -b arranca desde el último boot, y --list-boots te deja saltar a arranques anteriores para investigar fallos que ya no están en memoria.
journalctl -u mi-api.service # solo este servicio
journalctl -u mi-api.service -f # en vivo, como tail -f
journalctl -u mi-api.service --since "1 hour ago"
journalctl -u mi-api.service -p err # solo errores y críticos
journalctl -b # desde el último arranque
journalctl --list-boots # ver todos los arranques
journalctl --since "2026-08-01" --until "2026-08-03"
Si -u mi-api.service devuelve No entries, el servicio probablemente nunca arrancó: verifica con systemctl status mi-api.service y revisa que el nombre de la unidad coincida exactamente (incluyendo sufijo .service). Si --since "1 hour ago" no encuentra nada pero sabes que hay logs, el reloj del sistema puede estar desincronizado — timedatectl te lo confirma. Si el log se corta a mitad de línea, agregá --no-pager o pipeá a less.
Trucos útiles:
-o json o -o json-pretty para parsear logs con jq.
_PID=1234 para filtrar por PID.
journalctl -u a.service -u b.service sigue varios servicios a la vez.
Por defecto, los logs no sobreviven a un reinicio. Para hacerlos persistentes:
Crear /var/log/journal antes de reiniciar systemd-journald es clave: sin ese directorio, el journal no tiene dónde escribir logs persistentes y los datos de boot se siguen perdiendo. restart re-lee la config y empieza a volcar al disco, pero los logs anteriores a este punto no se recuperan.
Si mkdir falla por permisos, no estás en una shell con sudo; corré sudo -i primero para tener un shell limpio con PATH correcto. Si después de reiniciar el journal los logs siguen sin persistir tras un reboot, revisa que /var/log/journal no esté en una partición que se monte con noexec o nosuid — eso puede romper el journal. verifica con ls -ld /var/log/journal que systemd-journald sea dueño del directorio (uid/gid root:root con permisos 2755).
Atención: en sistemas con journal persistente, los logs pueden crecer sin control. Limita su tamaño con SystemMaxUse= en /etc/systemd/journald.conf.
—
5. Timers: cron moderno y observabilidad gratis
Los .timer sustituyen a cron y se benefician del journal. Ejemplo: backup diario a las 03:30.
# /etc/systemd/system/backup.timer
[Unit]
Description=Backup diario a las 03:30
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
Unit=backup.service
[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service
[Unit]
Description=Backup a S3
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Activación del timer: daemon-reload registra el .timer en systemd (sin esto, los archivos nuevos no existen para el sistema), enable --now crea el symlink en timers.target.wants/ y arranca el timer en el mismo paso (atajo para no tener que correr enable y start por separado), y list-timers --all te muestra cuándo va a disparar la próxima vez — clave para confirmar que el OnCalendar= quedó bien parseado.
Si enable --now falla con Failed to enable unit: Unit backup.timer is masked, hay otro .timer con el mismo nombre activo o uno quedó mask-eado por una sesión previa: corré sudo systemctl unmask backup.timer antes. Si list-timers --all no muestra tu timer tras activarlo, te falta el daemon-reload (systemd cachea las unidades hasta que recargás). Si OnCalendar=--* 03:30:00 no dispara a la hora esperada, revisa la zona horaria con timedatectl — systemd usa localtime del sistema.
Persistent=true ejecuta la unidad perdida si el equipo estuvo apagado a la hora programada. Equivale a anacron y funciona en servidores que no están siempre encendidos.
—
6. Drop-ins: modificar units sin tocar el archivo original
Los drop-ins permiten sobreescribir o añadir directivas en archivos gestionados por paquetes. El sistema busca *.conf en /etc/systemd/system/.d/ y /usr/lib/systemd/system/.d/.
Caso típico: añadir variables de entorno a un servicio del sistema:
systemctl edit abre el editor por defecto ($EDITOR o vi/nano) con un esqueleto vacío bajo # systemctl edit nginx.service y guarda el drop-in en /etc/systemd/system/nginx.service.d/override.conf. Cualquier directiva que pongas ahí se mergea con el unit original sin tocarlo, así que las actualizaciones de paquetes no pisan tus cambios.
sudo systemctl edit nginx.service
Si edit no abre el editor, no tienes EDITOR ni VISUAL definido: exportá EDITOR=vim (o nano) antes de invocar. Si al guardar se queja de Failed to prepare temporary file, el directorio /etc/systemd/system/.d/ no tiene permisos para tu usuario — usa sudoedit en su lugar o creá el directorio a mano con sudo mkdir -p y sudo chmod 755. Si tus directivas no parecen aplicarse, recuerda que necesitas daemon-reload después de editar.
Esto abre un editor con un esqueleto y guarda el drop-in en /etc/systemd/system/nginx.service.d/override.conf. Para sobreescribir directivas que estaban antes (no añadir), usa:
[Service]
Environment="HTTPS=on"
Y luego sudo systemctl daemon-reload && sudo systemctl restart nginx.service.
Para revertir un edit, simplemente sudo systemctl revert nginx.service.
—
7. Errores frecuentes y cómo depurarlos
Síntoma
Causa probable
systemctl status muestra inactive (dead)
El servicio ejecutó y salió. Revisa ExecStart.
failed with result 'exit-code'
Script mal llamado, error en el binario.
failed with result 'signal'
El proceso murió por SIGSEGV/SIGKILL.
203/EXEC
Archivo ExecStart no es ejecutable o no existe.
status=n/a repetido
Type=simple pero el proceso hace fork. Usa forking.
address already in use
El puerto está ocupado. Comprueba con ss -tlnp.
Depuración rápida:
Este trío es el flujo mínimo de diagnóstico cuando un service no arranca: restart fuerza un intento limpio desde el estado actual (sin recargar unit files), journalctl -n 50 muestra las últimas 50 líneas sin paginar (clave para copiar el error y buscarlo), y systemctl show -p filtra las propiedades efectivas del unit — útil para confirmar qué directivas se aplicaron tras un drop-in.
Si restart falla con Job for mi-api.service failed because the control process exited, hay un error de sintaxis en el .service o el binario de ExecStart no es ejecutable — corré systemd-analyze verify /etc/systemd/system/mi-api.service para que apunte exactamente a la línea problemática. Si journalctl no muestra nada, el servicio puede tener StandardOutput=null o SyslogIdentifier mal seteado: revisa con systemctl cat. Si show -p ExecStart devuelve vacío, te falta el daemon-reload después de la última edición.
—
8. Hardening de units en 2026
systemd tiene directivas de seguridad que aplican seccomp, cgroups, namespaces y capabilities sin necesidad de AppArmor o SELinux. Para servicios caseros y SaaS pequeños, esto es generalmente suficiente.
[Service]
# Limita el sistema de archivos
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
ProtectHostname=true
ProtectClock=true
ProtectProc=invisible
# Limita la red
PrivateNetwork=false # true si el servicio no necesita red
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# Capabilities mínimas
CapabilityBoundingSet=
AmbientCapabilities=
NoNewPrivileges=true
# Aislamiento de proceso
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
# Recursos
LimitNOFILE=65536
CPUQuota=75%
MemoryMax=512M
systemd-analyze ayuda a verificar y analizar:
systemd-analyze security aplica un puntaje heurístico a las directivas del unit: cada Protect, Restrict, Private* y CapabilityBoundingSet= suman o restan puntos según el riesgo que cubren. El output agrupa los checks en categorías (Namespace, Capabilities, Network, Filesystem, etc.) y lista qué directivas faltan para subir el puntaje.
Si security devuelve OVERALL EXPOSURE LEVEL: 9.5 UNSAFE, no entres en pánico: muchas directivas de hardening no aplican a tu caso (ej: PrivateNetwork=true rompe servicios que escuchan en puerto). Lo importante es leer cada sugerencia y evaluar si tiene sentido para tu service, no perseguir un número bajo. Si verify reporta Unknown lvalue 'ProtectFoo' o similar, tienes una versión vieja de systemd que no soporta la directiva — revisa con systemctl --version y subí el paquete si puedes.
El puntaje de systemd-analyze security no es un benchmark inmutable: las recomendaciones se ajustan con cada versión. Lo importante es usar las directivas correctas y no acumular servicios con RootDirectory=/ sin aislar.
Notas prácticas:
Si tu servicio necesita escribir logs, monta un %t o /var/log con ReadWritePaths=/var/log/mi-api.
NoNewPrivileges=true rompe setuid/setgid binarios. Solo quítalo si tu servicio lo requiere.
MemoryDenyWriteExecute=true puede romper binarios que usan JIT (Java, Node con V8 moderno). Pruébalo antes de dejarlo fijo.
systemd sigue siendo el sistema de inicio estándar de Linux en 2026. Cubre desde el caso más simple (ExecStart=/bin/true) hasta un servicio endurecido con seccomp, cgroups y namespaces. Para el día a día, acostúmbrate a tres comandos: systemctl status, journalctl -u y systemd-analyze security. El primero te dice qué pasó, el segundo te da contexto, el tercero te dice qué te falta por asegurar.
—
Preguntas frecuentes
¿Por qué systemd: guía práctica para crear y asegurar servicios en Linux en 2026 es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con systemd: guía práctica para crear?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con systemd: guía práctica para crear?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar systemd: guía práctica para crear y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a systemd: guía práctica para crear?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Soy Alfonso, sysadmin senior con RHCE y más de 10 años administrando sistemas Linux para empresas y proyectos personales. Me especializo en infraestructura, redes, virtualización, monitoring, automation y self-hosting.
Sobre SoyLinux.com
SoyLinux.com es un blog técnico en español sobre Linux, software libre y self-hosting. Lo mantengo en mi tiempo libre.
Áreas de expertise
- Linux server administration: RHEL, CentOS, Rocky, Alma, Fedora, Debian, Ubuntu
- Network services: Postfix, BIND, Samba, NFS, Squid
- Virtualización y containers: KVM, Proxmox, Docker, Podman
- Monitoring: Prometheus, Grafana, Zabbix
- Automation: Ansible, Bash scripting
- Self-hosting: Vaultwarden, Nextcloud, Jellyfin, Immich, Homelab
Contacto
- Email: [email protected]
One thought on “systemd: guía práctica para crear y asegurar servicios en Linux en 2026”
Usamos cookies propias para que el sitio funcione y cookies de terceros (Google AdSense, Google Analytics) para medir el uso y mostrar anuncios personalizados.
Puedes aceptar todas las cookies o solo las estrictamente necesarias.
Más información en nuestra Política de Privacidad.
Estrictamente necesariasSesión, seguridad, preferencias. No se pueden desactivar.
Analítica (Google Analytics)Métricas anónimas de uso para mejorar el sitio.
Publicidad (Google AdSense)Anuncios personalizados. Sin esto, verás anuncios genéricos.
Pingback: Cómo crear un servidor de Minecraft en Linux: guía completa 2026 - Soy Linux