Start from Nix shell

Published June 13, 2024

I am developing this website with WordPress! Sorry, I had to tell this to somebody. I started my journey with PHP and when I decided to invest my time on creating the contents I always wanted to write but that I didn’t find a good place for I decided to use WordPress, because I want to stay focused on contents and I knew I needed a database for the newsletter, scheduling posts and so on.

I decided to do it my own way, so it means no theme because they turn a nightmare to maintain for what recall, and a few plugins as possible. Right now I am using Independent Analytics only to count sessions length, page views and so on. I didn’t want to use Google Analytics and it looked a nice alternative.

Enough is enough, obviously I am using NixOS as delivery mechanism and to set up my development environment, since I am developing the theme I do it locally, and then I ship it when I am done.

I think nix-shell, the tool Nix serves to create a development environment is actually the right way to start figuring out how NixOS works, at least it worked out great for me.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = {self, nixpkgs, flake-utils, ...}:
    flake-utils.lib.eachDefaultSystem
    (system:
    let
      pkgs = import nixpkgs { inherit system; };
    in with pkgs;
    {      
      devShells.default = mkShell {
        buildInputs = [
          git
          php
          mariadb
          process-compose
        ];
      };
    });
}

There are a lot of articles about nix already, so I will go do deep on its structure, if you want let me know and I can write its own article.

Nix supports cross arch build and flake-utils hides the supported platform. Specifically, this declaration makes the devShell to compile correctly on the defultSystems.

You can enter this devShell running nix develp.

I am installing the required dependencies, PHP, MariaDB obviously, and I am using process-compose to spin all up. I tend to always write a process or a docker compose even if I need to spin up a few and easy services because you never know! Having it setup makes onboarding of new services easier, and it improves experimentation. For example, if I end up needing a cache, I will just be a matter of spinning up Redis or Memcached to try it out, and I tend to forget about this, so I am sure if I won’t develop this website for a few weeks I won’t remember about how I did basic things. Because we all know that here are a million ways to achieve the same things, and very often the decision is driven by what we want to experiment with or the time we have to invest at that point in time.

Speaking of time, I had some time to waste, and I decided to avoid Docker for spinning up MariaDB. Too easy and I didn’t want to use a container, so I created a wp-data directory that I added to .gitignore and I wasted some time figuring out how to spin up MariaDB. This is the process-compose:

version: "0.5"
processes:
  wp:
    command: "php -S 0:8080"
    working_dir: "./wordpress"
  mysql:
    command: "mariadbd --defaults-file=./dev/my.cnf"

And here the my.cnf

# Example mysql config file.

[client-server]
socket=/tmp/mysql-dbug.sock
port=3307

# Here are entries for some specific programs
# The following values assume you have at least 32M ram

# The MariaDB server
[mysqld]
temp-pool
key_buffer_size=16M
datadir=./wp-data
loose-innodb_file_per_table

[mariadb]
datadir=ABSPATH/wp-data
default-storage-engine=aria
loose-mutex-deadlock-detector
max-connections=20

[mariadb-5.5]
socket=/tmp/mysql-dbug.sock
port=3307

[mariadb-10.1]
socket=/tmp/mysql2-dbug.sock

[mysqldump]
quick
max_allowed_packet=16M

[mysql]
no-auto-rehash
loose-abort-source-on-error

[mysql_install_db]
datadir=./wp-data

When you start MySQL or MariaDB from an empty directory, it fails:

$ mkdir wp-data
$ mariadbd --defaults-file=./contrib/dev/my.cnf
...
2024-06-13 10:39:17 0 [ERROR] Could not open mysql.plugin table: "Table 'mysql.plugin' doesn't exist". Some plugins may be not loaded
2024-06-13 10:39:17 0 [Warning] mariadbd: unknown option '--loose-mutex-deadlock-detector'
2024-06-13 10:39:17 0 [Note] InnoDB: Buffer pool(s) load completed at 240613 10:39:17
2024-06-13 10:39:17 0 [ERROR] Can't open and lock privilege tables: Table 'mysql.servers' doesn't exist
2024-06-13 10:39:17 0 [Note] Server socket created on IP: '0.0.0.0'.
2024-06-13 10:39:17 0 [Note] Server socket created on IP: '::'.
2024-06-13 10:39:17 0 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.db' doesn't exist
2024-06-13 10:39:17 0 [ERROR] Aborting

You need to initialize the database:

$ mysql_install_db --defaults-file=./contrib/dev/my.cnf

And now you have an up and running MariaDB or MySQL instance dedicated to your own project.

This is not the way I go in production, I rely on how the OS I use package the database, but it was fun to experiment with that locally. So far I didn’t have any issue, it works as expected.

Are you having trouble figuring out your way to building automation, release and troubleshoot your software? Let's get actionables lessons learned straight to you via email.