1
0
Fork 0
mirror of https://github.com/archtechx/nix.git synced 2025-12-12 03:24:02 +00:00
A collection of scripts and config files, mainly for deploying Laravel on NixOS https://stancl.substack.com/p/deploying-laravel-on-nixos
Find a file
2025-07-24 01:17:19 +02:00
anywhere Initial commit 2025-07-23 01:59:06 +02:00
postinstall Initial commit 2025-07-23 01:59:06 +02:00
laravel.nix Firewall settings (open 80 and 443), sudo rule for checking queue status, simplify ssh keygen 2025-07-24 01:17:19 +02:00
README.md Multi-domain support 2025-07-23 16:14:11 +02:00

Nix scripts

A collection of scripts and configuration files for our use of Nix tooling.

Setting up a new server

This is just for getting a working NixOS installation with /etc/nixos/configuration.nix deployed onto a generic cloud VM.

The setup also uses /etc/nixos/flake.nix since that's an easy way of addressing the nixos-anywhere NIX_PATH issue and you likely want to use flakes anyway.

Note: All of the automated scripts for the steps below assume you're logging in as root. If that's not the case, just follow the steps manually. The scripts will also create lockfiles in anywhere/ and postinstall/ to make future deployments consistent and faster (by reusing more things from your nix store). Feel free to delete those if you want a completely fresh install each time.

This section is overall just a thin wrapper around nixos-anywhere.

Installing NixOS

  • Provision a new server. This config works on Hetzner Cloud, may require adjustments for other providers, see anywhere/flake.nix
    • The default config uses aarch64, you can change this to x86_64
  • Preferably use passwordless auth with just your SSH key

Cross-compilation is sometimes buggy so it's recommended to run this on Linux (use a NixOS VM if you're on macOS), preferably matching the server's ISA. On macOS I highly recommend creating a NixOS VM (helpful for development anyway) in Parallels with no desktop environment, ssh enabled, and shared folders.

That said, running this on macOS should still work fine, again ideally on the same ISA as the server (hence the aarch64 default).

Now either run (cd anywhere && ./auto.sh <server_ip> <path_to_your_ssh_key>), with the path being e.g. ~/.ssh/id_ed25519.pub. Or if you want to do this manually (or make customizations):

  • Put the key into anywhere/configuration.nix (the REPLACEME) so you can log in after NixOS is installed
  • Run nix run nixpkgs#nixos-anywhere -- --flake .#cloud root@<your-server-ip>
    • Replace the output name if you've changed it
    • The user doesn't have to be root but has to be able to sudo without entering a password
    • You need Nix installed with the nix-command experimental feature enabled. If this doesn't work for you on macOS, you can run this from a VM (preferably matching the server ISA).
  • If everything goes well, the server will reboot. Shortly after that you should be able to ssh into the server and get root access
    • The server will also have a new SSH key, so you'll have to clear old records from ~/.ssh/known_hosts

Adding basic configuration

Make sure you've removed the server's previous key from ~/.ssh/known_hosts if you've connected to the server before!

Following successful installation, run (cd postinstall && ./auto.sh <server_ip> <path_to_your_ssh_key>) (once the server has rebooted). Or if you want to do this manually:

  • ssh into the server and run nixos-generate-config
  • replace /etc/nixos/configuration.nix with postinstall/configuration.nix from this repo
  • copy postinstall/flake.nix to /etc/nixos/flake.nix
  • nixos-rebuild switch

Next steps

Configure your NixOS server as you want. The only things to keep in mind are:

  • there are no channels configured
  • it's using a flake for the system config and setting the nix path in /etc/nixos/flake.nix
  • the server's hostname is nixos

You may want to change the hostname, pull in some flake with system config for that particular hostname, or you may want to just import some modules into your config.

Setting up a Laravel app

After you have a NixOS server set up, you can use our laravel.nix module to start configuring Laravel sites.

The module is fairly generic so it should work for most sites. It's written in a simple way, to be as easy to customize as possible if needed, while offering enough customization for most applications.

Import the module in your system flake and invoke it with these parameters:

(laravelSite {
  name = "mysite";
  domains = [ "mysite.com" ];
  phpPackage = pkgs.php84;

  ssl = true; # optional, defaults to false, affects *ALL* domains
  extraNginxConfig = "nginx configuration string"; # optional
  sshKeys = [ "array" "of" "public" "ssh" "keys" ]; # optional
  extraPackages = [ pkgs.nodejs_24 ]; # optional
  queue = true; # start a queue worker - defaults to false, optional
  queueArgs = "--tries=3"; # optional, default empty
  generateSshKey = false; # optional, defaults to true
  poolSettings = { # optional
    "pm.max_children" = 12;
    "php_admin_value[opcache_memory_consumption]" = "512";
    "php_admin_flag[opcache.validate_timestamps]" = true;
  };
})

The module creates a new user (laravel-${name}), a /srv/${name} directory, configures cron to run every minute optionally starts a queue worker and configures php-fpm with good defaults (see below). The user has a home directory in /home/laravel-${name} (used mainly for ./cache used by composer and npm) and the site is served from the srv directory.

The default php-fpm opcache configuration is to cache everything forever without any revalidation. Therefore, make sure to include sudo systemctl reload phpfpm-${name} in your deployment script.

To deploy your app, you can use ssh deployments, rather than webhooks triggering pull hooks or other techniques. Since this module creates a new user for each site, this deployment technique becomes non-problematic and it's one of the simplest things you can do. Just ssh-keygen a private key, make a GitHub Actions job use that on push, and include the public key in the site's sshKeys array. Then, to be able to git pull the site on the server, add the user's ~/.ssh/id_ed25519.pub to the repository's deployment keys. The ssh key for the user is generated automatically (can be disabled by setting generateSshKey to false).

Also, if you're using ssl you should put this line into your system config:

security.acme.defaults.email = "your@email.com";

A full system config can look something like this (excluding any additional configuration you may want to make):

{
  description = "System flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
  };

  outputs = { self, nixpkgs, ... }@inputs: {
    nixosConfigurations = let
      system = "aarch64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
      laravelSite = import ./laravel.nix;
    in {
      nixos = nixpkgs.lib.nixosSystem {
        inherit system;

        modules = [
          {
            nix.nixPath = [ "nixpkgs=${inputs.nixpkgs}" ];
            security.acme.defaults.email = "your@email.com";
          }
          ./configuration.nix

          # your (laravelSite { ... }) calls here
        ];
      };
    };
  };
}

There's a million different ways to structure your system flake, so you may prefer to use something different. Note that laravel.nix is explicitly not a flake and not a top-level "input" - the goal is to just invoke it each time to change system configuration. We don't want an additional lockfile for the laravel module and we don't want to update the system lockfile whenever we make changes to the laravel module. With the most basic configuration, you should only have nixpkgs in your lockfile.

There also isn't any special shell since Laravel is entirely handled by system daemons like nginx, php-fpm, cron, and optionally a queue worker systemd service. We do include a .bashrc with some echos to quickly remind you of the filesystem structure and available commands.

Simply scp laravel.nix root@<your server ip>:/etc/nixos/ and start writing config as above.