The most common question about configuring an immutable OS is: "If the root is read-only, how do I change things?" The answer on Shani OS is: exactly the same way you would on any Linux distribution.
The /etc directory is writable via an OverlayFS mount. Your changes are stored in /data/overlay/etc/upper/ — separate from the OS image — and layered on top of the read-only OS defaults at boot. When the OS updates, your customisations in the overlay are untouched. When you rollback, same story. Your configuration is always yours.
Full reference: docs.shani.dev — System Configuration and docs.shani.dev — Overlay Filesystem.
---
Editing Configuration Files
Nothing special is required. Edit files in /etc exactly as you would on any Linux system:
# Edit SSH configuration
sudo nano /etc/ssh/sshd_config
# Edit hostname
sudo nano /etc/hostname
# Edit hosts file
sudo nano /etc/hosts
# Edit fstab (careful — errors here prevent boot)
sudo nano /etc/fstab
# Edit locale
sudo nano /etc/locale.conf
# Edit environment variables
sudo nano /etc/environment
Changes take effect immediately (or after service restart for daemon config). They survive every OS update and rollback.
---
Understanding the /etc Overlay
The OverlayFS mechanism is worth understanding because it explains some subtle behaviours:
Lower layer (read-only): /etc from the active @blue or @green slot
Upper layer (writable): /data/overlay/etc/upper/
Merged view: /etc (what you see and interact with)
When you read /etc/ssh/sshd_config, the kernel checks the upper layer first. If your modified version is there, you see it. If not, you see the OS default from the lower layer.
When you write to /etc/ssh/sshd_config, the kernel performs a "copy-up": it copies the file from the lower layer to the upper layer, then applies your changes. From then on, your version is in the upper layer.
When the OS updates (new lower layer), your upper-layer files are untouched. You see your modified version. Files you have never touched automatically reflect the new OS defaults from the new lower layer.
Inspecting Your Customisations
# See everything you have changed from OS defaults
find /data/overlay/etc/upper/ -type f | sort
# Compare a modified file to the OS default
diff /data/overlay/etc/upper/ssh/sshd_config \
/etc/ssh/sshd_config
# List just the filenames
ls -la /data/overlay/etc/upper/
Reverting a Specific File to OS Default
# Remove the upper-layer version — the OS default becomes active again
sudo rm /data/overlay/etc/upper/ssh/sshd_config
# For a directory
sudo rm -rf /data/overlay/etc/upper/some/directory/
Resetting All /etc Customisations
Do not use raw rm -rf to wipe the overlay — this leaves the work directory in an inconsistent state and does not reset the other persistent state directories (/data/varlib, /data/varspool) that services depend on. Use shani-reset instead:
# Factory reset all persistent system state in /data
# (keeps /home and OS slots intact, reboots automatically)
sudo shani-reset
# Preview what would be wiped without making changes
sudo shani-reset --dry-run
# Keep previously downloaded OS images to avoid re-downloading
sudo shani-reset --keep-downloads
shani-reset wipes the /etc overlay upper layer, the /var overlay, all service state in /data/varlib and /data/varspool, and all boot markers — then reboots. User accounts are part of the /etc overlay and will be gone after reset; the desktop setup wizard runs on next login to create a new account. Your files in /home are untouched unless you pass --home.
---
systemd Services
systemctl works exactly as you would expect on any Linux distribution. Service state (enabled/disabled) persists via the overlay.
# Enable and start a service
sudo systemctl enable --now sshd
sudo systemctl enable --now nginx
# Disable a service
sudo systemctl disable sshd
# Start/stop/restart
sudo systemctl start sshd
sudo systemctl stop sshd
sudo systemctl restart sshd
# Reload config without restart (for services that support it)
sudo systemctl reload nginx
# Check status
systemctl status sshd
# View logs for a service
journalctl -u sshd -f
journalctl -u sshd --since today
# List all enabled services
systemctl list-unit-files --state=enabled
# List all failed services
systemctl --failed
Service enablement (systemctl enable) creates symlinks in /etc/systemd/system/. These go into the overlay upper layer and persist across OS updates.
User Services
Per-user services run in your user session and do not require root:
# Enable a user service
systemctl --user enable --now my-service.service
# Check user service status
systemctl --user status my-service.service
# View user service logs
journalctl --user -u my-service.service -f
# List enabled user services
systemctl --user list-unit-files --state=enabled
User service unit files can be placed in ~/.config/systemd/user/.
---
Creating Custom Service Units
Place custom .service files in /etc/systemd/system/ (they go into the overlay):
# Create a custom service
sudo nano /etc/systemd/system/myapp.service
Example unit for a simple application:
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=username
WorkingDirectory=/home/username/myapp
ExecStart=/home/username/myapp/start.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
# Reload systemd to see the new unit
sudo systemctl daemon-reload
# Enable and start
sudo systemctl enable --now myapp.service
---
Network Configuration
NetworkManager handles all network configuration. Your Wi-Fi passwords, VPN profiles, and static IP configurations are stored in /data/varlib/NetworkManager (bind-mounted to /var/lib/NetworkManager) — they persist across all updates and rollbacks.
# List connections
nmcli connection show
# Add a Wi-Fi connection
nmcli device wifi connect "SSID" password "password"
# Add a static IP connection
nmcli connection add type ethernet con-name "static-eth" \
ipv4.method manual ipv4.addresses "192.168.1.100/24" \
ipv4.gateway "192.168.1.1" ipv4.dns "8.8.8.8"
# Modify a connection
nmcli connection modify "My Connection" ipv4.dns "1.1.1.1,8.8.8.8"
# Delete a connection
nmcli connection delete "My Connection"
# Check current network status
nmcli device status
---
Kernel Parameters (sysctl)
sysctl settings are configured via files in /etc/sysctl.d/. Changes go into the overlay and persist:
# Check a current value
sysctl vm.swappiness
# Apply a setting immediately (lost on reboot unless also in file)
sudo sysctl -w vm.swappiness=10
# Make it permanent
echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-custom.conf
sudo sysctl --system # apply all sysctl.d files immediately
Common customisations:
# In /etc/sysctl.d/99-custom.conf
# Lower swappiness (use swap less aggressively)
vm.swappiness=10
# Increase inotify watches (for IDEs, webpack, etc.)
fs.inotify.max_user_watches=524288
# Increase open file limit
fs.file-max=2097152
# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6=1
---
Hostname and DNS
# Set hostname
sudo hostnamectl set-hostname myhostname
# View full status
hostnamectl status
# Check /etc/hosts
cat /etc/hosts
# Edit as needed
sudo nano /etc/hosts
Hostname changes persist via the overlay. Your machine is reachable as hostname.local on the local network via Avahi (mDNS), which is active by default.
---
Environment Variables
System-wide environment variables are set in /etc/environment:
sudo nano /etc/environment
# Example contents
EDITOR=vim
VISUAL=vim
JAVA_HOME=/home/user/.nix-profile/lib/jvm/java-21
For shell-specific variables (Zsh, Bash), use ~/.zshrc or ~/.profile — these are in your home directory and are always writable.
---
Reviewing All Changes Before an Update
Before applying an OS update, you can see exactly what configuration changes you have made relative to the OS defaults:
# All customised /etc files
find /data/overlay/etc/upper/ -type f -printf "%P\n" | sort
# What systemd services you have enabled
systemctl list-unit-files --state=enabled | grep -v "systemd\|dbus\|getty"
# What's in your user systemd directory
ls ~/.config/systemd/user/
This is useful for auditing your configuration before a major update and for documenting what you would need to reconfigure if you ever reinstalled from scratch.
---
Resources
- Shani OS Troubleshooting Guide — when things go wrong
- Updates on Shani OS — update and rollback reference
- Shani OS FAQ — common questions answered
- docs.shani.dev — System Configuration — full reference
- docs.shani.dev — Overlay Filesystem — OverlayFS technical details
- The Architecture Behind Shani OS — how /etc stays writable
- Networking on Shani OS — full networking configuration
- Telegram community
---
Built in India 🇮🇳 · Immutable · Atomic · Zero Telemetry