numerous updates
This commit is contained in:
@@ -93,6 +93,48 @@ The printing service (cups) is turned on. This may need more work to "just work"
|
||||
|
||||
mDNS is installed and enabled so the your can find and SSH to your machine on your LAN using {machinename}.local.
|
||||
|
||||
### Firewall
|
||||
|
||||
The ufw firewall is on. It blocks incoming connections except SSH (22), mDNS (5353/udp), LocalSend (53317) and anything arriving over Tailscale. ufw-docker is installed too, because ports published by Docker containers otherwise get around ufw. To let a container's port through, use `sudo ufw-docker allow {container} {port}`. To open a port for something else, e.g. a dev server you want to reach from another machine, use `sudo ufw allow {port}/tcp`. `sudo ufw status` shows the current rules.
|
||||
|
||||
### Shell
|
||||
|
||||
Your ~/.bashrc sources ~/.local/share/coredesktop/shell/bashrc, which sets up the starship prompt, zoxide (`z {part of a path}` jumps to a directory you've used before), fzf key bindings (Ctrl-R searches history, Ctrl-T inserts a file path), eza for `ls`/`ll`/`la`/`lt`, and the aliases and functions in [shell/](shell/). If you already have ~/.config/starship.toml, your prompt config is used. Anything you add to ~/.bashrc after the CoreDesktop line overrides it.
|
||||
|
||||
### Snapshots
|
||||
|
||||
If / is btrfs (the archinstall default), Snapper takes a snapshot of / before every `update` and keeps the last 5. /home is a separate subvolume and isn't included, so rolling back never touches your files. `sudo snapper -c root list` shows the snapshots.
|
||||
|
||||
These snapshots can't be picked from the boot menu. To roll back after a bad update, boot the Arch ISO and replace the @ subvolume with a snapshot:
|
||||
|
||||
```
|
||||
mount -o subvolid=5 /dev/{root partition} /mnt
|
||||
mv /mnt/@ /mnt/@.broken
|
||||
btrfs subvolume snapshot /mnt/@.snapshots/{number}/snapshot /mnt/@
|
||||
reboot
|
||||
```
|
||||
|
||||
If the disk is encrypted, open it with `cryptsetup open` first and mount the opened device. Once the system works again, free the space the broken root used:
|
||||
|
||||
```
|
||||
sudo mount -o subvolid=5 /dev/{root partition} /mnt
|
||||
sudo btrfs subvolume delete /mnt/@.broken
|
||||
sudo umount /mnt
|
||||
```
|
||||
|
||||
### GPU drivers
|
||||
|
||||
The installer adds the Vulkan driver for Intel and AMD GPUs. If there's an NVIDIA GPU and archinstall's proprietary driver wasn't chosen, it installs NVIDIA's driver: the open kernel modules for GTX 16xx / RTX 20xx and newer, or the 580xx legacy driver for older cards back to the GTX 900 series. Reboot afterwards.
|
||||
|
||||
### System defaults
|
||||
|
||||
- SSH connections notice a dropped link within a minute instead of hanging (override per host in ~/.ssh/config).
|
||||
- Logins allow 10 wrong passwords before locking the account for 2 minutes (Arch's default is 3 tries, then 10 minutes).
|
||||
- Shutdown waits at most 10 seconds for a service that won't stop, instead of 90.
|
||||
- If memory runs out, systemd-oomd closes the app causing it instead of the whole desktop freezing.
|
||||
- Boot no longer waits for the network.
|
||||
- Commands run over SSH (`ssh {machine} {command}`) can find tools in ~/.local/bin and mise.
|
||||
|
||||
## Keep your System Up-to-date
|
||||
|
||||
From time-to-time, you'll want to update your system. Hopefully you'll do this more than once-a-month.
|
||||
@@ -103,7 +145,16 @@ To update the system type into the terminal:
|
||||
update
|
||||
```
|
||||
|
||||
The script does three things. It runs 'flatpak update' to update your Flatpak apps, it runs 'gem update' to update your Rails environment, and it runs 'sudo pacman -Syu' to update your Arch and Gnome installation.
|
||||
The script pulls the latest CoreDesktop, then runs each step in ~/.local/share/coredesktop/updates.d/ in order. Among other things it:
|
||||
|
||||
- stops if there's less than 10 GiB free on / (run `UPDATE_FORCE=1 update` to skip the check)
|
||||
- snapshots / first, if Snapper is set up (see Snapshots above)
|
||||
- updates the Arch keyring, then Arch and GNOME, then AUR packages, Flatpaks, Ruby, GNOME extensions and firmware
|
||||
- warns you not to reboot if the initramfs failed to rebuild
|
||||
- runs any one-time migrations, the way existing machines pick up new CoreDesktop setup
|
||||
- lists packages that are no longer needed, and the command to remove them
|
||||
|
||||
If a step fails, the other steps still run, and the failed ones are listed at the end.
|
||||
|
||||
It is a good idea to reboot after an update especially if you see you have a new Linux kernel installed (and that happens frequently enough for Arch).
|
||||
|
||||
@@ -141,6 +192,8 @@ If you want to use mDNS networking on your LAN (the ability to log in to other l
|
||||
|
||||
This whole "project" is licensed under the MIT License. Want to help make CoreDesktop better? Awesome! We welcome any and all help. Just contribute a PR and we're off to a better CoreDesktop.
|
||||
|
||||
Changes to install.sh only reach new installs. If existing machines need the change too, also add a migration: a script named `migrations/$(date +%s).sh` that `update` runs once on each machine. It may also run on fresh installs, so make it safe to repeat.
|
||||
|
||||
## Bonus
|
||||
|
||||
Bonus: here's a [nice song to listen to while you're installing](https://music.youtube.com/watch?v=y-5o2f9wzmw&si=_z9kcKHRwj-KTs7w).
|
||||
|
||||
+27
-1
@@ -70,7 +70,8 @@ echo "Starting full system setup..."
|
||||
|
||||
# Bring the system fully up to date before installing anything new
|
||||
echo "Updating system..."
|
||||
sudo pacman -Syu --noconfirm
|
||||
sudo pacman -Sy --needed --noconfirm archlinux-keyring
|
||||
sudo pacman -Su --noconfirm
|
||||
|
||||
cd ~/
|
||||
|
||||
@@ -168,6 +169,26 @@ if ! systemctl is-active tailscaled &> /dev/null; then
|
||||
sudo systemctl start tailscaled
|
||||
fi
|
||||
|
||||
# SSH keepalives, login lockout, shutdown timeout, OOM protection, boot, SSH PATH
|
||||
echo "Applying system defaults..."
|
||||
bash ~/.local/share/coredesktop/system/defaults.sh
|
||||
|
||||
# Block incoming connections except SSH, mDNS, LocalSend and Tailscale
|
||||
echo "Configuring the firewall..."
|
||||
bash ~/.local/share/coredesktop/system/firewall.sh
|
||||
|
||||
# Snapshot / before each update (btrfs only)
|
||||
echo "Configuring Snapper..."
|
||||
bash ~/.local/share/coredesktop/system/snapper.sh
|
||||
|
||||
echo "Installing GPU drivers..."
|
||||
bash ~/.local/share/coredesktop/system/vulkan.sh
|
||||
bash ~/.local/share/coredesktop/system/nvidia.sh
|
||||
|
||||
# Prompt, zoxide, fzf key bindings, aliases and functions
|
||||
echo "Configuring the shell..."
|
||||
bash ~/.local/share/coredesktop/shell/setup.sh
|
||||
|
||||
# Apply GNOME dconf settings only if the settings file has changed since last run
|
||||
bash ~/.local/share/coredesktop/gnome/apply-gnome-settings.sh
|
||||
|
||||
@@ -177,6 +198,11 @@ if systemctl is-enabled systemd-resolved.service &> /dev/null; then
|
||||
bash ~/.local/share/coredesktop/fixmdns.sh
|
||||
fi
|
||||
|
||||
# Run one-time migrations not yet recorded on this machine. On a fresh install
|
||||
# they repeat setup done above, which is safe because each one is idempotent.
|
||||
echo "Running migrations..."
|
||||
run_migrations
|
||||
|
||||
# Check whether the running kernel matches the installed modules — if not, a
|
||||
# newer kernel was installed during this run and a reboot is required
|
||||
if ! ls /usr/lib/modules/$(uname -r) > /dev/null 2>&1; then
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Rename the coreupdate and corerefresh commands to update and refresh
|
||||
|
||||
COREDESKTOP="$HOME/.local/share/coredesktop"
|
||||
|
||||
source "$COREDESKTOP/utils.sh"
|
||||
@@ -15,3 +17,5 @@ if [ -f ~/.local/bin/corerefresh ]; then
|
||||
install_script "$COREDESKTOP/refresh" ~/.local/bin/refresh
|
||||
sudo rm -f ~/.local/bin/corerefresh
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Hook CoreDesktop's shell setup into ~/.bashrc
|
||||
bash "$HOME/.local/share/coredesktop/shell/setup.sh"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# SSH keepalives, login lockout, shutdown timeout, OOM protection, boot and SSH PATH
|
||||
bash "$HOME/.local/share/coredesktop/system/defaults.sh"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Turn on the ufw firewall
|
||||
bash "$HOME/.local/share/coredesktop/system/firewall.sh"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set up Snapper for pre-update snapshots on btrfs
|
||||
bash "$HOME/.local/share/coredesktop/system/snapper.sh"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install Vulkan drivers for Intel and AMD GPUs
|
||||
bash "$HOME/.local/share/coredesktop/system/vulkan.sh"
|
||||
@@ -1,6 +1,7 @@
|
||||
# System utilities
|
||||
SYSTEM_UTILS=(
|
||||
age
|
||||
bash-completion
|
||||
bluez
|
||||
bluez-utils
|
||||
borg
|
||||
@@ -48,6 +49,8 @@ SYSTEM_UTILS=(
|
||||
tailscale
|
||||
traceroute
|
||||
tree
|
||||
ufw
|
||||
ufw-docker
|
||||
unzip
|
||||
usbutils
|
||||
vi
|
||||
@@ -128,6 +131,7 @@ MEDIA=(
|
||||
FONTS=(
|
||||
noto-fonts
|
||||
noto-fonts-emoji
|
||||
ttf-nerd-fonts-symbols
|
||||
)
|
||||
|
||||
# Services to enable
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# CoreDesktop aliases, sourced by shell/bashrc
|
||||
|
||||
# Files
|
||||
if command -v eza &> /dev/null; then
|
||||
alias ls='eza --group-directories-first --icons=auto'
|
||||
alias ll='eza -lh --group-directories-first --icons=auto'
|
||||
alias la='eza -lha --group-directories-first --icons=auto'
|
||||
alias lt='eza --tree --level=2 --long --icons=auto --git'
|
||||
fi
|
||||
|
||||
# Fuzzy-find a file with a preview, or open the one you pick in your editor
|
||||
alias ff="fzf --preview 'bat --style=numbers --color=always {}'"
|
||||
alias eff='${EDITOR:-nvim} "$(ff)"'
|
||||
|
||||
alias decompress='tar -xzf'
|
||||
|
||||
# Directories
|
||||
alias ..='cd ..'
|
||||
alias ...='cd ../..'
|
||||
alias ....='cd ../../..'
|
||||
|
||||
# Tools
|
||||
alias g='git'
|
||||
alias lg='lazygit'
|
||||
alias d='docker'
|
||||
alias ld='lazydocker'
|
||||
|
||||
# Git
|
||||
alias gcm='git commit -m'
|
||||
alias gcam='git commit -a -m'
|
||||
alias gcad='git commit -a --amend'
|
||||
@@ -0,0 +1,37 @@
|
||||
# CoreDesktop shell setup, sourced from ~/.bashrc (added by shell/setup.sh).
|
||||
# Anything in ~/.bashrc after the line that sources this file overrides it.
|
||||
|
||||
# Only for interactive shells
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
COREDESKTOP_SHELL="$HOME/.local/share/coredesktop/shell"
|
||||
|
||||
# History: keep a lot of it, skip duplicates, and don't let shells overwrite
|
||||
# each other's history on exit
|
||||
shopt -s histappend
|
||||
HISTCONTROL=ignoreboth
|
||||
HISTSIZE=32768
|
||||
HISTFILESIZE="$HISTSIZE"
|
||||
|
||||
if [[ ! -v BASH_COMPLETION_VERSINFO && -f /usr/share/bash-completion/bash_completion ]]; then
|
||||
source /usr/share/bash-completion/bash_completion
|
||||
fi
|
||||
|
||||
source "$COREDESKTOP_SHELL/aliases"
|
||||
source "$COREDESKTOP_SHELL/functions"
|
||||
|
||||
# Prompt. Uses CoreDesktop's starship config unless you have your own.
|
||||
if [[ $TERM != "dumb" ]] && command -v starship &> /dev/null; then
|
||||
[[ -f "$HOME/.config/starship.toml" ]] || export STARSHIP_CONFIG="$COREDESKTOP_SHELL/starship.toml"
|
||||
eval "$(starship init bash)"
|
||||
fi
|
||||
|
||||
# z <part of a path> jumps to a directory you've visited before
|
||||
if command -v zoxide &> /dev/null; then
|
||||
eval "$(zoxide init bash)"
|
||||
fi
|
||||
|
||||
# Ctrl-R fuzzy history search, Ctrl-T to insert a file path, Alt-C to cd
|
||||
if [[ -f /usr/share/fzf/key-bindings.bash ]]; then
|
||||
source /usr/share/fzf/key-bindings.bash
|
||||
fi
|
||||
@@ -0,0 +1,78 @@
|
||||
# CoreDesktop shell functions, sourced by shell/bashrc
|
||||
|
||||
# n opens Neovim in the current directory, or on the files given
|
||||
n() { if [ "$#" -eq 0 ]; then command nvim . ; else command nvim "$@"; fi; }
|
||||
|
||||
# open a file or URL with its default app, detached from the terminal
|
||||
open() (
|
||||
xdg-open "$@" > /dev/null 2>&1 &
|
||||
)
|
||||
|
||||
# compress <dir> makes <dir>.tar.gz (decompress is an alias for tar -xzf)
|
||||
compress() { tar -czf "${1%/}.tar.gz" "${1%/}"; }
|
||||
|
||||
# SSH port forwarding
|
||||
# fip <host> <port>... forward each localhost port to the same port on host
|
||||
# dip <port>... stop forwarding those ports
|
||||
# lip list active forwards
|
||||
fip() {
|
||||
(( $# < 2 )) && echo "Usage: fip <host> <port1> [port2] ..." && return 1
|
||||
local host="$1"
|
||||
shift
|
||||
for port in "$@"; do
|
||||
ssh -f -N -L "${port}:localhost:${port}" "$host" && echo "Forwarding localhost:$port -> $host:$port"
|
||||
done
|
||||
}
|
||||
|
||||
dip() {
|
||||
(( $# == 0 )) && echo "Usage: dip <port1> [port2] ..." && return 1
|
||||
for port in "$@"; do
|
||||
pkill -f "ssh.*-L ${port}:localhost:${port}" && echo "Stopped forwarding port $port" || echo "No forwarding on port $port"
|
||||
done
|
||||
}
|
||||
|
||||
lip() {
|
||||
pgrep -af "ssh.*-L [0-9]+:localhost:[0-9]+" || echo "No active forwards"
|
||||
}
|
||||
|
||||
# Git worktrees
|
||||
# ga <branch> create ../<repo>--<branch> on a new branch and cd into it
|
||||
# gd from inside that worktree, remove it and its branch
|
||||
ga() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Usage: ga [branch name]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local branch="$1"
|
||||
local base="$(basename "$PWD")"
|
||||
local wt_path="../${base}--${branch}"
|
||||
|
||||
git worktree add -b "$branch" "$wt_path" || return 1
|
||||
command -v mise &> /dev/null && mise trust "$wt_path"
|
||||
cd "$wt_path"
|
||||
}
|
||||
|
||||
gd() {
|
||||
local cwd base branch root worktree answer
|
||||
|
||||
cwd="$(pwd)"
|
||||
worktree="$(basename "$cwd")"
|
||||
|
||||
# split on first `--`
|
||||
root="${worktree%%--*}"
|
||||
branch="${worktree#*--}"
|
||||
|
||||
# Protect against accidentally nuking a non-worktree directory
|
||||
if [[ "$root" == "$worktree" ]]; then
|
||||
echo "Not in a worktree made by ga (expected a <repo>--<branch> directory)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
read -rp "Remove worktree $worktree and branch $branch? [y/N] " answer
|
||||
[[ $answer == [yY]* ]] || return 0
|
||||
|
||||
cd "../$root"
|
||||
git worktree remove "$cwd" --force || return 1
|
||||
git branch -D "$branch"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Hook CoreDesktop's shell setup (prompt, zoxide, fzf key bindings,
|
||||
# aliases and functions in shell/) into ~/.bashrc
|
||||
|
||||
LINE='[[ -f "$HOME/.local/share/coredesktop/shell/bashrc" ]] && source "$HOME/.local/share/coredesktop/shell/bashrc"'
|
||||
|
||||
if grep -qF "$LINE" ~/.bashrc 2>/dev/null; then
|
||||
echo "CoreDesktop shell setup already in .bashrc"
|
||||
else
|
||||
echo "$LINE" >> ~/.bashrc
|
||||
echo "CoreDesktop shell setup added to .bashrc"
|
||||
fi
|
||||
@@ -0,0 +1,32 @@
|
||||
add_newline = true
|
||||
command_timeout = 200
|
||||
format = "[$directory$git_branch$git_status]($style)$character"
|
||||
|
||||
[character]
|
||||
error_symbol = "[✗](bold cyan)"
|
||||
success_symbol = "[❯](bold cyan)"
|
||||
|
||||
[directory]
|
||||
truncation_length = 2
|
||||
truncation_symbol = "…/"
|
||||
repo_root_style = "bold cyan"
|
||||
repo_root_format = "[$repo_root]($repo_root_style)[$path]($style)[$read_only]($read_only_style) "
|
||||
|
||||
[git_branch]
|
||||
format = "[$branch]($style) "
|
||||
style = "italic cyan"
|
||||
|
||||
[git_status]
|
||||
format = '[$all_status]($style)'
|
||||
style = "cyan"
|
||||
ahead = "⇡${count} "
|
||||
diverged = "⇕⇡${ahead_count}⇣${behind_count} "
|
||||
behind = "⇣${count} "
|
||||
conflicted = " "
|
||||
up_to_date = " "
|
||||
untracked = "? "
|
||||
modified = " "
|
||||
stashed = ""
|
||||
staged = ""
|
||||
renamed = ""
|
||||
deleted = ""
|
||||
@@ -60,8 +60,9 @@ Existing coredesktop hooks use a numeric prefix to control execution order:
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------|-----------------------------------------|
|
||||
| `00-rename-migration.sh` | Legacy command renames |
|
||||
| `09-snapshot.sh` | Snapper snapshot of / (btrfs only) |
|
||||
| `10-pacman.sh` | Arch system update |
|
||||
| `12-migrations.sh` | One-time migrations from `migrations/` |
|
||||
| `15-services.sh` | Enable new systemd services |
|
||||
| `20-aur.sh` | AUR packages |
|
||||
| `30-flatpak.sh` | Flatpak apps |
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : System defaults adapted from Omarchy: SSH keepalives, a gentler
|
||||
# login lockout, faster shutdown, out-of-memory protection, faster
|
||||
# boot, and a PATH for commands run over SSH
|
||||
|
||||
set -e
|
||||
|
||||
# SSH client: notice a dropped connection within a minute instead of hanging
|
||||
# until TCP gives up. Settings in ~/.ssh/config still win per host.
|
||||
echo "Configuring SSH keepalives..."
|
||||
sudo install -d -m 755 /etc/ssh/ssh_config.d
|
||||
sudo tee /etc/ssh/ssh_config.d/20-coredesktop-keepalive.conf > /dev/null << 'EOF'
|
||||
# CoreDesktop: notice dropped connections quickly instead of hanging until TCP
|
||||
# times out. Settings in ~/.ssh/config take precedence over these defaults.
|
||||
Host *
|
||||
ServerAliveInterval 15
|
||||
ServerAliveCountMax 3
|
||||
ConnectTimeout 10
|
||||
EOF
|
||||
|
||||
# Login lockout: Arch locks an account for 10 minutes after 3 wrong passwords.
|
||||
# Allow 10 tries and unlock after 2 minutes.
|
||||
echo "Relaxing the failed-login lockout..."
|
||||
sudo sed -i -E \
|
||||
-e 's/^#?[[:space:]]*deny[[:space:]]*=.*/deny = 10/' \
|
||||
-e 's/^#?[[:space:]]*unlock_time[[:space:]]*=.*/unlock_time = 120/' \
|
||||
/etc/security/faillock.conf
|
||||
|
||||
# Shutdown: don't wait 90 seconds on a service or app that won't stop
|
||||
echo "Shortening the shutdown timeout..."
|
||||
sudo install -d -m 755 /etc/systemd/system.conf.d /etc/systemd/user.conf.d
|
||||
printf '[Manager]\nDefaultTimeoutStopSec=10s\n' \
|
||||
| sudo tee /etc/systemd/system.conf.d/10-coredesktop-timeout.conf > /dev/null
|
||||
printf '[Manager]\nDefaultTimeoutStopSec=10s\n' \
|
||||
| sudo tee /etc/systemd/user.conf.d/10-coredesktop-timeout.conf > /dev/null
|
||||
|
||||
# Out of memory: let systemd-oomd kill the app causing memory pressure instead
|
||||
# of the whole session freezing. GNOME launches apps into app.slice, so GNOME
|
||||
# Shell itself is never a candidate.
|
||||
echo "Enabling out-of-memory protection..."
|
||||
sudo install -d -m 755 /etc/systemd/user/app.slice.d
|
||||
sudo tee /etc/systemd/user/app.slice.d/10-coredesktop-oomd.conf > /dev/null << 'EOF'
|
||||
[Slice]
|
||||
ManagedOOMMemoryPressure=kill
|
||||
ManagedOOMSwap=kill
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now systemd-oomd.service
|
||||
|
||||
# Boot: nothing on the desktop needs to wait for the network to come up
|
||||
echo "Masking NetworkManager-wait-online..."
|
||||
sudo systemctl mask NetworkManager-wait-online.service
|
||||
|
||||
# `ssh host command` runs without a login shell, so ~/.bashrc never sets PATH
|
||||
# and tools in ~/.local/bin or installed with mise aren't found. PAM sets the
|
||||
# environment for every login, including those. @{HOME} expands per user.
|
||||
if ! grep -qE '^PATH[[:space:]]' /etc/security/pam_env.conf; then
|
||||
echo "Adding user tool paths for SSH commands..."
|
||||
sudo tee -a /etc/security/pam_env.conf > /dev/null << 'EOF'
|
||||
|
||||
# CoreDesktop: give SSH commands and other non-shell logins the user-level tool paths
|
||||
PATH DEFAULT=/usr/local/sbin:/usr/local/bin:/usr/bin:@{HOME}/.local/share/mise/shims:@{HOME}/.local/bin
|
||||
EOF
|
||||
fi
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Turn on the ufw firewall. Incoming connections are blocked except
|
||||
# for the services CoreDesktop runs, and ufw-docker stops ports
|
||||
# published by Docker containers from getting around the firewall.
|
||||
|
||||
set -e
|
||||
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
install_packages ufw ufw-docker
|
||||
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
|
||||
sudo ufw allow 22/tcp comment 'SSH'
|
||||
sudo ufw allow 5353/udp comment 'mDNS'
|
||||
sudo ufw allow 53317 comment 'LocalSend'
|
||||
sudo ufw allow in on tailscale0 comment 'Tailscale'
|
||||
|
||||
sudo ufw --force enable
|
||||
sudo systemctl enable ufw.service
|
||||
|
||||
# ufw-docker only installs its rules while ufw is active, and they take effect
|
||||
# once ufw restarts
|
||||
if ! sudo grep -q 'BEGIN UFW AND DOCKER' /etc/ufw/after.rules; then
|
||||
sudo ufw-docker install
|
||||
sudo systemctl restart ufw.service
|
||||
fi
|
||||
|
||||
sudo ufw status verbose
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Install NVIDIA's driver when the machine has an NVIDIA GPU and no
|
||||
# NVIDIA driver yet (i.e. archinstall's proprietary option wasn't
|
||||
# picked). Turing (GTX 16xx / RTX 20xx) and newer get the open kernel
|
||||
# modules; Maxwell, Pascal and Volta get the 580xx legacy driver from
|
||||
# the AUR. Older cards stay on nouveau.
|
||||
#
|
||||
# Run from install.sh only, never from an update: silently moving a
|
||||
# working machine off nouveau is too risky to do mid-update.
|
||||
|
||||
set -e
|
||||
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
# Read device IDs from sysfs: lspci needs pciutils and wakes suspended GPUs.
|
||||
# Turing is the first generation with GSP firmware (open modules) and the first
|
||||
# with device IDs at 0x1e00 or above; Maxwell starts at 0x1340.
|
||||
GPU=none
|
||||
for device in /sys/bus/pci/devices/*; do
|
||||
[[ $(< "$device/vendor") == 0x10de && $(< "$device/class") == 0x03* ]] || continue
|
||||
id=$(( $(< "$device/device") ))
|
||||
if (( id >= 0x1e00 )); then
|
||||
GPU=open
|
||||
elif (( id >= 0x1340 )) && [ "$GPU" = none ]; then
|
||||
GPU=legacy
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$GPU" = none ]; then
|
||||
echo "No NVIDIA GPU supported by the current drivers found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if is_installed nvidia-utils || is_installed nvidia-580xx-utils; then
|
||||
echo "NVIDIA driver already installed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# DKMS builds the module for every installed kernel, so each needs its headers
|
||||
PACKAGES=()
|
||||
for kernel in linux linux-lts linux-zen linux-hardened; do
|
||||
if is_installed "$kernel"; then
|
||||
PACKAGES+=("$kernel-headers")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$GPU" = open ]; then
|
||||
PACKAGES+=(nvidia-open-dkms nvidia-utils libva-nvidia-driver)
|
||||
else
|
||||
PACKAGES+=(nvidia-580xx-dkms nvidia-580xx-utils)
|
||||
fi
|
||||
|
||||
echo "Installing NVIDIA driver..."
|
||||
install_packages "${PACKAGES[@]}"
|
||||
|
||||
# Load the driver from the initramfs so the GPU is ready when GDM starts
|
||||
sudo install -d -m 755 /etc/mkinitcpio.conf.d
|
||||
echo 'MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)' \
|
||||
| sudo tee /etc/mkinitcpio.conf.d/nvidia.conf > /dev/null
|
||||
sudo mkinitcpio -P
|
||||
|
||||
# GDM only offers Wayland on NVIDIA when these are enabled, since without them
|
||||
# the GPU loses its memory contents across suspend
|
||||
sudo systemctl enable nvidia-suspend.service nvidia-hibernate.service nvidia-resume.service
|
||||
|
||||
echo "NVIDIA driver installed. Reboot to start using it."
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Configure Snapper so update can snapshot / before each upgrade
|
||||
# (updates.d/09-snapshot.sh). Only applies when / is btrfs, which is
|
||||
# archinstall's default. /home is a separate subvolume and is not
|
||||
# included in the snapshots.
|
||||
|
||||
if [ "$(findmnt -no FSTYPE /)" != "btrfs" ]; then
|
||||
echo "/ is not btrfs; skipping Snapper setup."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
install_packages snapper
|
||||
|
||||
if [ ! -f /etc/snapper/configs/root ]; then
|
||||
echo "Creating Snapper config for /..."
|
||||
|
||||
# create-config makes its own /.snapshots subvolume and fails if the path
|
||||
# already exists. archinstall mounts a separate @.snapshots subvolume there,
|
||||
# so follow the Arch wiki: unmount it, let snapper create its config, then
|
||||
# swap snapper's nested subvolume back out for the @.snapshots mount.
|
||||
if mountpoint -q /.snapshots; then
|
||||
sudo umount /.snapshots
|
||||
sudo rmdir /.snapshots
|
||||
sudo snapper -c root create-config /
|
||||
sudo btrfs subvolume delete /.snapshots
|
||||
sudo mkdir /.snapshots
|
||||
sudo mount /.snapshots
|
||||
else
|
||||
if [ -e /.snapshots ] && ! sudo rmdir /.snapshots 2>/dev/null; then
|
||||
echo "/.snapshots exists and isn't an empty directory. Move it aside and run this again."
|
||||
exit 1
|
||||
fi
|
||||
sudo snapper -c root create-config /
|
||||
fi
|
||||
|
||||
# Keep only the last 5 pre-update snapshots, and no hourly timeline. Only set
|
||||
# on a config we created, so a config you made yourself keeps its settings.
|
||||
sudo snapper -c root set-config \
|
||||
TIMELINE_CREATE=no \
|
||||
NUMBER_CLEANUP=yes \
|
||||
NUMBER_MIN_AGE=0 \
|
||||
NUMBER_LIMIT=5 \
|
||||
NUMBER_LIMIT_IMPORTANT=5
|
||||
sudo systemctl disable --now snapper-timeline.timer 2> /dev/null || true
|
||||
else
|
||||
echo "Snapper config for / already exists."
|
||||
fi
|
||||
|
||||
sudo systemctl enable --now snapper-cleanup.timer
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Install the Vulkan driver for each Intel or AMD GPU in the machine.
|
||||
# NVIDIA's Vulkan driver comes with nvidia-utils (see nvidia.sh).
|
||||
|
||||
set -e
|
||||
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
# Read vendor IDs from sysfs: lspci needs pciutils and wakes suspended GPUs
|
||||
PACKAGES=()
|
||||
for device in /sys/bus/pci/devices/*; do
|
||||
[[ $(< "$device/class") == 0x03* ]] || continue
|
||||
case "$(< "$device/vendor")" in
|
||||
0x8086) PACKAGES+=(vulkan-intel) ;;
|
||||
0x1002) PACKAGES+=(vulkan-radeon) ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( ${#PACKAGES[@]} > 0 )); then
|
||||
mapfile -t PACKAGES < <(printf '%s\n' "${PACKAGES[@]}" | sort -u)
|
||||
install_packages "${PACKAGES[@]}"
|
||||
else
|
||||
echo "No Intel or AMD GPU found."
|
||||
fi
|
||||
@@ -48,6 +48,16 @@ if [[ -z "$UPDATE_REEXECED" ]]; then
|
||||
exec ~/.local/bin/update
|
||||
fi
|
||||
|
||||
# An upgrade that runs out of disk space part way through can leave the system
|
||||
# half-upgraded. Set UPDATE_FORCE=1 to skip this check.
|
||||
MIN_FREE_GIB=10
|
||||
FREE_KIB="$(df -k --output=avail / | tail -n 1 | tr -d ' ')"
|
||||
if [[ -z "$UPDATE_FORCE" && "$FREE_KIB" =~ ^[0-9]+$ ]] && (( FREE_KIB < MIN_FREE_GIB * 1024 * 1024 )); then
|
||||
echo "Only $(( FREE_KIB / 1024 / 1024 )) GiB free on /; updating needs at least $MIN_FREE_GIB GiB."
|
||||
echo "Free up space (sudo paccache -rk1 clears old cached packages), or run: UPDATE_FORCE=1 update"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ask for the password once, then keep sudo's cached credentials fresh until
|
||||
# update exits, so long-running hooks don't stop for a password again.
|
||||
sudo -v || exit 1
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Snapshot / before the system update so a bad upgrade can be rolled back.
|
||||
# system/snapper.sh creates the "root" config on btrfs machines and keeps the
|
||||
# last 5 snapshots.
|
||||
|
||||
is_installed() {
|
||||
command -v snapper &>/dev/null && [ -f /etc/snapper/configs/root ]
|
||||
}
|
||||
|
||||
run_update() {
|
||||
echo "Snapshotting / before updating..."
|
||||
sudo snapper -c root create -c number -d "Before CoreDesktop update" \
|
||||
&& sudo snapper -c root cleanup number
|
||||
}
|
||||
+19
-1
@@ -6,12 +6,28 @@ source "$COREDESKTOP/utils.sh"
|
||||
source "$COREDESKTOP/packages.conf"
|
||||
source "$COREDESKTOP/remove-packages.conf"
|
||||
|
||||
STATUS=0
|
||||
|
||||
echo "Removing unwanted packages..."
|
||||
remove_packages "${REMOVE_PACMAN[@]}"
|
||||
remove_flatpaks "${REMOVE_FLATPAKS[@]}"
|
||||
|
||||
# A machine that hasn't updated in a while can have a keyring too old to verify
|
||||
# the new packages. Update it first; the -Su below completes this -Sy.
|
||||
echo "Updating Arch keyring..."
|
||||
sudo pacman -Sy --needed --noconfirm archlinux-keyring || STATUS=1
|
||||
|
||||
# script(1) keeps pacman's progress bars while logging its output for the
|
||||
# initramfs check
|
||||
echo "Updating Arch..."
|
||||
sudo pacman -Syu --noconfirm
|
||||
mkdir -p "$(dirname "$PACMAN_UPDATE_LOG")"
|
||||
: > "$PACMAN_UPDATE_LOG"
|
||||
sudo script -qefc "pacman -Su --noconfirm" "$PACMAN_UPDATE_LOG" || STATUS=1
|
||||
|
||||
if initramfs_build_failed; then
|
||||
echo -e "\e[31mRebuilding the initramfs failed. Don't reboot until it's fixed - see the output above or $PACMAN_UPDATE_LOG.\e[0m"
|
||||
STATUS=1
|
||||
fi
|
||||
|
||||
echo "Checking for new packages..."
|
||||
install_packages "${SYSTEM_UTILS[@]}"
|
||||
@@ -20,3 +36,5 @@ install_packages "${MAINTENANCE[@]}"
|
||||
install_packages "${DESKTOP[@]}"
|
||||
install_packages "${MEDIA[@]}"
|
||||
install_packages "${FONTS[@]}"
|
||||
|
||||
exit $STATUS
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run one-time changes from migrations/ that haven't run on this machine yet.
|
||||
# This is how machines installed before a change to install.sh catch up, so a
|
||||
# change that should reach existing machines needs a migration as well. To add
|
||||
# one, create migrations/$(date +%s).sh; it runs with bash, once, on success.
|
||||
#
|
||||
# Runs after 10-pacman.sh so migrations install packages against fresh
|
||||
# package databases.
|
||||
|
||||
COREDESKTOP="$HOME/.local/share/coredesktop"
|
||||
|
||||
source "$COREDESKTOP/utils.sh"
|
||||
|
||||
run_migrations
|
||||
@@ -8,3 +8,12 @@ if command -v paccache &>/dev/null; then
|
||||
sudo paccache -rk2
|
||||
sudo paccache -ruk0
|
||||
fi
|
||||
|
||||
# Report packages that were installed as dependencies and are no longer needed.
|
||||
# Not removed automatically: some may be tools you use directly.
|
||||
ORPHANS="$(pacman -Qtdq 2>/dev/null)"
|
||||
if [ -n "$ORPHANS" ]; then
|
||||
echo "Packages no longer needed by anything:"
|
||||
echo "$ORPHANS" | sed 's/^/ /'
|
||||
echo "To remove them: sudo pacman -Rns \$(pacman -Qtdq)"
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
if initramfs_build_failed; then
|
||||
echo -e "\e[31mDon't reboot yet: the initramfs failed to rebuild (see $PACMAN_UPDATE_LOG).\e[0m"
|
||||
# If the running kernel's modules are gone, a newer kernel was installed
|
||||
if [ ! -d "/usr/lib/modules/$(uname -r)" ]; then
|
||||
elif [ ! -d "/usr/lib/modules/$(uname -r)" ]; then
|
||||
echo "A newer kernel has been installed. Please reboot when convenient."
|
||||
fi
|
||||
|
||||
@@ -73,6 +73,40 @@ enable_services() {
|
||||
done
|
||||
}
|
||||
|
||||
# Run each script in migrations/ that hasn't run on this machine yet, oldest
|
||||
# first. A migration is recorded as done only when it succeeds, and the first
|
||||
# failure stops the run so a later migration never runs ahead of an earlier one.
|
||||
run_migrations() {
|
||||
local dir="${COREDESKTOP:-$HOME/.local/share/coredesktop}/migrations"
|
||||
local state="$HOME/.local/state/coredesktop/migrations"
|
||||
local file name
|
||||
|
||||
mkdir -p "$state"
|
||||
for file in "$dir"/*.sh; do
|
||||
[ -f "$file" ] || continue
|
||||
name="$(basename "$file")"
|
||||
[ -f "$state/$name" ] && continue
|
||||
|
||||
echo "Running migration $name..."
|
||||
if ! bash "$file"; then
|
||||
echo "Migration $name failed; it will run again on the next update."
|
||||
return 1
|
||||
fi
|
||||
touch "$state/$name"
|
||||
done
|
||||
}
|
||||
|
||||
# Output of the last update's pacman -Su, written by updates.d/10-pacman.sh
|
||||
PACMAN_UPDATE_LOG="$HOME/.local/state/coredesktop/pacman-update.log"
|
||||
|
||||
# True if the last update rebuilt the initramfs and mkinitcpio reported a
|
||||
# failure. Rebooting then can leave the machine unbootable.
|
||||
initramfs_build_failed() {
|
||||
[ -f "$PACMAN_UPDATE_LOG" ] || return 1
|
||||
grep -q "Updating linux initcpios" "$PACMAN_UPDATE_LOG" || return 1
|
||||
grep -q "==> ERROR" "$PACMAN_UPDATE_LOG" || ! grep -q "Image generation successful" "$PACMAN_UPDATE_LOG"
|
||||
}
|
||||
|
||||
# Install a script atomically (copy to a temp file, then rename over the target)
|
||||
# so a copy of it that is running right now keeps reading the old file
|
||||
install_script() {
|
||||
|
||||
Reference in New Issue
Block a user