| Title: Making a home NAS using NixOS | |
| Author: Solène | |
| Date: 18 October 2020 | |
| Tags: nixos linux nas | |
| Description: | |
| Still playing with [NixOS](https://nixos.org/), I wanted to experience | |
| how difficult it would be to write a NixOS configuration file to | |
| turn a computer into a simple NAS with basics features: samba | |
| storage, dlna server and auto suspend/resume. | |
| What is [NixOS](https://nixos.org/features.html)? As a reminder for | |
| some and introduction to the others, NixOS is a Linux distribution | |
| built by the Nix package manager, which make it very different than | |
| any other operating system out there, except | |
| [Guix](https://guix.gnu.org/) | |
| which has a similar approach with their own package manager written | |
| in Scheme. | |
| NixOS uses a declarative configuration approach along with lot of | |
| others features derived from Nix. What's big here is you no longer | |
| tweak anything in `/etc` or install packages, you can define the | |
| working state of the system in one configuration file. This system | |
| is a totally different beast than the others OS and require some | |
| time to understand how it work. Good news though, **everything** | |
| is documented in the man page `configuration.nix`, from fstab | |
| configuration to users managements or how to enable samba! | |
| Here is the `/etc/nixos/configuration.nix` file on my NAS. | |
| It enables ssh server, samba, minidlna and vnstat. Set up a user | |
| with my ssh public key. Ready to work. | |
| Using `rtcwake` command (Linux specific), it's possible to put | |
| the system into standby mode and schedule an auto resume after | |
| some time. This is triggered by a cron job at 01h00. | |
| { config, pkgs, ... }: | |
| { | |
| # include stuff related to hardware, auto generated at install | |
| imports = [ ./hardware-configuration.nix ]; | |
| boot.loader.grub.device = "/dev/sda"; | |
| networking.interfaces.enp3s0.ipv4.addresses = [ { | |
| address = "192.168.42.150"; | |
| prefixLength = 24; | |
| } ]; | |
| networking.defaultGateway = "192.168.42.1"; | |
| networking.nameservers = [ "192.168.42.231" ]; | |
| i18n.defaultLocale = "fr_FR.UTF-8"; | |
| console = { font = "Lat2-Terminus16"; keyMap = "fr"; }; | |
| time.timeZone = "Europe/Paris"; | |
| environment.systemPackages = with pkgs; [ | |
| kakoune vnstat borgbackup utillinux | |
| ]; | |
| networking.firewall.enable = false; | |
| services.openssh.enable = true; | |
| services.vnstat.enable = true; | |
| services.cron.systemCronJobs = [ | |
| "0 1 * * * root rtcwake -m mem --date +6h" | |
| ]; | |
| services.samba.enable = true; | |
| services.samba.enableNmbd = true; | |
| services.samba.extraConfig = '' | |
| workgroup = WORKGROUP | |
| server string = Samba Server | |
| server role = standalone server | |
| log file = /var/log/samba/smbd.%m | |
| max log size = 50 | |
| dns proxy = no | |
| map to guest = Bad User | |
| ''; | |
| services.samba.shares = { | |
| public = { | |
| path = "/home/public"; | |
| browseable = "yes"; | |
| "writable" = "yes"; | |
| "guest ok" = "yes"; | |
| "public" = "yes"; | |
| "force user" = "share"; | |
| }; | |
| }; | |
| services.minidlna.enable = true; | |
| services.minidlna.announceInterval = 60; | |
| services.minidlna.friendlyName = "Rorqual"; | |
| services.minidlna.mediaDirs = ["A,/home/public/Musique/" | |
| "V,/home/public/Videos/"]; | |
| # note that tmpfiles are not necesserarly temporary if you don't | |
| # set an expire time. Trick given on irc by someone I forgot the | |
| name.. | |
| systemd.tmpfiles.rules = [ "d /home/public 0755 share users" ]; | |
| users.users.solene = { | |
| isNormalUser = true; | |
| extraGroups = [ "wheel" "sudo" ]; | |
| openssh.authorizedKeys.keys = [ | |
| "ssh-ed25519 | |
| AAAAC3NzaC1lZDI1NTE5AAAAIOIZKLFQXVM15viQXHYRjGqE4LLfvETMkjjgSz0mzMzS | |
| personal" | |
| "ssh-ed25519 | |
| AAAAC3NzaC1lZDI1NTE5AAAAIOIZKLFQXVM15vAQXBYRjGqE6L1fvETMkjjgSz0mxMzS | |
| pro" | |
| ]; | |
| }; | |
| # I prefer a dedicated one than "nobody" | |
| # can't log into it | |
| users.users.share= { | |
| isNormalUser = false; | |
| }; | |
| } | |