I installed opensuse on my laptop
School had just ended. During the school year, I had been using a hybrid graphics (dual-gpu) laptop, that otherwise worked normally, but had horrible, terrible battery life. I had struggled to get 2 hours out of it, because the dedicated nvidia gpu would not get turned off properly.
So I decided to switch to my second laptop, which has been unused so far. But it has pure intel graphics, and the laptop has much better linux support, and consequently, a much better battery life.
Before setting it up, I had a few requiremnts.
Security. Previously, I didn’t care about this, because I carried my laptop around with me at all times, but now I was going to be leaving my laptop unattended, maybe for extended periods of time. That meant I needed full disk encryption, and secure/trusted boot. However, I had limited time to set this up, so I neede to find a distro that did this the easiest way possible. I eventually settled on opensuse, which had an option to set up secure boot and encryption in the installer, under guided partitioning. After some hiccups, it installed just fine.
And the other, is my tools and packages. I didn’t worry too much about this, because I had decided beforehand on using nix and home-manager to install packages not available in the repositories. Home manager is a tool that allows for declarative configuration of a user environmetn, including packages, configuration files, or environment variables, using the nix programming language. Notably, it can be useed on almost all linux distros.
Here is my current home.nix, as of writing this, the file home-manager takes as an input.
Show
home.nix
{
pkgs ? import <nixpkgs> {},
config,
lib,
...
}:
let
nixgl = import <nixgl> {};
nixGlWrapper = import ./nixglwrapper.nix {inherit nixgl pkgs lib config;};
in
with import ./quarto.nix {inherit pkgs config lib;};
with import ./nixglwrapper.nix {inherit pkgs config lib nixgl;};
{
# Home Manager needs a bit of information about you and the paths it should
# manage.
home.username = "moonpie";
home.homeDirectory = "/home/moonpie";
targets.genericLinux.enable = true;
nixpkgs.config.allowUnfree = true;
nix.settings.experimental-features = ["nix-command" "flakes"];
# This value determines the Home Manager release that your configuration is
# compatible with. This helps avoid breakage when a new Home Manager release
# introduces backwards incompatible changes.
#
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
nix.package = pkgs.nix;
home.stateVersion = "23.11"; # Please read the comment before changing.
# The home.packages option allows you to install Nix packages into your
# environment.
#fonts.fontconfig.enable = true;
xdg.mime.enable = true;
home.packages = [
#nixgl
nixgl.nixGLIntel
nixgl.nixVulkanIntel
(nixGLWrap pkgs.vscode)
(nixGLWrap pkgs.microsoft-edge)
(nixGLWrap pkgs.firefox)
pkgs.micro
pkgs.calibre
pkgs.languagetool
pkgs.git
pkgs.soundwireserver
quarto
pkgs.jupyter
pkgs.python3
pkgs.yt-dlp
pkgs.macchanger
pkgs.nmap
pkgs.wireshark
pkgs.gocryptfs
# # Adds the 'hello' command to your environment. It prints a friendly
# # "Hello, world!" when run.
# pkgs.hello
# # It is sometimes useful to fine-tune packages, for example, by applying
# # overrides. You can do that directly here, just don't forget the
# # parentheses. Maybe you want to install Nerd Fonts with a limited number of
# # fonts?
# (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })
# # You can also create simple shell scripts directly inside your
# # configuration. For example, this adds a command 'my-hello' to your
# # environment:
# (pkgs.writeShellScriptBin "my-hello" ''
# echo "Hello, ${config.home.username}!"
# '')
];
# Home Manager is pretty good at managing dotfiles. The primary way to manage
# plain files is through 'home.file'.
home.file = {};
home.sessionVariables = {
# EDITOR = "emacs";
};
# Let Home Manager install and manage itself.
programs = {
home-manager.enable = true;
bash.enable = true;
gh.enable = true;
};
}Of course, the home.nix file isn’t all there is too it. There are also some imports, which take info from files that aren’t home.nix.
I have two imports, as of right now.
Using nix to run applications on non-nixos distros mostly works, but has some quirks. One quirk is that hardware accelerated graphics (opengl, vulkan) is lacking. In order to get around this, I use a program called nixgl. However, nixgl is essentially a wrapper, and it works by calling hte program you want to run as a command line argument. Someone automated that in nix, and I integrated that into my code.
Show
nixglwrapper.nix
{ config, pkgs, lib, nixgl } :
{
nixGLWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
mkdir $out
ln -s ${pkg}/* $out
rm $out/bin
mkdir $out/bin
for bin in ${pkg}/bin/*; do
wrapped_bin=$out/bin/$(basename $bin)
echo "exec ${lib.getExe nixgl.nixGLIntel} $bin \"\$@\"" > $wrapped_bin
chmod +x $wrapped_bin
done
'';
nixVulkanWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
mkdir $out
ln -s ${pkg}/* $out
rm $out/bin
mkdir $out/bin
for bin in ${pkg}/bin/*; do
wrapped_bin=$out/bin/$(basename $bin)
echo "exec ${lib.getExe nixgl.nixVulkanIntel} $bin \"\$@\"" > $wrapped_bin
chmod +x $wrapped_bin
done
'';
}And of course, finally my custom quarto package that I had made in another post
Show
quarto.nix
{ pkgs, config, lib, ... } :
let
pandoc = null;
extraRPackages = [];
extraPythonPackages = ps: with ps; [];
in
{
quarto = (pkgs.quarto.overrideAttrs (oldAttrs: rec {
version = "1.3.361";
src = pkgs.fetchurl {
url = "https://github.com/quarto-dev/quarto-cli/releases/download/v${version}/quarto-${version}-linux-amd64.tar.gz";
sha256 = "sha256-vvnrIUhjsBXkJJ6VFsotRxkuccYOGQstIlSNWIY5nuE=";
};
buildInputs = with pkgs; [ ];
preFixup = ''
wrapProgram $out/bin/quarto \
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.deno ]} \
--prefix QUARTO_PANDOC : $out/bin/tools/pandoc \
--prefix QUARTO_ESBUILD : ${pkgs.esbuild}/bin/esbuild \
--prefix QUARTO_DART_SASS : $out/bin/tools/dart-sass/sass \
--prefix QUARTO_R : ${pkgs.rWrapper.override { packages = [ pkgs.rPackages.rmarkdown ] ++ extraRPackages; }}/bin/R \
--prefix QUARTO_PYTHON : ${pkgs.python3}/bin/python3
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin $out/share
mv bin/* $out/bin
mv share/* $out/share
'';
})).override {inherit pandoc extraPythonPackages extraRPackages;};
}However, in order for running some programs with sudo to work, I had to edit opensuse’s default sudo configuration to keep environment variables, and not change the default path. This is an understandable thing to do on a multi user system, but on my single user system where I want to use some packages installed via nix with sudo, it is just annoying.
/etc/sudoers
...
##
## Defaults specification
##
## Prevent environment variables from influencing programs in an
## unexpected or harmful way (CVE-2005-2959, CVE-2005-4158, CVE-2006-0151)
#Defaults always_set_home
## Use this PATH instead of the user's to find commands.
#Defaults secure_path="/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin"
Defaults !env_reset
## Change env_reset to !env_reset in previous line to keep all environment variables
....I’ve now uploaded my home.nix to a github repo: https://github.com/moonpiedumplings/home-manager
Here is the home.nix that is currently in the main branch of my github repo (this is dynamically rendered and updated every update of this blog)
home.nix
{
config,
pkgs,
inputs,
system,
...
}:
let
# multiverse cli
mvs = inputs.multiverse.packages.${system}.mvs;
# Get a specific version of a package via pkgname."versionnumber"
multiverse = inputs.multiverse.multiverse.${system}.versions;
# .fast gets packages without evaluating or caching nixpkgs, preventing store bloat.
# Also, packages need to be appended with .out
# see: https://github.com/fzakaria/nixpkgs-multiverse/blob/main/docs/nix-api.md#the-fast-path
fastverse =
pkgs.lib.mapAttrsRecursiveCond
(x: !pkgs.lib.isDerivation x)
(_path: drv: drv.out)
inputs.multiverse.multiverse.${system}.fast.versions;
llm-agents = inputs.llm-agents.packages.${system};
maki = inputs.maki.packages.${system}.default;
#llamacpp = inputs.llamacpp.packages.${system};
pkgsRocm = import <nixpkgs> {
config = {
allowUnfree = true;
rocmSupport = true;
permittedInsecurePackages = [
"python3.13-vllm-0.16.0"
];
};
};
vllm = pkgsRocm.vllm;
llama-cpp = pkgs.llama-cpp.override {
vulkanSupport = false;
cudaSupport = false;
rocmSupport = true;
rocmGpuTargets = [ "gfx1151" ];
};
llamacpp = llama-cpp.overrideAttrs (oldAttrs: rec {
version = "9992";
src = pkgs.fetchFromGitHub {
owner = "ggml-org";
repo = "llama.cpp";
tag = "b${version}";
hash = "sha256-yWyNIVx7jVuskKywG9HQ4WpPfplMtQAWjLAFbJxPEbA=";
leaveDotGit = true;
postFetch = ''
git -C "$out" rev-parse --short HEAD > $out/COMMIT
find "$out" -name .git -print0 | xargs -0 rm -rf
'';
};
npmDepsHash = "sha256-6s9skw1wzEfm9QKktTqea3J+oudQAsS6O2VnZEMXAdw=";
# preFixup = ''
# wrapProgram $out/bin/llama \
# --set-default HSA_OVERRIDE_GFX_VERSION 11.5.1
# '';
# nativeBuildInputs = (with pkgs; [
# cmake
# installShellFiles
# ninja
# nodejs
# npmHooks.npmConfigHook
# pkg-config
# spirv-headers
# makeWrapper
# ]);
});
in
{
# Home Manager needs a bit of information about you and the paths it should
# manage.
# home.username = builtins.getEnv "USER";
# home.homeDirectory = builtins.getEnv "HOME";
# You're not supposed to update this value because it changes config options and is not guaranteed to be compatible
# But because I use home manager exclusively for packages, and not at all for config, I can safely update this to the latest version pretty much always
home.stateVersion = "25.11";
# Prevent generation of home-configuration.nix manpage (not all packages)
# Prevents a warning about something being unreliable
manual.manpages.enable = false;
# Enables GPU acceleration for all Nix pacakges, not just home manager one's.
targets.genericLinux = {
enable = true;
gpu.enable = true;
};
# targets.genericLinux.nixGL = {
# packages = null;
# #packages = pkgs.nixgl;
# defaultWrapper = "mesa";
# # might cause issues
# vulkan.enable = true;
# };
home.packages =
(with pkgs; [
# nix cli helper
nh
# multiverse cli for running specfic versions
mvs
fastverse.kubectl."1.33.1"
fluxcd
kubernetes-helm
yaml-language-server
age
sops
# kubectl plugins and tools
k9s
kubectl-cnpg
kubectl-view-secret
#kubectl object inspection
kubectl-tree kubectl-graph
# docs and examples
kubectl-example kubectl-explore kubectl-validate
# cluster info
kubectl-df-pv kubectl-images
#debugging, pod/nod
kubectl-node-shell kubespy kubectl-doctor
# network utilities
krelay kubeshark cilium-cli
# various utilities
streamlink
zellij
dbeaver-bin
# logging
lnav
# github cli client + copilot
gh
# llama.cpp
#llamacpp.rocm
#(config.lib.nixGL.wrappers.mesa llamacpp.vulkan)
#(config.lib.nixGL.wrappers.mesa llamacpp)
#llamacpp
#vllm
# llm agents
llm-agents.nanocoder
llm-agents.kilocode-cli
llm-agents.goose-cli
llm-agents.forgecode
llm-agents.hermes-agent
llm-agents.hermes-desktop
llm-agents.hermes-hud
llm-agents.pi
maki
# sandboxing features
pkgs.fence
# UI stuff for AI
pkgs.open-webui
# nix dev stuff
nixd nil
# games and fun
gzdoom ares
])
#++ gpu-wrapped-agents
#++ gpu-wrapped-hermes
;
programs.man = {
enable = true;
generateCaches = true;
};
nix = {
# nix shell nixpkgs#test will use home manager's nixpkgs and dependencies
# This prevents auto updattes and then massive duplication of dependencies of nix flake stuff.
registry.nixpkgs.flake = inputs.nixpkgs;
package = pkgs.nix;
settings = {
flake-registry = "${config.xdg.configHome}/nix/project-registry.json";
extra-experimental-features = [ "nix-command" "flakes" ];
extra-trusted-substituters = [
"https://nix-community.cachix.org"
"https://cache.numtide.com"
];
extra-trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g="
];
};
};
home.file = {
# Adjusting nix.channels, nix.path and similar requires home manager to be managing the shell and env variables
# Since home manager isn't, I just directly symlink the empty channels directory to home managers nixpkgs flake.
# This fixes channels not working, since they disappeared on me
".nix-defexpr/channels" = {
source = (pkgs.linkFarm "home-manager-channels" [
{
name = "nixpkgs";
path = inputs.nixpkgs;
}
]);
recursive = false;
};
};
# Home Manager can also manage your environment variables through
# 'home.sessionVariables'. These will be explicitly sourced when using a
# shell provided by Home Manager. If you don't want to manage your shell
# through Home Manager then you have to manually source 'hm-session-vars.sh'
# located at either
#
# ~/.nix-profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# /etc/profiles/per-user/moonpie/etc/profile.d/hm-session-vars.sh
#
home.sessionVariables = {
# Debug variable available in the repl (after :lf .) at homeConfigurations.moonpie.config.home.sessionVariables.TYPE_OF
# Because nix is such a nightmare to debug that I have to do this to view the type of something declared inside the let block
#TYPE_OF = "${builtins.typeOf gpu-wrapped-agents}";
# see https://github.com/karolswdev/framework-rocm
# I could probably wrap llama.cpp itself but whatever
#wHSA_OVERRIDE_GFX_VERSION = "11.5.1";
};
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
}