Feb 20, 2020 - Artix Linux

Artix Linux

I’m pretty fed up with having to reinstall my deskop PC occassionally because my distribution moved to another major release version. And I’m pretty fed up with all the crappy quirks of systemd and how it’s spreading like an infection through the Linux system. That’s why I was looking for a distribution which tries to follow the KISS principle, the old school Linux principle that a tool does one job and does it well, and which has a rolling release system. So I ended up with Artix Linux, an Arch-based distribution, which you can have with openrc or runit init system. And I think it’s quite likely that’s gonna be my distribution of choice of many years to come.

But it will take me a while to get used it. I started with Suse, then had Fedora for a few years, after which a used several different Debian based distribution for many years, a short encounter with Gentoo in between, but I haven’t used an Arch based distribution yet.

The installation wasn’t as smooth as other distributions. For example I couldn’t set up an encrypted home partition in the installer. Well, I could, but then you I couldn’t boot up the installed system. So I ended up performing a very basic installation via the installer and then set up the specific requirements afterwards. Which wasn’t too bad. You find a lot of good documentation on Arch.

The heart of a Linux distribution is it’s software management system, which in this case is ‘pacman’. And it’s pretty cool! I’ve used it now for a couple weeks and it just works. No nasty surprises, no broken dependencies, etc. You find pretty much everything in the pacman repositories. And in the rare case you don’t, you’ll find it in the AUR, the arch user repository, from where you can install it from source. And in the very, very rare case you can’t even find it there, then just build it from source. With the help from pacman that’s so much easier than with most other distributions.

Lets start with the basics. I’ll probably add another post later covering the runit init system, I just have to get a bit more familiar with it myself.

Pacman basics

# System update:
pacman -Syu   # To force a full refresh of the package db: -Syyu and allow downgrade: -Syyuu

# Search for package:
pacman -Ss some_package  # search for installed packages: -Qs

# Get more info about package:
pacman -Si  # or -Qi for installed package

# List of all installed packages:
pacman -Ql

# Install package:
pacman -S some_package

# better: 
pacman -Syu some_package # to make sure system is up to date, otherwise packages might get out of sync

# install directly from file:
pacman -U some_package.tar.xz or
pacman -U https://example.org/some_package.tar.xz

# Remove:
pacman -R some_package 
#  or -Rsu to remove unnecessary deps too
#  or -Rc to remove all packages which depends on this package
#  add n to remove also config files

# Remove orphaned: 
pacman -Rs $(pacman -Qdtq)

# Clear cache:
pacman -Sc  # of no longer installed packages, add another c to clear all

Install from AUR

If you can’t find your software with pacman you most likely find it on the Arch User Repository.

Preparation: Install building tools and headers (equivalent to ‘build-essentials’ for Debian based distros); and create a ‘builds’ directory in your home directory:

pacman -Syu base-devel linux-headers
mkdir ~/builds

Then you can build AUR packages with

cd ~/builds
git clone https://aur.archlinux.org/some_package.git
cd some_package
# build some_package.tar.xz
makepkg -s 
# or build and install directly
makepkg -si

Jan 31, 2020 - Update A record for domain using OVH API

Update A record for domain using OVH API

I recently noticed that the external IP of my broadband connection doesn’t actually change very often, once every one or two months. So I figured I could just point one of my domains to my ‘home server’; no need to use a ‘dynamic DNS’ provider.

If you use the ‘Pong script’ which I posted earlier, then this Python script can update the A record of your domain’s nameserver to point to your current external IP address, given that you use the OVH nameservers. Just call it with a cron job.

Note: You need install python-ovh:

pip install python-ovh

And you need to generate API access keys for the script: https://eu.api.ovh.com/createToken/

For this step be careful to grant three permissions:

GET /domain/zone/<YOUR DOMAIN>/record
GET /domain/zone/<YOUR DOMAIN>/record/*
PUT /domain/zone/<YOUR DOMAIN>/record/*

And here’s the script:

import json
import ovh
import sys
import socket
import re


DOMAIN = "example.com"
OVH_ENDPOINT = "ovh-eu"
OVH_APP_KEY = ""
OVH_APP_SEC = ""
OVH_CON_KEY = ""

# Using https://floki.cc/2019/10/netcat_pong
# (adjust get_current_ip() method if you're using
# something else)
PONG_HOST = "External IP"
PONG_PORT = 12345


def get_current_ip():
    """
    Get the current external IP using the 'PONG_HOST'.
    :return: See above
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((PONG_HOST, PONG_PORT))
    data = s.recv(1024)
    s.close()
    new_ip = data.decode("utf-8").strip()
    if not re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$").match(new_ip):
        raise Exception("Could not get current IP")
    return new_ip

def get_current_arecord_ip(client):
    """
    Get the current IP and record ID which is set in the
    A record of the nameserver for the domain
    :param client: The OVH API client
    :return: (record_id, ip) tuple
    """
    path = "/domain/zone/{}/record".format(DOMAIN)
    result = client.get(path,
                        fieldType='A',
                        subDomain='' # you can use a subdomain too
                        )

    if len(result) != 1:
        raise Exception("Could not get current A record IP")

    record_id = result[0]
    path = "/domain/zone/{}/record/{}".format(DOMAIN,record_id)
    result = client.get(path)
    return record_id, result['target']

def update_arecord(client, record_id, ip):
    """
    Update the A record with the given ID with the provided IP
    :param client: The OVH API client
    :param record_id: The ID of the A record
    :param ip: The IP to update the record with
    :return:
    """
    path = "/domain/zone/{}/record/{}".format(DOMAIN,record_id)
    result = client.put(path,
                        target=ip
                        )

def main():
    ip = get_current_ip()

    client = ovh.Client(
        endpoint=OVH_ENDPOINT,
        application_key=OVH_APP_KEY,
        application_secret=OVH_APP_SEC,
        consumer_key=OVH_CON_KEY,
    )
    record_id, old_ip = get_current_arecord_ip(client)

    if ip != old_ip:
        print("Updating A record to IP {}".format(ip))
        update_arecord(client, record_id, ip)
    else:
        print("No update required")


if __name__ == "__main__":
    main()

Jan 9, 2020 - Using sed to edit config files

Using sed to edit config files

If you have a script which installs something, you often also want to automatically adjust a config file after installation. You can use the unix tool ‘sed’ for that.

Here are some examples, which assume that you have a parameter called ‘Test’ in the config file which is set to a value using ‘=’ character, e.g. test.conf

# This is some fake config file
Test = 123

Now you can use ‘sed’ to comment that line out, in or change the value:

# comment out
sed -i -e '/^[[:blank:]]*Test/ s/^#*/#/' test.conf

# comment in
sed -i -e '/^[[:blank:]]*#[[:blank:]]*Test/ s/^[[:blank:]]*#*//' test.conf

# set the value to 'abc'
sed -i -e '/^[[:blank:]]*Test[[:blank:]]*=/ s/=.*/= abc/' test.conf

With the ‘-i’ option the file is edited in-line. If you don’t use it the (modified) file content is printed out on the command line; good for testing.

The ‘[[:blank:]]’ fields are included so that the expression also works for messy config files, where you could have things like

  #  Test
Test    =123
   Test    = 123
# etc.