-
Notifications
You must be signed in to change notification settings - Fork 0
Services
System and user services configuration in NullOS.
NullOS configures services at two levels:
- System services - NixOS configuration (require sudo)
- User services - Home Manager (run as user)
Configured in modules/services/ directory.
Pipewire (modules/services/audio.nix):
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
jack.enable = true;
wireplumber.enable = true;
};
hardware.pulseaudio.enable = false;Features:
- Low-latency audio
- ALSA compatibility
- PulseAudio replacement
- JACK support
- Bluetooth audio
Control:
# Volume control
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
# List devices
wpctl statusSDDM (modules/services/sddm.nix):
services.displayManager.sddm = {
enable = true;
wayland.enable = true;
theme = "sugar-candy";
package = pkgs.kdePackages.sddm;
};Auto-login:
services.displayManager.autoLogin = {
enable = vars.autoLogin;
user = vars.username;
};XDG Desktop Portal (modules/services/xdg-portal.nix):
xdg.portal = {
enable = true;
extraPortals = with pkgs; [
xdg-desktop-portal-gtk
xdg-desktop-portal-hyprland
];
config.common.default = "*";
};Provides:
- Screen sharing
- File picker
- Notifications
- Screenshot portal
NetworkManager:
networking.networkmanager.enable = true;
users.users.${vars.username}.extraGroups = [ "networkmanager" ];Control:
# CLI
nmcli device wifi list
nmcli device wifi connect SSID password PASSWORD
# GUI
nm-applet # System trayBlueZ:
hardware.bluetooth = {
enable = true;
powerOnBoot = true;
settings = {
General = {
Enable = "Source,Sink,Media,Socket";
Experimental = true;
};
};
};
services.blueman.enable = true;Control:
# CLI
bluetoothctl
> scan on
> pair XX:XX:XX:XX:XX:XX
> connect XX:XX:XX:XX:XX:XX
# GUI
blueman-managerCUPS:
services.printing = {
enable = true;
drivers = with pkgs; [
gutenprint
hplip
splix
];
};
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
};Manage:
# Web interface
http://localhost:631/
# CLI
lpstat -p -d
lpr -P printer-name file.pdfDocker (modules/services/virtualisation.nix):
virtualisation.docker = {
enable = true;
enableOnBoot = true;
daemon.settings = {
data-root = "/var/lib/docker";
};
};
users.users.${vars.username}.extraGroups = [ "docker" ];Libvirt (optional):
virtualisation.libvirtd = {
enable = true;
qemu = {
package = pkgs.qemu_kvm;
ovmf.enable = true;
swtpm.enable = true;
};
};
users.users.${vars.username}.extraGroups = [ "libvirtd" ];services.openssh = {
enable = true;
settings = {
PermitRootLogin = "no";
PasswordAuthentication = false;
};
ports = [ 22 ];
};Firewall:
networking.firewall.allowedTCPPorts = [ 22 ];plocate:
services.locate = {
enable = true;
package = pkgs.plocate;
localuser = null;
};Usage:
# Update database
sudo updatedb
# Search
locate filenameservices.flatpak.enable = true;
xdg.portal.enable = true;Usage:
# Add Flathub
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# Install
flatpak install flathub org.gimp.GIMP
# Run
flatpak run org.gimp.GIMPsystem.autoUpgrade = {
enable = false; # Manual recommended
flake = "/home/${vars.username}/NullOS";
dates = "weekly";
allowReboot = false;
};nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
nix.optimise = {
automatic = true;
dates = [ "weekly" ];
};Configured via Home Manager in home/ directory.
Wallpaper Service:
systemd.user.services.hyprpaper = {
Unit = {
Description = "Hyprland wallpaper daemon";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
};
Service = {
ExecStart = "${pkgs.hyprpaper}/bin/hyprpaper";
Restart = "on-failure";
};
Install = {
WantedBy = [ "hyprland-session.target" ];
};
};Notification Daemon (home/swaync.nix):
services.swaync = {
enable = true;
settings = {
positionX = "right";
positionY = "top";
control-center-width = 380;
notification-visibility = {
telegram = {
state = "muted";
};
};
};
};On-Screen Display (home/swayosd.nix):
services.swayosd = {
enable = true;
topMargin = 0.9;
};Shows OSD for:
- Volume changes
- Brightness changes
- Caps Lock
services.syncthing = {
enable = true;
user = vars.username;
dataDir = "/home/${vars.username}/.syncthing";
configDir = "/home/${vars.username}/.config/syncthing";
overrideDevices = true;
overrideFolders = true;
settings = {
devices = {
"device1" = { id = "DEVICE-ID-HERE"; };
};
folders = {
"Documents" = {
path = "/home/${vars.username}/Documents";
devices = [ "device1" ];
};
};
};
};Backup services are typically configured at the system level using Restic.
See Backup for complete configuration.
Music Player Daemon:
services.mpd = {
enable = true;
musicDirectory = "/home/${vars.username}/Music";
extraConfig = ''
audio_output {
type "pipewire"
name "PipeWire"
}
'';
};
services.mpdris2.enable = true; # MPRIS supportText Expander:
services.espanso = {
enable = true;
configs = {
default = {
toggle_key = "CTRL";
};
};
matches = {
base = {
matches = [
{
trigger = ":shrug";
replace = "¯\\_(ツ)_/¯";
}
];
};
};
};Check status:
sudo systemctl status service-nameStart/Stop:
sudo systemctl start service-name
sudo systemctl stop service-name
sudo systemctl restart service-nameEnable/Disable:
sudo systemctl enable service-name
sudo systemctl disable service-nameView logs:
sudo journalctl -u service-name
sudo journalctl -u service-name -f # FollowCheck status:
systemctl --user status service-nameStart/Stop:
systemctl --user start service-name
systemctl --user stop service-name
systemctl --user restart service-nameEnable/Disable:
systemctl --user enable service-name
systemctl --user disable service-nameView logs:
journalctl --user -u service-name
journalctl --user -u service-name -fAll system services:
systemctl list-units --type=serviceAll user services:
systemctl --user list-units --type=serviceFailed services:
systemctl list-units --failed
systemctl --user list-units --failedCreate modules/services/my-service.nix:
{ config, pkgs, vars, ... }:
{
systemd.services.my-service = {
description = "My Custom Service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.my-package}/bin/my-command";
Restart = "on-failure";
RestartSec = "5s";
User = vars.username;
Group = "users";
# Security
PrivateTmp = true;
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
};
};
}Import in configuration.nix or modules/services/default.nix.
In home/my-service.nix:
{ config, pkgs, ... }:
{
systemd.user.services.my-service = {
Unit = {
Description = "My User Service";
After = [ "graphical-session.target" ];
};
Service = {
ExecStart = "${pkgs.my-package}/bin/my-command";
Restart = "on-failure";
RestartSec = "5s";
};
Install = {
WantedBy = [ "default.target" ];
};
};
}System timer:
systemd.timers.my-timer = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
OnBootSec = "5m";
Persistent = true;
};
};
systemd.services.my-timer = {
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.bash}/bin/bash -c 'echo hello'";
};
};User timer:
systemd.user.timers.my-timer = {
Unit = {
Description = "My Timer";
};
Timer = {
OnCalendar = "hourly";
Persistent = true;
};
Install = {
WantedBy = [ "timers.target" ];
};
};systemd.services.my-service = {
after = [ "network.target" "other-service.service" ];
before = [ "another-service.service" ];
requires = [ "required-service.service" ];
wants = [ "optional-service.service" ];
};Difference:
-
requires- Hard dependency (fails if missing) -
wants- Soft dependency (continues if missing) -
after- Start after other service -
before- Start before other service
serviceConfig = {
# Process
User = "specific-user";
Group = "specific-group";
NoNewPrivileges = true;
# Filesystem
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [ "/var/lib/myservice" ];
# Network
PrivateNetwork = false;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
# Capabilities
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
# System calls
SystemCallFilter = "@system-service";
SystemCallErrorNumber = "EPERM";
};systemd-analyze security service-namesystemd.services.my-service = {
environment = {
MY_VAR = "value";
PATH = "${pkgs.package}/bin";
};
# Or from file
environmentFile = "/run/secrets/service-env";
};systemd.user.services.my-service = {
Service = {
Environment = "MY_VAR=value";
EnvironmentFile = "/home/user/.env";
};
};# Check status
systemctl status service-name
# View full logs
journalctl -u service-name -n 100
# Check for errors
journalctl -p err -u service-name# Check restart count
systemctl show service-name -p NRestarts
# Increase verbosity
journalctl -u service-name -f --output=verbose# Check which user runs service
systemctl show service-name -p User
# Check file permissions
ls -l /path/to/file
# Test command manually
sudo -u username /path/to/command- Use Security Options - Restrict what services can access
- Set Restart Policies - Handle crashes gracefully
- Log Appropriately - Use structured logging
- Resource Limits - Prevent resource exhaustion
- User Services When Possible - Don't run as root unnecessarily
- Specialisations - Alternative boot configurations
- System Applications - System packages
- Troubleshooting - Debugging issues
- Backup - Backup service configuration