epicartificials blog

My Arch Linux Setup 2022

19.6.2022

The most popular operating systems are Windows, MacOS and Linux. After going to university to study Software engineering I became interested in trying the Linux operating system. The main reason was the heavy use of WSL (Windows subsystem for Linux) which was sufficient to finish all the school assignments, but there came a point where I spent more time in WSL then in Windows.

Introduction

After deciding to install Linux as a dualboot I looked at the available Linux distributions. From using RaspberryPi computers, which use Debian as an operating system, I started using their cousin Ubuntu. On Ubuntu I became familiar with Gnome, theming and ricing. I also started watching YouTube videos related to Linux customisation and was introduced to not only different Linux distributions, but also different display mangers.

The Linux distribution basically packages a base operating system (kernel), all additional applications, drivers, etc. The display managers dictate how to display the information to the user and how they can use the system.

As I mentioned before, I started with Ubuntu and Gnome. I dont particularly like the Gnome feel as it looks plain and a little bit old. With extensive ricing I got it to the point where it looked similar to a more modern style, however I once again noticed, that I mainly spend time in the terminal launching tasks and navigating directories.

On YouTube I found a type of display managers called Tiling window manager as opposed to a Stacking window manager. The magic of a Tiling window manager is that it first opens the desired application in full-screen, then after opening another one the screen splits into two, so both apps then take half-screen, etc. Tiling window managers are heavily key-bind based, so the user rarely has to use the mouse to interact with the screen.

The first tiling window manager that I have tried was i3 which uses a dynamic layout where the user can specify if the next window opens to the right or below the current window. This gives me the most flexibility to structure my workflow.

After becoming used to i3 on the "frontend" I started to look at a better "backend". The problem with linux distributions for me comes to the package managers. First of all, Ubuntu is a point release, which means that its package manager apt and apt-get only installs stability fixes and security updates. It also uses flatpak which is like an online repository for user packages.

The next most popular Linux distribution is Arch linux. Arch comes installed with only the backend, so the user can choose what frontend to install for themselves. Arch is also a rolling release which means that every package gets updated regularely. Arch also has two separate package managers pacman and an AUR (Arch User Repository) store which allowes users to download packages from a central trusted place. The biggest benefit is the ArchWiki which contains detailed, regularely updated and very useful guides to nearly everyting there is to use on Arch.

Disk Partitions

I am using a DELL Inspiron 15 7000 laptop, with 512GB SSD and 1TB HDD. With this setup I have to logically structure the available disk space. The partition structure that I ended up with and I find the most comfortable is the following:

SSD

EFI boot Windows C: (NTFS) Windows D: (NTFS)
500 MB 250 GB 200 GB

HDD

Linux / (ext4) Linux /home (ext4) Linux swap Windows G: (NTFS)
100 GB 60 GB 3 GB 400 GB

My partition logic is the following:

Apps

From using the arch linux daily for some years now I have tried many apps and tools for the tasks that I do day-to-day. In the following list I would like to list the apps that are essential for me as a programmer.

Essentials

Text editors

Programming

Other

File structure

Filesystem Hierarchy Standard

Linux uses the Filesystem Hierarchy Standard which categorieses types of files and common use-cases and designates them standardised locations on the system.

/ - primary directory containing everyting on the system /bin - essential command binaries that need to be available in single user mode; for all users, e.g., cat, ls, cp /boot - boot loader files, e.g., kernels, initrd, grub. /dev - device files, e.g., /dev/null, /dev/disk0, /dev/sda1, /dev/tty, /dev/random. /etc - host-specific system-wide configuration files. /home - users' home directories, containing saved files, personal settings, etc. /lib - libraries essential for the binaries in /bin and /sbin. /media - mount points for removable media such as CD-ROMs (appeared in FHS-2.3). /mnt - temporarily mounted filesystems. Temporary mount directory where sysadmins can mount filesystems. /opt - optional application software packages. Contains add-on applications from individual vendors. /proc - virtual filesystem providing process and kernel information as files. In Linux, corresponds to a procfs mount. Generally automatically generated and populated by the system, on the fly. /root - home directory of the root user /sbin - essential system binaries that are available to the system administrators, e.g., fsck, init, route. /srv - site-specific data served by this system, such as data and scripts for web servers, data offered by FTP servers, and repositories for version control systems. /tmp - temporary files. Often not preserved between system reboots, and may be severely size restricted. /usr - secondary hierarchy for read-only user data; contains the majority of (multi-)user utilities and applications. /var - variable files: files whose content is expected to continually change during normal operation of the system, such as logs, spool files, and temporary e-mail files.

