I installed opensuse on my laptop

nix
linux
_blog
Temporary, or permanent?
Published

June 11, 2023

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, pkgs-kbctl, ... }:

{
  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "moonpie";
  home.homeDirectory = "/home/moonpie";

  # 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.
  home.stateVersion = "24.05"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    pkgs-kbctl.kubectl

    pkgs.fluxcd
    pkgs.nixgl.nixGLIntel pkgs.nixgl.nixVulkanIntel
    pkgs.gzdoom
  ];

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {
    # # Building this configuration will create a copy of 'dotfiles/screenrc' in
    # # the Nix store. Activating the configuration will then make '~/.screenrc' a
    # # symlink to the Nix store copy.
    # ".screenrc".source = dotfiles/screenrc;

    # # You can also set the file content immediately.
    # ".gradle/gradle.properties".text = ''
    #   org.gradle.console=verbose
    #   org.gradle.daemon.idletimeout=3600000
    # '';
  };

  # 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 = {
    # EDITOR = "emacs";
  };

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}