GhostAcademy
GhostAcademy
Systemd — Guía Completa de Administración
Guía Completa
Systemd
El Sistema de Init y Gestión de Servicios

Systemd es el sistema de init estándar en la gran mayoría de distribuciones Linux modernas: Debian, Ubuntu, Fedora, Arch, RHEL, CentOS, openSUSE. Reemplaza a SysVinit y Upstart, y va mucho más allá de arrancar servicios: gestiona el proceso de boot, los logs del sistema, los timers, los sockets, los dispositivos y los namespaces de procesos.

ℹ PID 1 — el proceso raízSystemd es siempre el proceso con PID 1 — el primero que arranca el kernel y el padre de todos los demás procesos. Si systemd muere, el sistema entra en pánico. Todo lo que ocurre en el sistema Linux pasa por él.

¿Qué gestiona systemd?

ComponenteFunciónHerramienta
ServiciosArrancar, parar y supervisar daemons (nginx, sshd, mysql...)systemctl
LogsRecopilar y almacenar los logs del kernel y de todos los serviciosjournalctl
TimersEjecutar tareas programadas — alternativa moderna a cronsystemctl + archivos .timer
SocketsActivar servicios bajo demanda cuando llega una conexiónArchivos .socket
MontajesGestionar puntos de montaje (alternativa a /etc/fstab)Archivos .mount
TargetsAgrupar unidades — equivalente a los runlevels de SysVinitArchivos .target
DispositivosGestionar eventos de hardware (udev integration)Archivos .device

Systemd vs SysVinit

AspectoSysVinitSystemd
Arranque de serviciosSecuencial — un servicio a la vezParalelo — todos los que pueden a la vez
Tiempo de bootLentoRápido gracias a la paralelización
Scripts de inicioScripts bash en /etc/init.d/Archivos de unidad declarativos .service
LogsArchivos de texto en /var/log/Journal binario estructurado con metadatos
DependenciasOrden numérico (S01, S02...)Declaradas explícitamente (After=, Requires=)
Reinicio automáticoNo nativo — requiere supervisordNativo con Restart= en el service file
Fundamentos — 01
📦 Tipos de Unidades

Todo lo que gestiona systemd se expresa como una "unidad" (unit). Cada unidad es un archivo de texto con extensión que indica su tipo. Conocer los tipos principales es el primer paso para trabajar con systemd.

ExtensiónTipoPara qué sirveEjemplo
.serviceServicioGestionar un daemon o proceso en segundo planonginx.service, sshd.service
.timerTimerEjecutar tareas en momentos específicos — alternativa a cronbackup.timer, logrotate.timer
.socketSocketActivar un servicio cuando llega una conexión por socketsshd.socket, cups.socket
.targetTargetAgrupar unidades — equivalente a runlevelsmulti-user.target, graphical.target
.mountMontajeGestionar puntos de montaje de sistemas de archivoshome.mount, tmp.mount
.pathPathVigilar un archivo o directorio y activar una unidad al cambiarcups.path
.sliceSliceAgrupar procesos para gestionar recursos con cgroupssystem.slice, user.slice
.deviceDispositivoRepresentar dispositivos de hardware detectados por udevdev-sda1.device

Ubicaciones de los archivos de unidad

BASH — Dónde busca systemd los archivos de unidad
# Prioridad de mayor a menor (la primera encontrada gana)
/etc/systemd/system/         ← unidades del administrador (mayor prioridad)
/run/systemd/system/         ← unidades creadas en tiempo de ejecución
/usr/local/lib/systemd/system/ ← paquetes instalados manualmente
/usr/lib/systemd/system/     ← unidades de paquetes del sistema (menor prioridad)

# Ver todas las unidades disponibles y su ubicación
systemctl show nginx.service -p FragmentPath
FragmentPath=/usr/lib/systemd/system/nginx.service

# Listar todos los archivos de unidad disponibles
systemctl list-unit-files
systemctl list-unit-files --type=service