Base Directory Specification

For use specific data there exists a standard called a Base Directory Specification which defines standard locations where user-specific files are located. These locations are customisable by environment variables.

XDG_DATA_HOME - For user application's own data files (default $HOME/.local/share) XDG_CONFIG_HOME - For user's app configuration files (default $HOME/.config) XDG_STATE_HOME - For user-specific app session data, which should be stored for future reuse (default $HOME/.local/state) XDG_CACHE_HOME - For user-specific apps cache files (default $HOME/.cache) XDG_RUNTIME_DIR - For user-specific app runtime files like sockets which may survive reboot and logout cycles

A user home directory typically also contains folders such as Documents, Downloads, etc. These folders can be also customized using the XDG user directories which provides a command

$ xdg-user-dirs-update

which generates a file ~/.config/user-dirs.dirs and updates the following variables

XDG_DESKTOP_DIR - for files placed on user's desktop (default $HOME/Desktop) XDG_DOCUMENTS_DIR - for user's personal documents (default $HOME/Documents) XDG_DOWNLOAD_DIR - for files downloaded from the internet (default $HOME/Downloads) XDG_MUSIC_DIR - for user's music files (default $HOME/Music) XDG_PICTURES_DIR - for user's prictures (default $HOME/Pictures) XDG_PUBLICSHARE_DIR - for files that other users can access (default $HOME/Public) XDG_TEMPLATES_DIR - templates to use when creating a new file (default $HOME/Templates) XDG_VIDEOS_DIR - for user's videos (default $HOME/Videos)

Note that not all applications support the XDG user directory specification. Arch linux tracks these apps and sometimes also offers fixes on how to make the app comply with the specification https://wiki.archlinux.org/title/XDG_Base_Directory

Windows disk mounting

As I mentioned before, I store my user data on the Windows D: drive. This allows me to access the data from both Linux and Windows. To permanently mount the disk D: to Linux we need to first turn off Fast startup in WIndows because allows Windows to lock disk partitions as read-only and we can't modify them from Linux. So by unchecking the checkbox at Control Panel > Power Options > Choose what the power buttons do > Change settings that are currently unavailable > Turn on fast startup (recommended)

To mount a NTFS partition from Linux the de-facto standard is to use ntfs-3g implementation, however a new kernel-level implementation called ntfs3 is on the rise.

To mount the windows disk partition first create a user folder in the /media directory. So for user tomas create a directory /media/tomas/ and set appropriate permissions to the directroy. To mount the Windows D: partition lets create a folder /media/tomas/d/.

To mount the drive we first need to find its UUID, we can list the partitions with commands fdisk -l, lsblk and blkid. Then we can add an entry into /etc/fstab

# <file system> <dir> <type> <options> <dump> <pass>
# /dev/nvme0n1p4
UUID=484480604480531C    /media/tomas/d    ntfs3  defaults   0 0

This will mount the NTFS partition with proper permissions.

Dotfiles

Linux denotes hidden files with a dot for example .bashrc, .config/, .profile, etc. These are configuration files that the "common" user has not interest in. After using a lot of packages the home directory can become very cluttered and thats where the XDG user directories come in to standardise the file locations. This means that most of the configuration files would go to the .config directory.

.bashrc

.bashrc is a Bash shell script that Bash runs whenever it is started interactively. It initializes an interactive shell session. You can put any command in that file that you could type at the command prompt.

shopt

First we can set shopt (shell options) parameters. The one I really like is autocd which can execute a command as if it was a cd parameter

shopt -s autocd

PS1

Then we can set the visual feel of the of the console. By setting the PS1 variable, we set the shell prompt to look like [folder]$. With dircolors we can set custom colors in commands lie ls

export PS1="[\[$(tput sgr0)\]\[\033[38;5;33m\]\W\[$(tput sgr0)\]]\[$(tput sgr0)\]\[\033[38;5;33m\]\\$\[$(tput sgr0)\] \[$(tput sgr0)\]"

eval "$(dircolors -p | \
    sed 's/ 4[0-9];/ 01;/; s/;4[0-9];/;01;/g; s/;4[0-9] /;01 /' | \
    dircolors /dev/stdin)"

extensions

Sometimes we need to configure or add parameters to the commands. For this we can use environment variables and aliases. We declare these variables in .bashrc file. To no clutter the .bashrc file we can split these into ~/.config/aliasrc and ~/.config/envvarrc then we can source them inside the .bashrc

[ -f "$XDG_CONFIG_HOME/envvarrc" ] && source "$XDG_CONFIG_HOME/envvarrc"

