blog.pdericson.com - let’s encrypt nginx

SCHEDULED: <2020-06-02 Tue>

Install nginx:

pkg_add nginx

Using the example acme-client.conf as a starting point.

cp /etc/examples/acme-client.conf /etc/acme-client.conf
diff -u /etc/examples/acme-client.conf /etc/acme-client.conf

results:

--- /etc/examples/acme-client.conf      Fri May  8 04:51:59 2020
+++ /etc/acme-client.conf       Tue Jun  2 22:50:04 2020
@@ -11,9 +11,9 @@
        account key "/etc/acme/letsencrypt-staging-privkey.pem"
 }

-domain example.com {
-       alternative names { secure.example.com }
-       domain key "/etc/ssl/private/example.com.key"
-       domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
+domain pdericson.com {
+       alternative names { blog.pdericson.com }
+       domain key "/etc/ssl/private/pdericson.com.key"
+       domain full chain certificate "/etc/ssl/pdericson.com.fullchain.pem"
        sign with letsencrypt
 }
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
diff -u /etc/nginx/nginx.conf.orig /etc/nginx/nginx.conf

results:

--- /etc/nginx/nginx.conf.orig  Tue Jun  2 22:35:37 2020
+++ /etc/nginx/nginx.conf       Wed Jun  3 01:51:44 2020
@@ -89,6 +89,12 @@
         #location ~ /\.ht {
         #    deny  all;
         #}
+
+        location /.well-known/acme-challenge/ {
+            rewrite ^/.well-known/acme-challenge/(.*) /$1 break;
+            root /var/www/acme;
+        }
+
     }

Start nginx:

rcctl start nginx

Request the intial certificate:

acme-client -v pdericson.com

Do the bare minimum to enable https:

-        ssl_certificate      /etc/ssl/server.crt;
-        ssl_certificate_key  /etc/ssl/private/server.key;
+        ssl_certificate      /etc/ssl/pdericson.com.fullchain.pem;
+        ssl_certificate_key  /etc/ssl/private/pdericson.com.key;

Reload nginx:

rcctl reload nginx

Enable nginx (on boot):

rcctl enable nginx

Setup automatic certificate renewal:

crontab -e
~       *       *       *       *       acme-client pdericson.com && rcctl reload httpd

blog.pdericson.com

SCHEDULED: <2020-06-01 Mon>

I am re-purposing and re-installing my ARP Thunder Cloud Dedicated Server.

Load ISO:

OpenBSD-6.7-amd64-install67.iso

Power Off

Boot

  1. DVD/CD

(I)nstall

System hostname: blog

IPv4 config is manual: IPv4 address, Netmask, Default IPv4 route and DNS nameservers can all be found in the ARP Networks portal under the IP Assignments service.

IPv6 address: autoconf (this seems to work…)

DNS domain name: pdericson.com

I do not expect to run the X Window System.

I chose to setup a user (pdericson).

The timezone that I am in is NZ.

The disk auto layout was 👍

reboot

Login as root on console

reboot  # some firmware has been installed

Login as root on console

syspatch
reboot  # the kernel has been re-linked

Login as root on console

Because this is a re-install, the existing SATA disk is still present. I need to fsck the disk because I didn’t shutdown the server gracefully.

mkdir /data
fsck -y /dev/sd1a
duid=`disklabel sd1 | grep ^duid: | awk '{print $2}'`
cat >> /etc/fstab <<EOF
$duid.a /data ffs rw,nodev,nosuid 1 2
EOF
mount /data

I need git to clone my blog engine.

pkg_add git

I need emacs to adjust my blog engine.

pkg_add -i emacs  # 3: ...no_x11

My blog engine is written in Elixir.

pkg_add elixir
pkg_add node

My blog engine uses Pygments to highlight code.

pkg_add python3
ln -s python3 /usr/local/bin/python
pkg_add py3-pygments
pkg_add rsync

Login as pdericson via ssh

Setup public key authentication.

Elixir expects UTF-8 which is reasonable.

cat >> .profile <<EOF
export LC_CTYPE="en_NZ.UTF-8"
EOF
exit

Login as pdericson via ssh

tmux

Setup .gitconfig.

ansible callback plugins

SCHEDULED: <2020-05-16 Sat>

The latest version of ansible is:

https://pypi.org/project/ansible/

2.9.9

Callback Plugins:

https://docs.ansible.com/ansible/latest/plugins/callback.html

Developing plugins, Developing particular plugin types, Callback plugins:

https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#callback-plugins

The CallbackBase class:

https://github.com/ansible/ansible/blob/stable-2.9/lib/ansible/plugins/callback/__init__.py

What methods are available?

curl https://raw.githubusercontent.com/ansible/ansible/stable-2.9/lib/ansible/plugins/callback/__init__.py | grep def\ v2_

results:

