FROM debian:trixie-slim ENV TZ=America/New_York ARG DEBIAN_FRONTEND=noninteractive # Build-time args -> baked into the image as env vars for later use ARG DOTFILES_USER=cobertos ARG DOTFILES_EMAIL=me+git@cobertos.com ARG DOTFILES_GIT_DEFAULT_BRANCH=owo ARG DOTFILES_ENVIRONMENT=bare ARG DOTFILES_ARCHITECTURE=x86_64-linux ENV DOTFILES_USER=${DOTFILES_USER} ENV DOTFILES_ENVIRONMENT=${DOTFILES_ENVIRONMENT} ENV DOTFILES_ARCHITECTURE=${DOTFILES_ARCHITECTURE} ENV DOTFILES_LOG_SHELL_TO_DOCKER=1 # Nix installer args # Look up at https://github.com/NixOS/nix-installer/releases # Version corresponds to nix version at https://releases.nixos.org ARG NIX_INSTALLER_VERSION=2.34.6 ARG NIX_INSTALLER_ARCHITECTURE=${DOTFILES_ARCHITECTURE} # Deps before we start doing things RUN apt-get update \ && apt-get install -y ca-certificates sudo xz-utils curl \ && rm -rf /var/lib/apt/lists/* # Install nix multi-user (must be root) # The install process is pretty involved for multi-user install so unfortunately # we will use a script for this and not do it ourselves :( # In general I have to configure nix through this instead of with directly writing # nix.conf as this installer will clobber any changes we make # https://github.com/NixOS/nix-installer/blob/main/README.md#in-a-container RUN curl -sSfL https://github.com/NixOS/nix-installer/releases/download/${NIX_INSTALLER_VERSION}/nix-installer-${NIX_INSTALLER_ARCHITECTURE} -o nix-installer \ && chmod +x nix-installer \ && ./nix-installer install linux --extra-conf "sandbox = false" --enable-flakes --no-confirm --init none ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin" # Setup nix entrypoint. Needs to run as root so we can write to /usr/local/bin. # (quoted heredoc 'EOF' does no variable expansion) # I'm actually really surprised && part of this works, but it does. This is because # heredoc follows the command. I hate shell :3 USER root RUN cat > /usr/local/bin/entrypoint.sh <<'EOF' \ && chmod +x /usr/local/bin/entrypoint.sh #!/usr/bin/env bash set -e # Start the nix-daemon (needs root) if its socket isn't already present if [ ! -S /nix/var/nix/daemon-socket/socket ]; then sudo sh -c 'nohup /nix/var/nix/profiles/default/bin/nix-daemon >/var/log/nix-daemon.log 2>&1 &' # wait for the socket to appear for i in $(seq 1 30); do [ -S /nix/var/nix/daemon-socket/socket ] && break sleep 0.2 done fi # Make sure nix itself is on PATH (daemon profile, not the user's broken one) . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh # If we persist the users home directory as a docker volume, updating the # underlying image will break the old persisted home directory. This will # check if the symlink at ~/.nix-profile is broken and rebuild it HM_LINK="$HOME/.nix-profile" if [ ! -e "$HM_LINK" ] || { [ -L "$HM_LINK" ] && [ ! -e "$HM_LINK" ]; }; then echo "[entrypoint] home-manager profile broken/missing — re-running switch..." nix run home-manager/master -- switch --flake "/dotfiles#${DOTFILES_ENVIRONMENT}" fi # Run whatever the user passed into the container after we started the daemon # (defaults to sleep infinity but might be something else) exec "$@" EOF # Setup user RUN groupadd -g 1000 ${DOTFILES_USER} && \ useradd -m -u 1000 -g 1000 -s /bin/bash ${DOTFILES_USER} && \ echo "${DOTFILES_USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers USER ${DOTFILES_USER} WORKDIR /home/${DOTFILES_USER} ENV USER=${DOTFILES_USER} ENV HOME=/home/${DOTFILES_USER} # Copy the dotfiles repo, filling in any defaults from our environment variables COPY --chown=1000:1000 . /dotfiles RUN test ! -f /dotfiles/secrets.sh || (echo "Failsafe: secrets.sh should not have been copied into the build!" && exit 1) # Add config.nix with Dockerfile configuration RUN cat > /dotfiles/config.nix </tmp/nix-daemon.log 2>&1 &' \ && sleep 2 \ && nix run home-manager/master -- switch --flake "/dotfiles#${DOTFILES_ENVIRONMENT}" \ && nix-collect-garbage -d \ && nix store optimise WORKDIR /home/${DOTFILES_USER} CMD ["sleep", "infinity"] ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]