[ -f "$XDG_CONFIG_HOME/aliasrc" ] && source "$XDG_CONFIG_HOME/aliasrc"

shared history

Sometimes it can be annoying trying to find a previous command from the terminal only to find out that it was overriden by another terminal that we have opened later. Using the following commands we can enable histroy sharing between terminals

shopt -s histappend
export HISTCONTROL=ignoredups:erasedups
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

.config/aliasrc

In this file I place all the aliases that I use on the system. I split these into categories of shortcuts, default arguments, redirections and colors.

#!/bin/bash

# shortcuts
alias e="emacs --no-window-system" \
      v="vim"


# default arguments
alias valgrid="valgrid --leak-check=full --track-origins=yes --show-reachable=yes"
alias ls="ls -A -hN --group-directories-first"
alias mvn="mvn -gs \"$XDG_CONFIG_HOME/maven/settings.xml\""
alias yarn='yarn --use-yarnrc "$XDG_CONFIG_HOME/yarn/config"'
alias sxiv="sxiv -a"
alias teams="teams --disable-seccomp-filter-sandbox"


# substitutions 
command -v nvim >/dev/null && alias vim="nvim" vimdiff="nvim -d"


# colors
alias ls="${BASH_ALIASES[ls]} --color=auto"
alias grep="grep --color=auto"
alias diff="diff --color=auto"


# enable aliases with sudo
alias sudo="sudo "

.config/envvarrc

In this file I place all the environment variables. Mainly the XDG fixes defined in the XDG user directories Wiki Page.

CDPATH

To quickly access common places on my system such as my data folder in /media/tomas/d/ I use the CDPATH environment variable. This variable tells cd what directories to search. To support tab completion I use the package called bash-completion.

#!/bin/bash

# XDG variables
# ...

# extend cd paths
export CDPATH=".:/media/${USER}"

.profile

This file is source on startup. Bash sources .bash_profile so we source .profile from that file. In this file I define the user preferred files like a terminal, editor and browser

export TERMINAL="xterm"
export EDITOR="vim"
export VISUAL="vim"
export BROWSER="firefox"

Here we can also load our Xorg configurations like Xresources and Xmodmap

xrdb -marge "$XDG_CONFIG_HOME/X11/Xresources"
xmodmap "$XDG_CONFIG_HOME/X11/Xmodmap"

.Xresources

Here we can configure the terminal "feel". Mailny the colors and fonts. To declutter the home directory, I have relocated the file into $XDG_CONFIG_HOME/X11/Xresources.

.Xmodmap