def v2_on_any(self, *args, **kwargs):
def v2_runner_on_failed(self, result, ignore_errors=False):
def v2_runner_on_ok(self, result):
def v2_runner_on_skipped(self, result):
def v2_runner_on_unreachable(self, result):
def v2_runner_on_async_poll(self, result):
def v2_runner_on_async_ok(self, result):
def v2_runner_on_async_failed(self, result):
def v2_playbook_on_start(self, playbook):
def v2_playbook_on_notify(self, handler, host):
def v2_playbook_on_no_hosts_matched(self):
def v2_playbook_on_no_hosts_remaining(self):
def v2_playbook_on_task_start(self, task, is_conditional):
def v2_playbook_on_cleanup_task_start(self, task):
def v2_playbook_on_handler_task_start(self, task):
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
def v2_playbook_on_import_for_host(self, result, imported_file):
def v2_playbook_on_not_import_for_host(self, result, missing_file):
def v2_playbook_on_play_start(self, play):
def v2_playbook_on_stats(self, stats):
def v2_on_file_diff(self, result):
def v2_playbook_on_include(self, included_file):
def v2_runner_item_on_ok(self, result):
def v2_runner_item_on_failed(self, result):
def v2_runner_item_on_skipped(self, result):
def v2_runner_retry(self, result):
def v2_runner_on_start(self, host, task):

Logitech K780

SCHEDULED: <2020-05-10 Sun>

I’m quite happy with my keyboard, but… the fn keys are swapped by default!

Logitech K780

We can use xev to find out more…

F4:

KeyPress event, serial 34, synthetic NO, window 0x200001,
    root 0x203, subw 0x0, time 349417, (155,9), root:(3039,559),
    state 0x0, keycode 180 (keysym 0x1008ff18, XF86HomePage), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

fn-F4:

KeyPress event, serial 34, synthetic NO, window 0x200001,
    root 0x203, subw 0x40000e, time 424031, (376,218), root:(3260,768),
    state 0x0, keycode 70 (keysym 0xffc1, F4), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

https://pwr-solaar.github.io/Solaar/

Solaar is a Linux manager for Logitech’s devices that connect via a USB Unifying, Lightspeed, or Nano receiver.

I found that I needed version 1.0.2rc2, the version from pypi (1.0.1) and the version from debian buster (0.9.2) were too old.

https://pwr-solaar.github.io/Solaar/installation

sudo apt install python3-pyudev
git clone git@github.com:pwr-Solaar/Solaar.git
cd Solaar
sudo bash -c 'umask 022 ; pip3 install .'

I think a reboot was required but I’m not sure…

I’m using the following in my ~/.xsession file:

# turn off fn-swap
sudo solaar config 1 fn-swap off
# keep solaar running so we don't lose our settings when the keyboard sleeps
sudo solaar -w hide &

Notebook tutorial - Part 5: Animations!

SCHEDULED: <2020-05-01 Fri>

Just a bit more reading please:

https://pandas.pydata.org/docs/getting_started/intro_tutorials/04_plotting.html

But also, take a look at the Python tutorial - it’s really nice!

https://docs.python.org/3.7/tutorial/introduction.html

If we bring together everything we have learnt, at a stretch we can start thinking about creating a cool animation.

Here’s one I put together:

Pretty neat huh?

Right, let’s walk through how it was made…

part-5.ipynb

import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML


fig, ax = plt.subplots()

ax.tick_params(axis='x', rotation=90)


data = {}

def animate(i):
    # The animate function is called for each frame of the animation - in this case a frame per day!

    data.setdefault((date1 + datetime.timedelta(days=i)).strftime('%Y-%m-%d'), {})

    # This dataframe is a subset of the results...  e.g. Date of report less than
    # or equal to first date + i days
    df3 = df1[df1["Date of report"] <= date1 + datetime.timedelta(days=i)][["Date of report", "DHB"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "DHB"]).size()
    for item in df3.items():
        data.setdefault(item[0][0], {})[item[0][1]] = item[1]

    # print(data)
    # This is what "data" looks like for index 0 (frame 1)
    # e.g. {'2020-02-26': {'Auckland': 1}}

    args = [sorted(data)]
    # We're creating a plot per DHB (?)
    for dhb in dhbs:
        args.append([data[x].get(dhb, 0) for x in data])

    # stackplot expects multiple lists of data, first one being the x axis (dates),
    # then, in our case, a list per dhb (for this time period.)
    ax.stackplot(*args)

    ax.legend(dhbs, loc='upper left', fontsize='xx-small')


# Think of an animation as a sequence of graphs (or frames)
ani = animation.FuncAnimation(fig, animate, frames=days)

# Finally, let's create a video!
ani.save('part-5.mp4', fps=1, dpi=200)

What did we learn?

  • We learnt one way to make an animation and that an animation is simply a sequence of frames (or graphs), can you create your own animation? Have a think about what data you can extract and how it could be presented and send me a copy!

Notebook tutorial - Part 4: Pandas and DataFrames

SCHEDULED: <2020-04-30 Thu>

Time to do some reading, take a look at this page in the Panda’s tutorial:

https://pandas.pydata.org/docs/getting_started/intro_tutorials/03_subset_data.html

Do some experimenting:

df1
df1[["Date of report"]].groupby(df1["Date of report"]).count()
df1[["Date of report", "Overseas travel"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "Overseas travel"]).size().unstack()
df1[["Date of report", "Last country before return"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "Last country before return"]).size().unstack()

What did we learn?

  • We learnt that pandas refers to a table of data as a “DataFrame” and that a subset of a DataFrame can be selected to present different features of the data. Please select some data and share the Python code with me!