The purpose of this repository is to provide nixos configuration files to quickly assemble a working chuck-stack.
You can use the below files like a menu of services. Choose the options you wish to install on a given server using the below details.
- system.nix - installs all the tools one might expect to manage a server.
- postgresql.nix - installs PostgreSQL with minimal configuration
- user.nix - provides example 'real' and 'system' users
- stk-core.nix - represents the most simple version of a chuck-stack application
- configures PostgreSQL to contain a specific database
- creates a service to run migrations from chuck-stack-core using chuck-stack-nushell-psql-migration
- installs pg_jsonschema extension for PostgreSQL 17
- creates a PostgREST system user named 'postgrest'
- configures PostgREST and runs it as a service
- creates a 'stk_superuser' to perform database administration
- nginx.nix - installs and configures nginx for publishing a static site and providing a reverse proxy for PostgREST
- more...
This section assumes you are connecting to a new NixOS instance.
sudo nix-channel --update
sudo nixos-rebuild switch
# nix-shell: temporarily install tools and create sub-shell so you can change configuration.nix
sudo nix-shell --packages wget git neovim tmux
https://raw.githubusercontent.com/chuboe/chuboe-system-configurator/refs/heads/main/.inputrc
# tmux: (optional) use tmux to create a session that remains even if you get disconnected
cd /etc/nixos/
# git: you can create a fork and clone your own copy if desired
git clone https://github.com/chuckstack/chuck-stack-nixos.git
nvim configuration.nix #make below changes
# update the configuration.nix as described below
sudo nixos-rebuild switch
Notes:
- You can use nix-shell to temporarily create a sub-shell and install git, neovim and tmux (and anything else you wish to use).
- You can exit from the nix-shell sub-shell at any time.
- These tools will no long be available when you exit from the sub-shell.
You simply include the services you want in your /etc/nixos/configuration.nix file.
Here is an example configuration.nix file. Notice the lines ending in '# here'. They represent the lines you might want to add to your configuration.
...
imports = [
# Include the default incus configuration.
"${modulesPath}/virtualisation/incus-virtual-machine.nix"
# Include the container-specific autogenerated configuration.
./incus.nix
./chuck-stack-nixos/nixos/system.nix # here
./chuck-stack-nixos/nixos/postgresql.nix # here
./chuck-stack-nixos/nixos/user.nix # here
./chuck-stack-nixos/nixos/stk-core.nix # here
./chuck-stack-nixos/nixos/nginx.nix # here
#./chuck-stack-nixos/nixos/nginx-fail2ban.nix # here if needed
#./chuck-stack-nixos/nixos/cloudflared.nix # here if needed
];
...
Use your preferred git best practice to manage changes to the nix confirmation files. The purpose of this section is to discuss options for how to manage your changes.
You are welcome to fork the chuck-stack-nixos repository and use that repository above instead. Doing so has the following benefits:
- You can privately track your changes in your github account.
- You can easily compare your changes against the current version of chuck-stack-nixos.
Another option to simply copy the newly cloned /etc/nixos/chuck-stack-nixos/ directory to a version you track yourself.
Either option is valid.
Some of the services require consideration and possibly configuration before using. Perform the following to quickly see all pending actions in all files:
grep -rni -C10 "Action:" /etc/nixos/chuck-stack-nixos/nixos
To look for a specific action with a specific keyword somewhere in the same line:
grep -rni -C10 "Action:.*your-keyword" /etc/nixos/chuck-stack-nixos/nixos
Note: -C10 shows the previous and following 10 lines around the action.
To rebuild with the new configuration:
nixos-rebuild switch
If you completely exit from your session then reconnect, your bash session will be updated with all the new tools and features.
Nix is powerful, capable as well as complex. We have tried to be consistent and adopt best practices in how we do things. One way to promote consistency is to highlight examples of something is done. Do not hesitate to offer suggestions!
When looking for examples, start in system.nix. It represents the starting place to configure your system.
Perform the following to quickly see all "# Example..." in all files:
grep -rni -A10 "Example:" /etc/nixos/chuck-stack-nixos/nixos
To look for a specific example with a specific keyword somewhere in the same line:
grep -rni -C10 "Example:.*your-keyword" /etc/nixos/chuck-stack-nixos/nixos
Note: -A10 shows the following (after) 10 lines
This section helps you connect to your newly created chuck-stack database. Here are important details to know:
- The database is configured to listen to unix socket connects from local users.
- The stk-core.nix configuration creates a 'stk_superuser' in both the database and nixos.
- This means that if a NixOS user is authenticated (stk_superuser for example) and the same user exists in the database, you can connect without a password.
To connect to the database (assuming you starting from the nixos root user):
# > root
su - stk_superuser
# > stk_superuser
psql
Note that you do not need to specify the database when calling psql
because the <./nixos/stk-core.nix> configuration sets the PGDATABASE='stk_db' environment variable for everyone.
The stk-core.nix configuration uses chuck-stack-nushell-psql-migration to manage database migrations. Migrations are sourced from the chuck-stack-core repository.
To re-run migrations:
sudo systemctl restart stk-db-migrations
sudo systemctl status stk-db-migrations
To view migration logs:
sudo journalctl -u stk-db-migrations -n 50
SSH is disabled by default in system.nix. Uncomment the system.nix => services.openssh section if you wish to enable it. The reasons it is disabled by default are:
- It is safer to assume you do not want it.
- The NixOS default behavior is to open the ssh port firewall port when the ssh service is enagbled. To prevent this, you must explicitly disable the port in the system.nix => networking.firewall section.
- The Incus command
incus exec instance-name bash
does not use ssh to connect; therefore, you can connect from Incus without needing the sshd services enabled.
If you wish to expose an instance to the outside world from an Incus cluster, execute the following assuming your external IP is x.x.x.x/32.
# from incus cli
incus config device override incus-isntance-name eth0 ipv4.routes.external=x.x.x.x/32
Inside your container's /etc/nixos/configuration.nix, update the systemd.network => networks => networkConfig accordingly:
...
networkConfig = {
Address = "x.x.x.x/32";
DHCP = "yes";
IPv6AcceptRA = true;
};
...
If you run ip a
, you should see an internal IP and the above x.x.x.x/32 external IP.
The most simple and standard way to handle key-value pairs in NixOS while restricting visibility is to use a separate Nix file with restricted file permissions. Note this topic does not involve/include encryption.
To create isolation from the nix store, place the secrets file in a separate directory with restricted permissions:
sudo mkdir -p /etc/chuck-stack/secrets
sudo chmod 700 /etc/chuck-stack/secrets
sudo touch /etc/chuck-stack/secrets/keys.nix
sudo chmod 600 /etc/chuck-stack/secrets/keys.nix
sudo chown root:root /etc/chuck-stack/secrets/keys.nix
# /etc/chuck-stack/secrets/keys.nix
{
apiKey = "your-api-key";
dbPassword = "your-db-password";
# other key-value pairs
}
Here is an example:
# /etc/nixos/configuration.nix
{ config, pkgs, ... }:
let
secrets = import /etc/chuck-stack/secrets/keys.nix;
in {
# Now use the values as needed
services.someService.apiKey = secrets.apiKey;
services.database.password = secrets.dbPassword;
}
Here is another example copied in part from cloudflared.nix:
{ config, lib, pkgs, modulesPath, ... }:
let
# Import secrets here
secrets = import /etc/chuck-stack/secrets/keys.nix;
in {
environment.systemPackages = with pkgs; [
cloudflared
];
#... Lines omitted for brevity
systemd.services.my_tunnel = {
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" "systemd-resolved.service" ];
requires = [ "network-online.target" ];
serviceConfig = {
# Use secret here
ExecStart = "${pkgs.cloudflared}/bin/cloudflared tunnel --no-autoupdate run --token=${secrets.cloudflaredToken}";
Restart = "always";
User = "cloudflared";
Group = "cloudflared";
};
};
}
Be aware that this approach only protects the file from being read directly. For true security, you would need encryption-based tools like agenix
or sops-nix
.
Each Nix file has a section at the top for notes about the configuration and its usage