I am using the i3 window manager and I am using Mod1 (Alt) key as the action key for i3. Linux associates both the left Alt and the right "Alt Gr" keys to the Mod1 key. However "Alt Gr" key is often used as a Multi_Key for using diacritics and letter combinations. That is why I remapped the "Alt Gr" key from Mod1 to Multi_key. To declutter the home directory, I have relocated the file into `$XDG_CONFIG_HOME/X11/Xmodmap.

remove mod1 = Alt_R
keycode 108 = Alt_R
keysym Alt_R = Multi_key

.Xauthority

The .Xauthority file can be found in each user home directory and is used to store credentials in cookies used by xauth for authentication of X sessions. Once an X session is started, the cookie is used to authenticate connections to that specific display. To move the file into a differnet directory we have to set the $XAUTHORITY variable. To declutter the home directory, we have to set the variable to export XAUTHORITY="$XDG_CONFIG_HOME/X11/Xauthority"

Note that not all display managers accept the $XAUTHORITY vaiable and have hard-coded paths.

.config/git

git is an absolutely amazing version control tool. It allows us to track file changes with a very simple commands. Then we can upload our local git changes to cloud servers like GitHub or Gitlab. These online clouds usually require some form of authentication, weather it is an username and password or a token.

If we dont want to remebemr the passwords, git offers various solutions to store these credentials. To store only the usernames and passwords we can use a git Credential Helper.

git config --global credential.helper 'store --file=$XDG_CONFIG_HOME/git/credentials'

We can also move .gitconfig to XDG_CONFIG_HOME/git/config as it is an XDG-compliant alternative

.config/i3

As I mentioned in the introduction, i3 is my window manager of choice, more specifically the i3-gaps extension. i3 is a tiling window manager designed for X11, inspired by wmii and written in C. It supports tiling, stacking, and tabbing layouts, which it handles dynamically.

i3-gaps

The best feature for me is the dynamic aspect of tiling windows. I havent spent much time with the static tiling window managers, but after getting used to the dynamic layout it is very hard to imagine using anything else.

Instead of making compile-time changes by modifying the literal source code of the window manager i3 uses a configuration file located in $XDG_CONFIG_HOME/i3/config.

I structure the configuration file into the following sections: Basic configuration, Basic bindings, Letter key bindings, Workspace names, Workspace switching, Moving windows to workspaces, App autostart, Default settings, Function keys, Special modes

Basic configuration

In this section we set the global variables. For command combinations I use Mod1 (Alt) rather then Mod4 (Win key). I find the Alt key position more natural but it also takes precedence over Alt shortcuts inside various applications like Intellij IDEA.

workspace_auto_back_and_forth yes

gaps inner 15
gaps outer 15
smart_gaps on
smart_borders on

set $mod Mod1

for_window [class="^.*"] border pixel 3

# class        border  backgr. text    indicator child_border
client.focused #555555 #555555 #ffffff #4361ee   #4895EF

Basic bindings

This section binds special non-letter keys. I use evironment variables to not hardcode the preferred default apps.

bindsym $mod+Return         exec --no-startup-id $TERMINAL
bindsym $mod+Shift+Return   exec --no-startup-id samedir

bindsym $mod+Shift+space    floating toggle
bindsym $mod+space          focus mode_toggle

bindsym $mod+F2             exec --no-startup-id $BROWSER

bindsym Print               exec i3-scrot
bindsym --release Shift+Print   exec i3-scrot -s

Letter key bindings

This section binds letter controls. There is some duplications as I support both the arrow keys and the vim (hjkl) navigation.

bindsym $mod+Shift+q        [con_id="__focused__" instance="^(?!dropdown_).*$"] kill

bindsym $mod+r              mode "resize"
bindsym $mod+Shift+r        restart

bindsym $mod+t              split toggle
bindsym $mod+Shift+t        gaps inner current set 15; gaps outer current set 15

bindsym $mod+s              sticky toggle

bindsym $mod+g              gaps inner current plus 5
bindsym $mod+Shift+g        gaps inner current minus 5

bindsym $mod+d              exec --no-startup-id $HOME/.local/bin/dmenu_run_history
bindsym $mod+Shift+d        gaps inner current set 0; gaps outer current set 0

bindsym $mod+f              fullscreen toggle

bindsym $mod+h              focus left
bindsym $mod+Shift+h        move left 30
bindsym $mod+Ctrl+h         move workspace to output left

bindsym $mod+j              focus down
bindsym $mod+Shift+j        move down 30
bindsym $mod+Ctrl+j         move workspace to output down

bindsym $mod+k              focus up
bindsym $mod+Shift+k        move up 30
bindsym $mod+Ctrl+k         move workspace to output up

bindsym $mod+l              focus right
bindsym $mod+Shift+l        move right 30
bindsym $mod+Ctrl+l         move workspace to output right

bindsym $mod+Left           focus left
bindsym $mod+Shift+Left     move left 30
bindsym $mod+Ctrl+Left      move workspace to output left

bindsym $mod+Down           focus down
bindsym $mod+Shift+Down     move down 30
bindsym $mod+Ctrl+Down      move workspace to output down

bindsym $mod+Up             focus up
bindsym $mod+Shift+Up       move up 30
bindsym $mod+Ctrl+Up        move workspace to output up

bindsym $mod+Right          focus right
bindsym $mod+Shift+Right    move right 30
bindsym $mod+Ctrl+Right     move workspace to output right

bindsym $mod+z              gaps outer current plus 5
bindsym $mod+Shift+z        gaps outer current minus 5

Workspaces

This section handles workspaces and moving things between them

# ^v^v^v^ [ Workspace names ] ^V^V^V^ #
set $ws1 "1"
set $ws2 "2"
set $ws3 "3"
set $ws4 "4"
set $ws5 "5"
set $ws6 "6"
set $ws7 "7"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10"

# ^v^v^v^ [ Switch to workspace ] ^V^V^V^ #
bindsym $mod+1      workspace $ws1
bindsym $mod+2      workspace $ws2
bindsym $mod+3      workspace $ws3
bindsym $mod+4      workspace $ws4
bindsym $mod+5      workspace $ws5
bindsym $mod+6      workspace $ws6
bindsym $mod+7      workspace $ws7
bindsym $mod+8      workspace $ws8
bindsym $mod+9      workspace $ws9
bindsym $mod+0      workspace $ws10

# ^v^v^v^ [ Move focused window to workspace ] ^V^V^V^ #
bindsym $mod+Shift+1    move container to workspace $ws1
bindsym $mod+Shift+2    move container to workspace $ws2
bindsym $mod+Shift+3    move container to workspace $ws3
bindsym $mod+Shift+4    move container to workspace $ws4
bindsym $mod+Shift+5    move container to workspace $ws5
bindsym $mod+Shift+6    move container to workspace $ws6
bindsym $mod+Shift+7    move container to workspace $ws7
bindsym $mod+Shift+8    move container to workspace $ws8
bindsym $mod+Shift+9    move container to workspace $ws9
bindsym $mod+Shift+0    move container to workspace $ws10

Autostart

In this section I define all the apps I want to run on startup. From the Apps section you probably already know what these apps do.

exec        --no-startup-id     nm-applet
exec_always --no-startup-id     nitrogen --restore
exec_always --no-startup-id     $HOME/.config/polybar/launch.sh
exec        --no-startup-id     i3-battery-popup -n -t 1m

Function keys

By default, some function keys do not work out of the box. In this section I define the way to handle audio (F1, F2, F3) and brightness keys (F11, F12)

bindsym XF86AudioRaiseVolume    exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
bindsym XF86AudioLowerVolume    exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status
bindsym XF86AudioMute           exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status
bindsym XF86AudioMicMute        exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status

bindsym XF86MonBrightnessUp     exec --no-startup-id xbacklight +5
bindsym XF86MonBrightnessDown   exec --no-startup-id xbacklight -5

Binding Modes

i3 supports being in different binding modes where we can bind keys only for that mode. For example I have a resize mode in which I rebind the arrow keys to resize the active window.

mode "resize" {
    # These bindings trigger as soon as you enter the resize mode

    bindsym j resize shrink width 10 px or 10 ppt
    bindsym k resize grow height 10 px or 10 ppt
    bindsym l resize shrink height 10 px or 10 ppt
    bindsym semicolon resize grow width 10 px or 10 ppt

    # same bindings, but for the arrow keys
    bindsym Left resize shrink width 10 px or 10 ppt
    bindsym Down resize grow height 10 px or 10 ppt
    bindsym Up resize shrink height 10 px or 10 ppt
    bindsym Right resize grow width 10 px or 10 ppt

    # back to normal: Enter or Escape or $mod+r
    bindsym Return mode "default"
    bindsym Escape mode "default"
    bindsym $mod+r mode "default"
}

.config/polybar

A window manager comes with only a way to manage windows. To give the user a context of what workspace he is on, what is his battery level, etc. he needs to use a status bar. By default i3 comes with a status bar called i3-status which is purely text-based.

Polybar aims to help users build beautiful and highly customizable status bars for their desktop environment, without the need of having a black belt in shell scripting. Polybar is a great, highly extensible status bar. It has a really nice feel, especially when using emojis.

Polybar

Polybar uses a simple configuration file located in $XDG_CONFIG_HOME/polybar/config.ini. I use the following configuration:

colors

[colors]
background = #282A2E
background-alt = #373B41
foreground = #C5C8C6
primary = #F0C674
secondary = #8ABEB7
alert = #A54242
disabled = #707880

bottom/bar

In this section I create a bottom status bar and I specify the fonts to use in order of imporance and the module strucutre

[bar/bottom]
bottom = true
width = 100%
height = 24pt
radius = 6

background = ${colors.background}
foreground = ${colors.foreground}

line-size = 3pt

padding-left = 0
padding-right = 1
module-margin = 1

cursor-click = pointer
cursor-scroll = ns-resize

enable-ipc = true

tray-position = right
wm-restack = i3

font-0 = "monospace;2"
font-1 = NotoSans-Regular:size=8;-1
font-2 = MaterialIcons:size=10;0
font-3 = Termsynu:size=8:antialias=false;-2
font-4 = FontAwesome:size=10;0

modules-left = xworkspaces i3
modules-right = filesystem battery backlight pulseaudio wlan date

module/xworkspaces

This module displays i3 workspaces as neat buttons

[module/xworkspaces]
type = internal/xworkspaces

label-active = %name%
label-active-background = ${colors.background-alt}
label-active-underline= ${colors.primary}
label-active-padding = 1

label-occupied = %name%
label-occupied-padding = 1

label-urgent = %name%
label-urgent-background = ${colors.alert}
label-urgent-padding = 1

label-empty = %name%
label-empty-foreground = ${colors.disabled}
label-empty-padding = 1

module/i3

This module simply shows the active i3 mode

[module/i3]
type = internal/i3

format = <label-mode>
label-mode-padding = 1
label-mode-background = ${colors.background-alt}
label-mode-foreground = #F0C674

module/filesystem

This module shows the disk usage of the /home directory

[module/filesystem]
type = internal/fs
interval = 25

mount-0 = /home

label-mounted = %{F#F0C674}%mountpoint%%{F-} %percentage_used%%

label-unmounted = %mountpoint% not mounted
label-unmounted-foreground = ${colors.disabled}

module/battery

This module shows the battery icon and the percentage remaining. The battery is represented by an icon that slowly drains and changes color from white to orange then red.

[module/battery]
type = internal/battery
full-at = 98

format-charging = <animation-charging> <label-charging>
format-discharging = <ramp-capacity> <label-discharging>
format-full = <ramp-capacity> <label-full>

ramp-capacity-0 = 
ramp-capacity-0-foreground = #f53c3c
ramp-capacity-1 = 
ramp-capacity-1-foreground = #ffa900
ramp-capacity-2 = 
ramp-capacity-3 = 
ramp-capacity-4 = 

bar-capacity-width = 10
bar-capacity-format = %{+u}%{+o}%fill%%empty%%{-u}%{-o}
bar-capacity-fill = █
bar-capacity-fill-foreground = #ddffffff
bar-capacity-fill-font = 3
bar-capacity-empty = █
bar-capacity-empty-font = 3
bar-capacity-empty-foreground = #44ffffff

animation-charging-0 = 
animation-charging-1 = 
animation-charging-2 = 
animation-charging-3 = 
animation-charging-4 = 
animation-charging-framerate = 750

module/backlight

This module tracks the brightness of the screen and displays it as a percentage. Again the sun changes from full-bright to less and less bright as the brightness drops.

[module/backlight]
type = internal/xbacklight
format = <ramp> <label>

ramp-0 = 
ramp-1 = 
ramp-2 = 

module/pulseaudio

This module shows the current volume according to pulseaudio.

[module/pulseaudio]
type = internal/pulseaudio

format-volume = <ramp-volume> <label-volume>
label-muted =  muted
label-muted-foreground = #66

ramp-volume-0 = 
ramp-volume-1 = 
ramp-volume-2 = 
ramp-volume-3 = 

module/wlan

This module displays the current connected WiFi nettwork name.

[network-base]
type = internal/network
interval = 5
format-connected = <label-connected>
format-disconnected = <label-disconnected>
label-disconnected = %{F#F0C674}%ifname%%{F#707880} disconnected

[module/wlan]
inherit = network-base
interface-type = wireless
label-connected = %essid%

module/date

This module displays the current time. After clicking on the time it expands to show also the current date and seconds.

[module/date]
type = internal/date
interval = 1

date = %H:%M
date-alt = %d.%m.%Y %H:%M:%S

label = %date%
label-foreground = ${colors.primary}

backup on git

After tweaking the dotfiles for so long it would be a shame to lose all our progress, especially after so much time put into it. To create a backup we can create a bare repository.

git init --bare $XDG_DATA_HOME/dotfiles
cd $XDG_DATA_HOME/dotfiles
git config --local status.showUntrackedFiles no

Now we can setup an alias that makes our home directory act as a git repository. As mentioned previously, I store the alias inside the $XDG_CONFIG_HOME/aliasrc

alias config="git --git-dir=$XDG_DATA_HOME/dotfiles" --word-tree=$HOME"

Now we can happily use config add, config commit, config push instead of git add, git commit, git push and the changes will be made to our dotfiles repo.

Text Editors [TODO]

Text editors are a large part of a progammers life. Most of the time we spend reading (and sometimes writing) code. For this it is crutial to have good text editors. For some tasks it is easier to use a dedicated Integrated Development Environment (IDE) and for others just a plain text editor. The text editors are usually so customisable that they can essecially become a personalized IDE built for our specific needs.

When it comes to Linux there are mainly three options:

I usually have all installed and switch between them as I need; however, I would like to learn and gravitate towards the simpler options like emacs or VS code. The big difference between them is that emacs is mainly shortcut oriented with lots of key combinations while VS code has the more common workflow.

vim [TODO]

One of the most common terminal text editors is vim. Vim is a free and open-source, screen-based text editor program. It is an improved clone of vi. NeoVim is a vim fork focused on extensibility and usability with 30% less source-code than Vim.

As these programs share the common syntax we can reference vim to neovim so we share the same configuration. First in aliases I redirect the vim command to neovim.

command -v nvim >/dev/null && alias vim="nvim" vimdiff="nvim -d"

The configuration of vim can be found in $XDG_CONFIG_HOME/nvim/init.vim

set showmatch               " show matching 
set ignorecase              " case insensitive 
set mouse=v                 " middle-click paste with 
set hlsearch                " highlight search 
set incsearch               " incremental search
set tabstop=4               " number of columns occupied by a tab 
set softtabstop=4           " see multiple spaces as tabstops so <BS> does the right thing
set expandtab               " converts tabs to white space
set shiftwidth=4            " width for autoindents
set autoindent              " indent a new line the same amount as the line just typed
set relativenumber          " add line numbers
set wildmode=longest,list   " get bash-like tab completions
filetype plugin indent on   " allow auto-indenting depending on file type
syntax on                   " syntax highlighting
set mouse=a                 " enable mouse click
set clipboard=unnamedplus   " using system clipboard
filetype plugin on
set ttyfast                 " Speed up scrolling in Vim

emacs [TODO]

VS code [TODO]

Virtual Private Server [TODO]

Every tech-savy person wants to have a VPS on some point in time. Weather it is for hosting game servers, self-hosting various services or just experimenting with the technology. At least if not a VPS, then at least a personal website.

When I wanted to make my personal website, I bought a web hosting for about 33€/month while the domain only costed 11€/month. A VPS would cost about 52€/month. Having a spare Raspberry Pi at home, I have decided to use it as a personal VPS and expose the port 80 to the internet via the home router.

A good tutorial is the following guide: VPS Beginner guide

Setup the router [TODO]

Setup the Raspberry Pi [TODO]

Setup the database

On the RPi I want to use PostgreSQL as it is one of the most popular databases. Using the command below we can install PostgreSQL.

sudo apt-get install postgresql

To configure the databse we will switch to the postgres user and create a new user

$ sudo su postgres
$ createuser pi -P --interactive
Enter password for new role:
Enter it again:
Shall the new user be a superuser? (y/n) y

Setup web hosting

For the webhosting I want to use the basic LAPP (Linux, Apache, PostgreSQL, PHP). In the previous step we have installed PostgreSQL. Using the command below we can install Apache and PHP.

$ apt-get install apache2
$ apt-get install php libapache2-mod-php php-pgsql
$ systemctl restart apache2

In /etc/php/7.3/apache2/php.ini uncomment the line

extension=pdo_pgsql

On the website we want to expose multiple services with domains such as domain.com, git.domain.com, db.domain.com, etc. For each exposed webserver we will create a separate folder inside the /var/www folder. So we an create folders like domain.com, gogs, etc.

Setup a free domain

If you dont want to pay for your custom domain, but you are satified with a subdomain, you can pick one up for free at https://freedns.afraid.org/. It offers making a subdomain on domains like mooo.com, my.to, h4ck.me, 404.mn, play.ai, etc.

FreeDNS allows us to point the url to an ip address. If we dont have a static ip address we can use the Dynamic DNS which allows us to send our IP periodically from our server and the URL will reconfigure itself to point to that IP address.

To an active account on the FreeDNS we can send periodic updates to sign in. We can use the following two scripts from this repository: https://github.com/leemgs/auto-freedns-afraid-org.

The file /opt/free_dns/afraid-autoip.sh will automatically update the IP on the dynamic DNS

TOKEN_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxx"

WGET_OPTION="-q --read-timeout=0.0 --waitretry=5 --tries=400 --background"
wget ${WGET_OPTION} http://freedns.afraid.org/dynamic/update.php?${TOKEN_KEY}
sleep 5

The file /opt/free_dns/afraid-autologin.sh will sign in the user.

ID="[email protected]"
PASS="xxxxxxx"

URL="https://freedns.afraid.org/zc.php?/step=2&from=L3N1YmRvbWFpbi8=&action=auth&username=$ID&password=$PASS"
curl --silent --output /dev/null -I $URL

We can run these scripts periodically using chrontab

$ sudo vim /etc/crontab
30 * * * * root /opt/free_dns/afraid-autoip.sh
30 * * * * root /opt/free_dns/afraid-autologin.sh

Then just restart the cronjob with sudo service cron restart

Setup HTTPS

We will use SSL signed by https://letsencrypt.org/. To automatize the process we will use certbot.

apt install snap
snap install core
sudo snap refresh core
snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --apache

Every time we want to re-generate or add new SSL certificates we just run certbot --apache and follow the provided steps.

Setup git server

Setting up a git server on its own seems to be pretty easy. However I would prefer also a visual git server. Gogs is a self-hosted Git service. A very nice tutorial video can be found in https://www.youtube.com/watch?v=5ysGZoBJGVU.

Gogs

The first step is obviously to istall git.

$ apt-get install git

Then we need to create a user that will hold the repositories

$ createuser -m git

To istall Gogs copy the latest version from https://gogs.io/docs/installation/install_from_binary

$ cd /var/www/gogs
$ wget https://dl.gogs.io/0.12.9/gogs_0.12.9_linux_armv7.tar.gz
$ tar xzvf gogs_0.12.9_linux_armv7.tar.gz

$ chown -R www-data:www-data /var/www/gogs
$ chmod -R 755 /var/www/gogs

Now we have to create database for gogs by issuing the following commands.

$ su postgres
$ psql

postgres=# CREATE USER gogs WITH PASSWORD 'jw8s0F4';
CREATE ROLE

postgres=# CREATE DATABASE gogs OWNER gogs;
CREATE DATABASE

Now we need to configure apache to serve the gogs service under git.domain.com. To do this we need to create a new file /etc/apache2/sites-enabled/git.conf

<VirtualHost *:80>
    ServerAdmin webmaster@localhost

    ServerName git.domain.com

    ProxyPreseveHost On
    ProxyRequests Off
    ProxyPass / http://localhost:29418/
    ProxyPassReverse / http://localhost:29418/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirualHost>

To activate apache proxy run the following commands

$ a2enmod proxy
$ a2enmod proxy_http
$ a2enmod proxy_balancer
$ systemctl restart apache2

Before running the server create a config file /var/www/gogs/custom/config/app.ini

[server]
HTTP_ADDR      = 127.0.0.1
HTTP_PORT      = 29418
EXTERNAL_URL   = http://git.domain.com

To launch the script automatically create a service in vim /etc/systemd/system/gogs.service

[Unit]
Description=Gogs
After=syslog.target
After=network.target
After=mariadb.service mysqld.service postgresql.service memcached.service redis.service

[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
Type=simple
User=git
Group=git
WorkingDirectory=/var/www/gogs
ExecStart=/var/www/gogs/gogs web
Restart=always
Environment=USER=git HOME=/home/git

# Some distributions may not support these hardening directives. If you cannot start the service due
# to an unknown option, comment out the ones not supported by your version of systemd.
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Lastly, enable and start the service with

systemctl enable gogs.service
systemctl start gogs.service

After the successfull installation the Gogs service will be available under [git.domain.com]. As the last step after registering in the /var/www/gogs/custom/config/app.ini we can set DISABLE_REGISTRATION=true

Setup website projects \w git submodules

My personal website acts as my portfolio on which I present some of my projects. Each project is a totally separate project and with the introduction of Gogs git server on my hosting I have decided to have each project a separate git repository. However my website is also hosted on git ,this creates a git-inside-git scenario. To work with these nested gits submodules come to help.

Git submodules allows us to keep a Git repository as a subdirectory of another Git repository. This lets us clone another repository into our project and keep the commits separate.

Using this technique I can have a repository for my personal website and inside /public/ folder I have all the projects linkes as submodules.

Setup website auto-deploys with CI/CD

Since I am not very used to transfering files via FTP or SCP transfering files to the server usually takes me quite a long time. Now that I am using my own git server as well I can use my git repository as the upload destination. I found this handy tutorial Deploying My Site With Gogs that uses Gog's git hooks to copy the repository data to the webhosting location.

#!/bin/bash
git --work-tree=/var/www/domain.com/ --git-dir=/home/git/repositories/zloutek1/domain.com.git checkout -f

Because I am using submodules, things werent so simple. The command above works, however it does not pull the contents of the submodules so if we add a new suvmodule to the website it would just be an empty directory. We need to add a few lines to force the submodule download.

#!/bin/bash

set -e

ARGS="--work-tree=. --git-dir=/home/git/repositories/zloutek1/domain.com.git -C /var/www/domain.com/"
git ${ARGS} checkout -f
git ${ARGS} submodule foreach git pull origin main
git ${ARGS} submodule update --init --recursive

Setup Minecraft server

The best Minecraft server that I know of is papermc. To setup the server create a directory /srv/minecraft and set its permissions to your user.

mkdir /srv/minecraft
chown myuser:myuser /srv/minecraft

Download java 17.

$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk list java
================================================================================
Available Java Versions
================================================================================
Vendor   | Use | Version | Dist   | Status | Identifier
--------------------------------------------------------------------------------
Liberica |     | 17.0.1  | librca |        | 17.0.1-librca

$ sdk install java 17.0.1-librca

Install the latest server jar.

$ cd /srv/minecraft
$ wget https://api.papermc.io/v2/projects/paper/versions/1.19/builds/29/downloads/paper-1.19-29.jar
$ echo "java -Xms256M -Xmx496M -jar paper-1.19-29.jar nogui" > run.sh
$ chmod +x run.sh

Now you can start the server at any time with /srv/minecraft/run.sh

#Arch Linux #Arch #Raspberry Pi #dotfiles