simple nixos config for vps static site

simple nixos config for vps static site

Setting up a little static site is something I’ve done a few different times on a few different operating systems. It’s a slightly fiddly task with a few disparate jobs that all need looking after: ssh, let’s encrypt, nginx. In my opinion, it is one of the moments where consolidating all the little bits and bobs you need to setup into one common configuration is very useful.

I’m going to go through a bit of the nixos config I’ve got for my vps.


Having a way to to get into your server is useful. Managing ssh on nix is very simple; this enables the ssh daemon, tells it what port to run on, disables plain text passwords, and disables root login.

services.openssh = {
  enable = true;
  ports = [ 69 ];
  settings = {
    passwordAuthentication = false;
    permitRootLogin = "no";


Generally, it’s nice to have a user so you’re not just rawdogging everything as root. This adds a user called ronald, sets their default shell, and adds them to some useful groups. You can even add your public ssh keys here for ultimate convenience.

users.users = {
  ronald = {
    isNormalUser = true;
    shell =;
    extraGroups = [ "wheel" "nginx" ];
	openssh.authorizedKeys.keyFiles = [ "/path/to/public/key/file" ]


I use nginx to serve my sites. Compared to the nginx config I used to mess around with, the equivalent nix config is very clean. This chunk tells nginx to serve the contents of /var/www/example-site at It also opens the ports for http and https in the firewall.

services.nginx = {
 enable = true;
 virtualHosts."" = {
   enableACME = true;
   forceSSL = true;
   root = "/var/www/example-site/";
networking.firewall.allowedTCPPorts = [ 80 443 ];


You can also make nix deal with all the let’s encrypt certbot stuff. It looks like this:

security.acme = {
  acceptTerms = true; = "ronald@email.yes";

This will set up certificates for any sites you set the enableAMCE to true option for.


This is one final little tidbit I set up the other day. I had got bored of having to ssh into my server to manually copy my updated site to the website root. The problem was I would need root privileges on the server to rsync the files to the website root. This seemed like a whole minefield I didn’t want to mess with. Instead I set up a little cron job which copies a directory from my home to the website root every hour.

services.cron = {
  enable = true;
  systemCronJobs = [
    "@hourly      root    cp -r /home/ronald/example-site /var/www/"

This means I can just rsync the updated site from my laptop to the server and it’ll be updated within the hour. Good enough for me.