# Ver la ruta exacta de una unidad
systemctl cat nginx.service   # muestra el contenido del archivo
Fundamentos — 02
🔧 systemctl — Control de Servicios

systemctl es la herramienta principal para interactuar con systemd. Permite arrancar, parar, reiniciar, habilitar y consultar el estado de cualquier unidad. Es el comando que más usarás como administrador Linux.

systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2024-01-15 14:32:01 UTC; 2h 15min ago
Process: 1234 ExecStartPre=/usr/bin/nginx -t (code=exited, status=0/SUCCESS)
Main PID: 1235 (nginx)
Tasks: 3 (limit: 4915)
Memory: 6.2M
CPU: 42ms
CGroup: /system.slice/nginx.service
├─1235 "nginx: master process /usr/sbin/nginx"
└─1236 "nginx: worker process"
Jan 15 14:32:01 servidor nginx[1234]: nginx: configuration file /etc/nginx/nginx.conf test is OK
BASH — systemctl: comandos esenciales
## CONTROL DE SERVICIOS
systemctl start nginx        # arrancar ahora (no persiste tras reinicio)
systemctl stop nginx         # parar el servicio
systemctl restart nginx      # parar y arrancar
systemctl reload nginx       # recargar config sin parar (si el servicio lo soporta)
systemctl reload-or-restart nginx  # reload si puede, restart si no

## HABILITAR / DESHABILITAR (persistencia entre reinicios)
systemctl enable nginx       # arrancar automáticamente al iniciar el sistema
systemctl disable nginx      # no arrancar automáticamente
systemctl enable --now nginx # habilitar Y arrancar ahora (lo más común)
systemctl disable --now nginx# deshabilitar Y parar ahora
systemctl mask nginx         # impedir completamente que arranque (ni manual)
systemctl unmask nginx       # revertir el mask

## CONSULTAR ESTADO
systemctl status nginx       # estado detallado con últimas líneas de log
systemctl is-active nginx    # active / inactive (ideal para scripts)
systemctl is-enabled nginx   # enabled / disabled
systemctl is-failed nginx    # true si el servicio falló

## LISTAR UNIDADES
systemctl list-units                    # unidades activas
systemctl list-units --all              # todas (activas e inactivas)
systemctl list-units --type=service     # solo servicios
systemctl list-units --state=failed     # solo los que fallaron
systemctl list-unit-files               # todos los archivos de unidad instalados

## RECARGAR CONFIGURACIÓN tras crear o editar un unit file
systemctl daemon-reload      # releer todos los archivos de unidad desde disco

## APAGAR Y REINICIAR EL SISTEMA
systemctl poweroff           # apagar
systemctl reboot             # reiniciar
systemctl suspend            # suspender
systemctl hibernate          # hibernar
Servicios — 01
📄 Archivos .service

Un archivo .service es la descripción declarativa de cómo systemd debe gestionar un proceso: qué ejecutar, con qué usuario, cuándo arrancar, qué hacer si falla. Es la pieza central del trabajo con systemd.

Estructura de un archivo .service

mi-app.serviceservice
# Sección [Unit] — metadatos y dependencias
[Unit]
Description=Mi Aplicación Web
Documentation=https://mi-app.com/docs
After=network.target postgresql.service
Requires=postgresql.service

# Sección [Service] — cómo ejecutar el proceso
[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/opt/mi-app
EnvironmentFile=/etc/mi-app/env
ExecStartPre=/opt/mi-app/bin/check-config
ExecStart=/opt/mi-app/bin/servidor --port 8080
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStartSec=30
StandardOutput=journal
StandardError=journal

# Sección [Install] — en qué target se activa
[Install]
WantedBy=multi-user.target

Opciones clave de [Service]

OpciónValores / EjemploQué hace
Type=simple, forking, oneshot, notify, idleDefine cómo systemd sabe que el servicio arrancó. simple: el ExecStart es el proceso principal. forking: el proceso hace fork y el padre sale (daemons tradicionales). oneshot: se ejecuta y termina. notify: el proceso avisa a systemd cuando está listo.
ExecStart=/usr/bin/nginx -g "daemon off;"Comando a ejecutar para arrancar el servicio. Ruta absoluta obligatoria.
ExecStartPre=/usr/bin/nginx -tComando a ejecutar antes de ExecStart. Si falla, el servicio no arranca.
ExecStop=/bin/kill -TERM $MAINPIDComando para parar el servicio. Si no se especifica, systemd envía SIGTERM.
Restart=no, on-failure, on-abnormal, alwaysCuándo reiniciar el servicio si se para. on-failure: si sale con código != 0 o por señal. always: siempre, incluso si se para limpiamente.
RestartSec=5s, 30Tiempo de espera antes de reiniciar.
User= / Group=www-data, nobodyUsuario y grupo con los que se ejecuta el proceso. Si no se especifica, corre como root.
WorkingDirectory=/opt/mi-appDirectorio de trabajo del proceso.
Environment=NODE_ENV=production PORT=3000Variables de entorno inline.
EnvironmentFile=/etc/mi-app/envCargar variables de entorno desde un archivo (formato KEY=VALUE).
TimeoutStartSec=30, infinityTiempo máximo para que el servicio arranque antes de que systemd lo declare fallido.
Servicios — 02
✏️ Crear un Servicio Propio

Laboratorio completo: crear un archivo .service desde cero, habilitarlo y diagnosticar su funcionamiento. Este es el flujo que usarás en la vida real para desplegar aplicaciones propias como servicios.

1
Crear el usuario del servicio (principio de mínimo privilegio)
Los servicios no deben correr como root. Crear un usuario del sistema sin shell de login ni directorio home.
BASH — Preparar el entorno
# Crear usuario del sistema para el servicio
sudo useradd --system --no-create-home --shell /usr/sbin/nologin webapp

# Crear directorios necesarios
sudo mkdir -p /opt/mi-app /var/log/mi-app /etc/mi-app
sudo chown webapp:webapp /opt/mi-app /var/log/mi-app

# Crear un script de ejemplo (la aplicación)
sudo tee /opt/mi-app/servidor.sh << 'EOF'
#!/bin/bash
echo "Servidor arrancando en puerto ${PORT:-8080}"
while true; do
    echo "$(date): Servidor ejecutándose" >> /var/log/mi-app/app.log
    sleep 10
done
EOF
sudo chmod +x /opt/mi-app/servidor.sh
sudo chown webapp:webapp /opt/mi-app/servidor.sh
2
Crear el archivo de variables de entorno
Las variables de entorno sensibles van en un archivo separado, no en el unit file (que es legible por todos).
BASH — Archivo de entorno
# Crear el archivo de variables de entorno
sudo tee /etc/mi-app/env << 'EOF'
PORT=8080
NODE_ENV=production
DATABASE_URL=postgresql://localhost/miapp
EOF
sudo chmod 640 /etc/mi-app/env
sudo chown root:webapp /etc/mi-app/env  # solo webapp puede leerlo
3
Crear el archivo .service en /etc/systemd/system/
Los servicios propios siempre van en /etc/systemd/system/ — nunca en /usr/lib/systemd/system/ que es para paquetes del sistema.
BASH — Crear el unit file
sudo tee /etc/systemd/system/mi-app.service << 'EOF'
[Unit]
Description=Mi Aplicación Web
Documentation=https://mi-app.com/docs
After=network.target
Wants=network.target

[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/opt/mi-app
EnvironmentFile=/etc/mi-app/env
ExecStart=/opt/mi-app/servidor.sh
Restart=on-failure
RestartSec=5s
TimeoutStartSec=30
TimeoutStopSec=20
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mi-app

# Seguridad básica
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/var/log/mi-app

[Install]
WantedBy=multi-user.target
EOF
4
Cargar, habilitar y arrancar el servicio
Después de crear o modificar cualquier archivo .service, systemd debe recargar su configuración antes de que los cambios tengan efecto.
BASH — Activar el servicio
# Releer los archivos de unidad desde disco (SIEMPRE tras crear o editar)
sudo systemctl daemon-reload

# Habilitar y arrancar en un solo comando
sudo systemctl enable --now mi-app.service

# Verificar que está corriendo
systemctl status mi-app.service
● mi-app.service - Mi Aplicación Web
     Loaded: loaded (/etc/systemd/system/mi-app.service; enabled)
     Active: active (running) since Mon 2024-01-15 14:32:01 UTC; 3s ago
   Main PID: 5678 (servidor.sh)
     CGroup: /system.slice/mi-app.service
             └─5678 /bin/bash /opt/mi-app/servidor.sh

# Ver los logs en tiempo real
journalctl -u mi-app.service -f
Servicios — 03
🎯 Targets y Niveles de Arranque

Los targets son el equivalente a los runlevels de SysVinit. Definen el estado del sistema — qué servicios están activos. El target activo determina si el sistema arranca en modo texto, con entorno gráfico, en modo de rescate, etc.

Equivalencia con runlevels SysVinit

Runlevel SysVTarget systemdDescripción
0poweroff.targetApagar el sistema
1rescue.targetModo de rescate — usuario único, sin red
2, 3, 4multi-user.targetSistema multiusuario sin entorno gráfico — el estándar en servidores
5graphical.targetSistema multiusuario con entorno gráfico (escritorio)
6reboot.targetReiniciar el sistema
BASH — Gestionar targets
# Ver el target activo por defecto (el que arranca el sistema)
systemctl get-default
multi-user.target

# Cambiar el target por defecto (p. ej. para añadir entorno gráfico)
sudo systemctl set-default graphical.target

# Cambiar al target de rescate SIN reiniciar (sesión actual)
sudo systemctl isolate rescue.target

# Ver qué servicios están habilitados en un target
systemctl list-dependencies multi-user.target

# Ver las dependencias de un servicio
systemctl list-dependencies nginx.service

# Arrancar en modo emergencia (mínimo absoluto — solo root)
sudo systemctl isolate emergency.target
Servicios — 04
🔗 Dependencias y Orden de Arranque

Systemd gestiona las dependencias entre unidades de forma explícita y declarativa. Entender las diferencias entre Requires, Wants, After y Before es fundamental para escribir unit files correctos.

DirectivaSecciónComportamiento
Requires=[Unit]Dependencia fuerte — si la unidad requerida falla o se para, esta también se para
Wants=[Unit]Dependencia débil — intenta arrancar la otra unidad, pero si falla esta sigue funcionando
After=[Unit]Orden — esta unidad arranca DESPUÉS de la especificada (no implica dependencia)
Before=[Unit]Orden — esta unidad arranca ANTES de la especificada
Conflicts=[Unit]Conflicto — si esta arranca, la especificada se para, y viceversa
BindsTo=[Unit]Como Requires pero más fuerte — si la otra unidad se para, esta también se para inmediatamente
PartOf=[Unit]Si la unidad padre se para o reinicia, esta también lo hace (pero no al revés)
💡 After vs RequiresAfter= solo define el orden — no activa la dependencia. Requires= define la dependencia pero no el orden. Para decir "necesito que B esté activo Y debo arrancar después de B", necesitas AMBOS: Requires=B y After=B. En la práctica casi siempre se usan juntos.
Unit file — Ejemplos de dependencias
# Servicio web que necesita base de datos
[Unit]
Description=Aplicación Web
After=network.target postgresql.service redis.service
Requires=postgresql.service    # si postgres falla, esta app también
Wants=redis.service             # intenta redis, pero funciona sin él

# Verificar dependencias en tiempo real
systemctl list-dependencies mi-app.service --all
systemd-analyze critical-chain mi-app.service  # cadena crítica de arranque
Logs — 01
📋 journald y journalctl

journald es el sistema de logging de systemd. Captura la salida estándar de todos los servicios, los logs del kernel y los mensajes del sistema en un journal binario estructurado. journalctl es la herramienta para consultarlo.

BASH — journalctl: consultar logs
## LOGS DE UN SERVICIO ESPECÍFICO
journalctl -u nginx.service              # todos los logs de nginx
journalctl -u nginx.service -f           # seguir en tiempo real (como tail -f)
journalctl -u nginx.service -n 50        # últimas 50 líneas
journalctl -u nginx.service --no-pager   # sin paginador (útil para scripts)

## FILTRAR POR TIEMPO
journalctl -u nginx --since "2024-01-15 14:00"
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since today
journalctl -u nginx --since "2024-01-15" --until "2024-01-16"

## FILTRAR POR PRIORIDAD (nivel de severidad)
journalctl -p err               # solo errores (err, crit, alert, emerg)
journalctl -p warning           # warnings y superior
journalctl -u nginx -p err -f   # errores de nginx en tiempo real

# Niveles disponibles: debug, info, notice, warning, err, crit, alert, emerg

## BOOT ACTUAL Y ANTERIORES
journalctl -b                   # logs del boot actual
journalctl -b -1                # boot anterior
journalctl --list-boots          # lista de todos los boots guardados

## LOGS DEL KERNEL
journalctl -k                   # kernel messages (como dmesg)
journalctl -k -b -1             # kernel del boot anterior

## SALIDA EN DISTINTOS FORMATOS
journalctl -u nginx -o json              # JSON estructurado
journalctl -u nginx -o json-pretty       # JSON formateado
journalctl -u nginx -o short-precise     # timestamp con microsegundos
journalctl -u nginx -o cat               # solo el mensaje, sin metadatos

## GESTIÓN DEL ESPACIO EN DISCO
journalctl --disk-usage          # ver espacio usado por el journal
journalctl --vacuum-size=500M    # reducir a máximo 500 MB
journalctl --vacuum-time=30d     # eliminar logs de más de 30 días

Configurar journald

/etc/systemd/journald.conf — Configuración
# /etc/systemd/journald.conf
[Journal]
Storage=persistent          # guardar en /var/log/journal (persiste entre boots)
Compress=yes               # comprimir entradas antiguas
SystemMaxUse=2G            # máximo 2GB en disco
SystemKeepFree=1G         # mantener al menos 1GB libre
MaxRetentionSec=30day     # retener logs máximo 30 días
MaxFileSec=1week          # rotar archivos semanalmente
ForwardToSyslog=no        # no reenviar a syslog clásico
RateLimitIntervalSec=30s
RateLimitBurst=10000      # max 10000 mensajes cada 30s por servicio

# Aplicar cambios
sudo systemctl restart systemd-journald
Logs — 02
🐛 Diagnóstico de Fallos

Cuando un servicio falla, systemd y journald proporcionan toda la información necesaria para diagnosticar el problema. Este es el flujo de investigación estándar.

BASH — Flujo de diagnóstico de un servicio que falla
## PASO 1: ver servicios fallidos
systemctl list-units --state=failed
  UNIT            LOAD   ACTIVE SUB    DESCRIPTION
● mi-app.service loaded failed failed Mi Aplicación Web

## PASO 2: status detallado del servicio
systemctl status mi-app.service
● mi-app.service - Mi Aplicación Web
     Active: failed (Result: exit-code) since Mon 2024-01-15 14:35:22 UTC
    Process: 5678 ExecStart=/opt/mi-app/servidor.sh (code=exited, status=1/FAILURE)
   Main PID: 5678 (code=exited, status=1/FAILURE)

Jan 15 14:35:22 servidor servidor.sh[5678]: Error: no se puede leer /etc/mi-app/env

## PASO 3: logs completos del servicio
journalctl -u mi-app.service -n 100 --no-pager
journalctl -u mi-app.service -b -p err  # solo errores del boot actual

## PASO 4: herramientas de análisis
systemd-analyze                         # tiempo total de arranque
Startup finished in 1.234s (kernel) + 3.456s (userspace) = 4.690s

systemd-analyze blame                   # servicios ordenados por tiempo de arranque
3.234s postgresql.service
1.123s NetworkManager.service
0.456s mi-app.service

systemd-analyze critical-chain          # cadena crítica del boot
systemd-analyze verify mi-app.service   # validar el unit file sin arrancarlo

## PASO 5: ver el unit file activo (con overrides aplicados)
systemctl cat mi-app.service

## PASO 6: ver las propiedades del servicio
systemctl show mi-app.service
systemctl show mi-app.service -p Restart,RestartSec,ExecStart

## REINTENTAR tras corregir el problema
sudo systemctl reset-failed mi-app.service  # limpiar el estado de fallo
sudo systemctl start mi-app.service
Avanzado — 01
⏱ Timers — Alternativa a cron

Los timers de systemd son la alternativa moderna a crontab. Ofrecen más control, logging integrado en journald, la posibilidad de capturar el estado de la última ejecución y activación al arranque si se perdió una ejecución.

💡 Timers vs CronLos timers de systemd tienen logging automático en journald (puedes ver cuándo se ejecutó y si falló con journalctl), soportan OnBootSec para ejecutar X tiempo después del arranque, y permiten ver la próxima ejecución con systemctl list-timers. La desventaja: requieren dos archivos en lugar de una línea de crontab.

Crear un timer: backup diario

backup.serviceservice
[Unit]
Description=Backup diario de base de datos
After=postgresql.service

[Service]
Type=oneshot
User=postgres
ExecStart=/usr/bin/pg_dump mibd | gzip > /backup/mibd-$(date +%%Y%%m%%d).sql.gz
StandardOutput=journal
backup.timertimer
[Unit]
Description=Ejecutar backup diariamente a las 02:00

[Timer]
OnCalendar=*-*-* 02:00:00 # todos los días a las 2AM
Persistent=true # ejecutar si se perdió la última vez
RandomizedDelaySec=10min # añadir hasta 10min de delay aleatorio

[Install]
WantedBy=timers.target
BASH — Gestionar timers
# Activar el timer (no el .service directamente)
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

# Ver todos los timers activos y cuándo se ejecutarán
systemctl list-timers
NEXT                        LEFT      UNIT          ACTIVATES
Mon 2024-01-16 02:03:42 UTC 11h left  backup.timer  backup.service

# Ver logs de las últimas ejecuciones
journalctl -u backup.service

## SINTAXIS OnCalendar — ejemplos
OnCalendar=daily              → cada día a las 00:00
OnCalendar=weekly             → cada lunes a las 00:00
OnCalendar=monthly            → primer día de mes a las 00:00
OnCalendar=hourly             → cada hora
OnCalendar=*:0/15             → cada 15 minutos
OnCalendar=Mon..Fri 09:00     → lunes a viernes a las 9AM
OnCalendar=*-*-* 02:00:00     → todos los días a las 2AM
OnCalendar=Sat *-*-* 03:30:00 → cada sábado a las 3:30AM

## TIMERS RELATIVOS AL ARRANQUE
OnBootSec=5min        → 5 minutos después del boot
OnActiveSec=1h        → 1 hora después de que el timer se activó
OnUnitActiveSec=1day  → 1 día después de la última activación

# Verificar sintaxis de la expresión
systemd-analyze calendar "Mon..Fri 09:00"
  Original form: Mon..Fri 09:00
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2024-01-15 09:00:00 UTC
Avanzado — 02
🔌 Socket Activation

La activación por socket permite arrancar un servicio solo cuando llega la primera conexión, en lugar de tenerlo corriendo siempre. Systemd gestiona el socket, y cuando llega una conexión, arranca el servicio y le pasa el socket. Reduce el consumo de recursos y acelera el boot.

mi-api.socketsocket
[Unit]
Description=Socket para Mi API

[Socket]
ListenStream=8080 # escuchar en el puerto 8080
Accept=no # pasar el socket al servicio (no por conexión)

[Install]
WantedBy=sockets.target
BASH — Activar socket activation
# Habilitar el socket (no el servicio — systemd lo arranca al primer acceso)
sudo systemctl enable --now mi-api.socket

# Ver sockets activos
systemctl list-sockets

# Usos comunes de socket activation
SSH: sshd.socket → sshd.service (activa sshd al primer intento de conexión)
DBus: dbus.socket → dbus.service
Printing: cups.socket → cups.service
Docker: docker.socket → docker.service
Avanzado — 03
🔒 Sandboxing y Seguridad

Systemd incluye un sistema de sandboxing muy potente para aislar servicios y limitar su acceso al sistema. Añadir estas directivas a cualquier service file reduce drásticamente el impacto de un compromiso.

Unit file — Directivas de seguridad y sandboxing
[Service]
# --- DIRECTIVAS ESENCIALES (bajo coste, alto impacto) ---
NoNewPrivileges=yes          # el proceso no puede ganar más privilegios (setuid, etc.)
PrivateTmp=yes               # /tmp privado — no compartido con otros servicios
ProtectSystem=strict        # /usr, /boot y /etc son read-only
ProtectHome=yes              # /home, /root y /run/user son inaccesibles

# --- CONTROL DE SISTEMA DE ARCHIVOS ---
ReadWritePaths=/var/lib/mi-app /var/log/mi-app  # solo estos directorios son escribibles
ReadOnlyPaths=/etc/mi-app   # acceso de solo lectura a la configuración
InaccessiblePaths=/root /home # completamente inaccesibles
PrivateDevices=yes           # solo /dev/null, /dev/zero, /dev/random (sin acceso a hardware)

# --- NAMESPACES Y AISLAMIENTO ---
ProtectKernelTunables=yes   # no puede modificar parámetros del kernel (/proc/sys, /sys)
ProtectKernelModules=yes    # no puede cargar módulos del kernel
ProtectControlGroups=yes    # no puede modificar cgroups
RestrictNamespaces=yes      # no puede crear namespaces
LockPersonality=yes         # no puede cambiar la personalidad del proceso (ABI)

# --- LLAMADAS AL SISTEMA ---
SystemCallFilter=@system-service  # permitir solo syscalls típicas de servicios
SystemCallErrorNumber=EPERM       # devolver EPERM en vez de SIGSYS si intenta syscall no permitida

# --- RED ---
PrivateNetwork=yes           # sin acceso a red (para servicios que no necesitan red)
RestrictAddressFamilies=AF_INET AF_INET6  # solo IPv4 e IPv6
BASH — Auditar la seguridad de un servicio
# Ver la puntuación de seguridad de un servicio
systemd-analyze security nginx.service
  NAME                                                        DESCRIPTION                              EXPOSURE
✗ PrivateNetwork=                                             Service has access to the host network    0.5
✗ PrivateTmp=                                                 Service has access to other units' /tmp   0.1
✓ NoNewPrivileges=                                            Service cannot gain new privileges
...
→ Overall exposure level for nginx.service: 7.2 MEDIUM

# Puntuación 0 = máxima seguridad, 10 = sin restricciones
# Objetivo recomendado: por debajo de 4 (OK) o 2 (bueno)
Avanzado — 04
🗂 Drop-in Overrides

Los overrides permiten personalizar un unit file de un paquete del sistema sin editarlo directamente. Al actualizar el paquete, el unit file original se sobreescribe pero el override se mantiene. Es la forma correcta de modificar servicios del sistema.

BASH — Crear y gestionar overrides
# Forma 1 — systemctl edit (abre el editor automáticamente)
sudo systemctl edit nginx.service
# Crea /etc/systemd/system/nginx.service.d/override.conf
# Solo hay que añadir las directivas que quieres cambiar

# Ejemplo de override: añadir límites de memoria y reinicio más agresivo
sudo tee /etc/systemd/system/nginx.service.d/override.conf << 'EOF'
[Service]
Restart=always
RestartSec=3s
MemoryMax=512M
CPUQuota=50%
Environment=EXTRA_VAR=valor
EOF

# Forma 2 — systemctl edit --full (edita una copia completa del unit file)
sudo systemctl edit --full nginx.service
# CUIDADO: este se sobreescribe al actualizar el paquete — usar solo si necesitas cambios mayores

# Aplicar los cambios
sudo systemctl daemon-reload
sudo systemctl restart nginx

# Ver el unit file final con los overrides aplicados
systemctl cat nginx.service
# /usr/lib/systemd/system/nginx.service  ← archivo original
[Unit]
...
# /etc/systemd/system/nginx.service.d/override.conf  ← override
[Service]
Restart=always

# Eliminar un override
sudo systemctl revert nginx.service
# O borrar el directorio manualmente
sudo rm -rf /etc/systemd/system/nginx.service.d/
sudo systemctl daemon-reload
Referencia
✅ Cheatsheet y Referencia Rápida

Los comandos más usados en el trabajo diario con systemd.

systemctl — Referencia rápida

  • Arrancar: systemctl start nombre.service
  • Parar: systemctl stop nombre.service
  • Reiniciar: systemctl restart nombre.service
  • Recargar config: systemctl reload nombre.service
  • Habilitar y arrancar: systemctl enable --now nombre.service
  • Estado: systemctl status nombre.service
  • Recargar unit files: systemctl daemon-reload
  • Servicios fallidos: systemctl list-units --state=failed

journalctl — Referencia rápida

  • Logs de un servicio: journalctl -u nombre.service
  • Seguir en tiempo real: journalctl -u nombre.service -f
  • Solo errores: journalctl -u nombre.service -p err
  • Boot actual: journalctl -b
  • Desde hace 1 hora: journalctl -u nombre --since "1 hour ago"
  • Espacio en disco: journalctl --disk-usage
  • Limpiar logs: journalctl --vacuum-time=30d

Comandos de diagnóstico

BASH — Cheatsheet de diagnóstico systemd
## ANÁLISIS DE ARRANQUE
systemd-analyze                          # tiempo total de boot
systemd-analyze blame                    # servicios más lentos
systemd-analyze critical-chain           # cadena crítica
systemd-analyze security nombre.service  # puntuación de seguridad
systemd-analyze verify nombre.service    # validar sintaxis del unit file

## INSPECCIONAR UNIDADES
systemctl cat nombre.service             # ver el contenido del unit file
systemctl show nombre.service            # todas las propiedades
systemctl show nombre.service -p Restart # propiedad específica
systemctl list-dependencies nombre       # árbol de dependencias

## TIMERS
systemctl list-timers                    # ver todos los timers y próxima ejecución
systemd-analyze calendar "daily"         # verificar expresión de calendario

## OVERRIDES
systemctl edit nombre.service            # crear/editar override
systemctl revert nombre.service          # eliminar override

## TARGETS
systemctl get-default                    # target de arranque
systemctl set-default multi-user.target  # cambiar target de arranque
systemctl isolate rescue.target          # cambiar target ahora

Flujo estándar para crear un nuevo servicio

  • Crear usuario del sistema sin shell: useradd --system --no-create-home --shell /usr/sbin/nologin nombre
  • Crear el archivo .service en /etc/systemd/system/
  • Validar la sintaxis: systemd-analyze verify nombre.service
  • Recargar la configuración: systemctl daemon-reload
  • Habilitar y arrancar: systemctl enable --now nombre.service
  • Verificar estado: systemctl status nombre.service
  • Ver logs: journalctl -u nombre.service -f
  • Auditar seguridad: systemd-analyze security nombre.service