All posts by Jon Schewe

I use X2Go to login to some of my systems when I need to access a graphical desktop. To keep the load on the system low I use XFCE as the desktop environment. Recently I found that when I logged into one of my systems running Ubuntu 22.04 that applications didn’t appear to want to launch. When checking top in a terminal on the remote system I found x2goagent at 100% CPU. After a couple of attempts I came across this post on the a Debian users mailing list that solved my problem.

Setting "use_compositing" to "false" in
~/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml
solved the issue.

GitHub pull requests and issues

I have resisted using pull requests on GitHub for my own repositories because it seemed like I need to have have both an Issue and a Pull Request for each branch. I create Issues for fixes and features that I want to implement. During development I create a branch for the Issue and then once it’s finished and tested I manually merge with a merge commit and use the message of the merge commit to close the Issue.

Recently I came across an article about converting a GitHub Issue to a Pull Request. This solved my issue of having both an Issue and a Pull Request for each feature. I can create my Issues like normal and create a branch. Then when I push the branch I execute the following:

hub pull-request -i <issue number> -b main

This converts the specified Issue number into a Pull Request and associates it with the current branch. I need the “-b main” because I have my push.default value set to “nothing” and it appears that “hub” can’t find the main branch with that setup.

I’ve found a couple of benefits of using this pattern. One is that I can merge pull requests using the GitHub mobile app on my phone. The other is that now it’s really easy to review the changes made for a feature and keep the discussion about the issue in the same place.

Using password protected zip files in Mac

In an earlier post I explained how to use password protected zip files in Windows. This post is the Mac version. 7-Zip is still the file format, however the application is Keka instead of 7-Zip. This is because the 7-Zip application for Mac is command line only and therefore not quite as user-friendly.

Install Keka

Download Keka from https://www.keka.io or the Mac App store.

If you downloaded the file from, do the standard Mac thing and open the dmg file and drag the application to the Applications folder.

Creating a password protected file

Start by putting the files that you want to send in a folder by themselves, even if it’s only a single file. This makes it easy to keep track of what is being sent. It also helps the recipient as they will get the same folder name when they uncompress the file.

Open Keka. Specify 7Z and enter a password

Drag and drop the folder onto the window

Pick filename

Click Compress

Attach this file to an email and send it with a simple message. DO NOT PUT THE PASSWORD IN THE EMAIL. Contact the recipient through another means, phone, text, encrypted chat (WhatsApp) to send the password.

Opening a password protected file

The recipient saves the file to their computer. You will need to pay attention to where the file is saved. It might be in Documents, it might be in Downloads or some other location depending on your email client.

Open Finder and navigate to where the file is saved. Right click on 7z file -> Open With Keka. Don’t double click on the file to open it. This will use the built-in Mac utility that doesn’t understand the encryption on the file. You will be prompted for a password, but it’ll never work.

Pick a location. Click Extract. You will then be prompted to enter the password. When it finishes you will have a folder with the files that were sent.

Using password protected zip files in windows

Creating zip files with a password is a fairly easy way to add some security to information that you are sending via email. It’s not really good encryption, but it will keep many people out.

I suggest using 7-Zip. It’s an open-source and free application that runs on Windows, Linux and Mac. 7-zip has some better password encryption options than the zip programs built into some operating systems. This does mean that both the sender and recipient need to install 7-Zip, but I think it’s worth it.

If you are on a Mac, see my post for that platform.

Install 7-Zip

Do this on both the sending computer and the recipient computer.

Download 7-Zip for your computer from their download page.

The first table on the page is the most recent stable version. Pick the 64-bit exe. In this screen shot it is the second row. This should work for most anyone these days. Pay attention to where the file is saved, it is probably in Downloads.

Open File Explorer and navigate to the downloaded file. Double click on the file to start the install. The file will be named 7z1900-64.exe, where the 1900 may be different. There will be a black and white icon next to it.

During the install, the defaults are all fine. You may need to enter an administrator password for the install to finish.

Creating a password protected file

Start by putting the files that you want to send in a folder by themselves, even if it’s only a single file. This makes it easy to keep track of what is being sent. It also helps the recipient as they will get the same folder name when they uncompress the file.

Open Windows Explorer and navigate to the folder that you want to send. Now right click on the folder that you put all of your files in. Then click on 7-Zip and then Add to archive… If the 7-Zip option isn’t in the right-click menu, it is likely the case that you installed the 32-bit version rather than the 64-bit version. Uninstall 7-Zip and then go back to the download page and make sure you get the 64-bit version.

In the archive window there is a section in the lower right to enter a password. You need to enter it twice to be sure it was typed correctly. Leave everything else at the defaults. This will use AES-256 encryption, lower right corner, to encrypt the file. The format will be 7-Zip, so the recipient needs 7-Zip to open it. Then click OK. This will create a file with the name that you specified with a 7z extension next to the folder. If you have extensions turned off you may just see the name of the file. In the image below the file to send is the one with the paper icon named “stuff to send.7z”. This was created from the yellow folder “stuff to send”.

Attach this file to an email and send it with a simple message. DO NOT PUT THE PASSWORD IN THE EMAIL. Contact the recipient through another means, phone, text, encrypted chat (WhatsApp) to send the password.

Opening a password protected file

The recipient saves the file to their computer. You will need to pay attention to where the file is saved. It might be in Documents, it might be in Downloads or some other location depending on your email client.

Open File Explorer and navigate to the downloaded file. Then right click on the file and select 7-Zip, then Extract Here… You will then be prompted for the password. When it finishes you will have a folder with the files that were sent.

Starting a new duplicati backup

The Duplicati backup software is a nice cross platform backup solution. There are times when one wants to start a new backup with the same settings as another backup. Duplicati doesn’t support 2 backups going to the same directory, so one needs to make sure to specify a new destination for the new backup.

  1. Export the backup
    1. Click on the backup
    2. Click Export
    3. Click Export button (accept message about passwords)
    4. Save file to somewhere on your computer
  2. Disable scheduled backups of this job for now
    1. Click on the backup
    2. Click Edit
    3. Click Schedule
    4. Uncheck Automatically run backups
    5. Click Options
    6. Save
  3. Create a new backup from the old configuration
    1. Click on Add backup
    2. Import from file
    3. Select the file on your computer
    4. Import file
    5. Change the name from “backup name” to “{backup name} {today’s date}”
    6. Click on Destination
    7. Change the end of the Path on server to be the current date (this makes sure that we start in a new directory)
    8. Test connection
    9. OK to create
    10. Schedule
    11. Make sure there is a schedule set
    12. Options
    13. Save
  4. Delete the exported backup file from your computer so that the password isn’t left around for someone to find
  5. Start the backup

Cleanup of old backups

Once you are certain that the backup is working you should clean up the old backup from the destination to save space. Here are instructions for doing this when the backup destination is Nextcloud.

Delete the backup from the server

  1. Click on the backup you want to delete
  2. Click Edit
  3. Click on 2 Destination
  4. The Storage type will be WebDAV – if not, this won’t work
  5. Pay attention to the Server and port and the SSL checkbox.
  6. In “Path on server” everything before “/remote.php” is the path
  7. Put the following in the address bar of your web browser https://{host}:{port}/{path}.
    • Use “http” instead of “https” if “SSL” is not checked.
  8. Login with the username and password that is configured in the backup.
  9. Check the box next to the directory from the OLD backup.
  10. Click the 3 dots next to Actions
  11. Click delete
  12. Wait for it to finish
  13. Use the gear in the top right to log out

Alternatively I have also found that one can click the checkbox in Duplicati to delete the files from the server when deleting the configuration (see below) and that will remove the files from the server in most cases.

Delete the backup configuration

  1. Click on the backup you want to delete
  2. Click Delete
  3. Click Delete backup (leave delete remote files unchecked, this was done above)

Fixing duplicati unexpected difference in fileset

Duplicati is a nice backup tool that is cross platform. However sometimes it has issues. This post gives one solution for dealing with the error “Unexpected difference in fileset version”.

  1. Open the duplicati web page
  2. Pay attention to the fileset version number in the error message.
  3. Dismiss the error
  4. Click on the troubled backup
  5. Click on commandline
  6. Change the command at the top to delete
  7. Clear out the commandline arguments field
  8. Put “–version=XX” in the commandline arguments field (change XX to version specified in the error message)
  9. Click Run “delete” command now at the bottom right
  10. Wait
  11. Execute a new backup and see if there are errors
  12. Repeat if necessary

Tracking packages installed

To help with restores or migration to another piece of hardware I find it useful to keep track of which packages are installed on my Linux systems. This isn’t very difficult, but it has taken a bit of experimenting to come up with with something that works fairly well and is automated.

Create in /etc/systemd/system/status-email-root@.service. This is a helper service for sending emails on service failures.

[Unit]
Description=status email for %i to Jon

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/systemd-email.sh root %i

/usr/local/sbin/systemd-email.sh looks like this

#!/bin/sh

debug() { ! "${log_debug-false}" || log "DEBUG: $*" >&2; }
log() { printf '%s\n' "$*"; }
warn() { log "WARNING: $*" >&2; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "'$@' failed"; }

mydir=$(cd "$(dirname "$0")" && pwd -L) || fatal "Unable to determine script directory"


/usr/sbin/sendmail -t <<ERRMAIL
To: $1
From: systemd <root@$HOSTNAME>
Subject: $2
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8

$(systemctl status --full "$2")
ERRMAIL

Create in /etc/systemd/system/track-installed-packages.service with the content. Note the “showmanual” argument to “apt-mark”. This makes sure to only output the packages that were manually installed and not include those that were installed as dependencies. This keeps the list short and if dependencies change later keeps from installed unneeded packages later.

[Unit]
Description=track installed packages
OnFailure=status-email-root@%n.service

[Service]
Type=oneshot
ExecStart=/usr/bin/apt-mark showmanual
StandardOutput=file:/home/installed-packages.txt

Now create /etc/systemd/system/track-installed-packages.timer

[Unit]
Description=track installed packages daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Now enable the timer with

systemctl daemon-reload
systemctl enable track-installed-packages.timer
systemctl start track-installed-packages.timer

Now if you backup /home, you’ll always have the most recent list of installed packages.

I have a similar pair of systemd files for snaps that calls “snap list” and outputs to “/home/snap-packages.txt”. Snap doesn’t appear to have an option to specify only manually installed snaps. This may also error out if there are no snaps installed.

Configure Linux Jenkins node

I have been setting up a few Jenkins nodes lately and decided that I should write up the configuration that I’m using to share with others.

Create the node in Jenkins

The first thing to do is to create the node in Jenkins. Start by logging into your Jenkins host, then visit the “Manage Jenkins” link. Once there, visit “Manage Nodes” and then click “New Node” on the left.

Give your node a name. It’s a good idea to avoid spaces and special characters. I use letters, numbers, underscores and hyphens. Select “Permanent Agent” and then “OK”.

Here you need to specify the working directory, labels and the usage. I usually set the usage to only build jobs with a matching label expression. This is useful when setting up nodes per job to make sure that the node doesn’t get used for other random jobs. You may also want to specify an email address to notify when the node goes online and/or offline.

Once you have saved the configuration you will see a page specifying that the agent is offline and how to launch it. The important piece of information here is the secret. This will be a very long string of letters and numbers.

Linux Setup

First create a user in Linux that the node will run as. This user should not have any special privileges.

sudo adduser JENKINS_BUILD_USER

Replace “JENKINS_BUILD_USER” with the username that you are using. By default this user has a locked password so no one can login as this user.

In “/home/JENKINS_BUILD_USER” create the file “start-jenkins-node.sh” to start the node

#!/bin/sh

debug() { ! "${log_debug-false}" || log "DEBUG: $*" >&2; }
log() { printf '%s\n' "$*"; }
warn() { log "WARNING: $*" >&2; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "'$@' failed"; }

mydir=$(cd "$(dirname "$0")" && pwd -L) || fatal "Unable to determine script directory"

jenkins_host=JENKINS_HOST
jenkins_node_name=NODE_NAME
jenkins_node_secret=SECRET

cd "${mydir}"
# --no-check-certificate is needed if the certificate store does not recognize the jenkins host certificate
try wget https://${jenkins_host}/jnlpJars/agent.jar -O agent.jar

# -noCertificateCheck is needed if the certificate isn't recognized
nohup java -jar agent.jar -jnlpUrl https://${jenkins_host}/computer/${jenkins_node_name}/slave-agent.jnlp -secret ${jenkins_node_secret} -workDir "${HOME}" > "${HOME}"/jenkins-node.log 2>&1

Replace JENKINS_HOST with the hostname that Jenkins is running on. This script assumes that Jenkins is running at hte root of your server. If that’s not the case you’ll want to append the base path to the end of JENKINS_HOST. Replace NODE_NAME with the name of the node and SECRET with the secret from the node configuration on the Jenkins host.

Mark the file executable.

chmod +x /home/JENKINS_BUILD_USER/start-jenkins-node.sh

Create “/etc/systemd/system/jenkins_node.service”

[Service]
Type=simple
ExecStart=/home/JENKINS_BUILD_USER/start-jenkins-node.sh
WorkingDirectory=/home/JENKINS_BUILD_USER
Restart=always
RestartSec=60
User=JENKINS_BUILD_USER

[Unit]
After=network-online.target
Wants=network-online.target

[Install]
WantedBy=default.target

Replace JENKINS_BUILD_USER with the user that you created. Then you can enable and start the service with

sudo systemctl daemon-reload
sudo systemctl enable jenkins_node
sudo systemctl start jenkins_node

At this point you should see your node online in Jenkins and you are ready to use it for jobs.

My initial experience with Google Inbox

This past week I finally decided to try out Google Inbox. The feature that really drew me to it was the ability to snooze emails. This feature allows you to make an email leave your inbox and come back at some later date and time. This is a really cool feature and a nice way to delay dealing with an email until you need to. In addition to this it is really easy to create filters that add emails to bundles (labels). These bundles can be set to appear in the inbox or not and you have some control over when the bundles appear in the inbox. When a bundle appears in the inbox it shows up as a wide message, once opened you see all of the messages in the bundle. This is a nice way to be able to group messages; you can see your labels in the inbox in a compact fashion. You can also decide which bundles will trigger notifications in the android app.

After using Inbox for about a week, I’ve decided to go back to using GMail. Here are my reasons:

  1. The keyboard shortcuts in the web interface are lacking.
    • No keyboard shortcut to goto a label/bundle
    • No keyboard shortcut to type in the name of a bundle to move to. There is a shortcut ‘.’ to open the move to menu though.
  2. The bar on the left side showing the bundles don’t show how many unread messages are in the bundle
  3. When you choose to have bundles show up in the inbox you can select as the messages arrive, once a day (7:00) and once a week (Monday 7:00). I would really like to be able to at least pick the time for once a day and once a week. It would be nice to be able to pick the day on the once a week.
  4. I like to make sure all messages that I keep are assigned at least one label. The Inbox interface doesn’t allow me to see what labels have been applied to a message. This makes me very concerned that I will loose messages by them being archived and not assigned any labels. GMail’s search interface is great, but I really like to be able to find my messages by label.

If Google fixes these features I will give Inbox a try again, until then I’m sticking with GMail.

IPv6 on Comcast Residential

Comcast has now opened up their IPv6 service to residential customers. If you have a supported modem from Comcast and a device connected to it that understands IPv6 you can connect. You might ask why would I want to setup IPv6? And that is a good question. One reason is to stay up to date with current networking technology. Another reason is that we’re running out of IPv4 addresses and we will eventually need to switch to IPv6. Currently many sites on the Internet are supporting IPv4 and IPv6 to help with the adoption of IPv6. Another reason for IPv6 support is that this setup can give you a subnet of public IPv6 addresses to use in your house. Meaning that you can allow computers on your internal network to be accessible from the outside world. Of course this also means that you could potentially open up your computers to the outside world, so you need to be careful and setup your firewall to keep your internal computers secure unless you want them accessible. This also removes any issues with NAT as IPv6 doesn’t have any NAT support.

For my setup I have a compatible modem from Comcast and a Linux computer as my router. My Linux computer is running Ubuntu. These instructions are specific to my setup, but should be able to be used by others running most any Linux distribution.

The first thing you should do is secure your network from IPv6 so that something doesn’t get in while you’re setting things up. Here is my IPv6 firewall setup, it’s very similar to my IPv4 setup, except the port numbers for DHCP are different. Outbound traffic is allowed and inbound traffic is denied. I’ve also disabled forwarding of traffic, this prevents inbound traffic directly to the internet work. This script needs to be located at “/usr/local/sbin/firewall-ipv6-start” for the radvd script at the end of this post to work properly.

#!/bin/sh 

IPTABLES=/sbin/ip6tables
INET_IFACE="eth0"
LAN_IFACE="eth1"
LO_IFACE="lo"

$IPTABLES -F
$IPTABLES -X

# accept everything by default
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD DROP

${IPTABLES} -A FORWARD \
 -m state --state RELATED,ESTABLISHED \
 -m comment --comment "allow inbound traffic for established and related connections" \
 -j ACCEPT
${IPTABLES} -A FORWARD \
 -i ${LAN_IFACE} -o ${INET_IFACE} \
 -m comment --comment "allow all Internet bound traffic from the internal network" \
 -j ACCEPT
${IPTABLES} -A FORWARD -p ipv6-icmp \
 -m comment --comment "forward any ICMP traffic" \
 -j ACCEPT

${IPTABLES} -A INPUT \
 -m state --state RELATED,ESTABLISHED \
 -m comment --comment "allow inbound traffic for established and related connections" \
 -j ACCEPT

${IPTABLES} -A INPUT \
 -i ${LO_IFACE} \
 -m comment --comment "allow any local-only traffic" \
 -j ACCEPT

${IPTABLES} -A INPUT \
 -p ipv6-icmp \
 -m comment --comment "allow ICMP traffic from anywhere" \
 -j ACCEPT

${IPTABLES} -A INPUT -i ${INET_IFACE} \
 -p udp -m udp --dport 546 \
 -m comment --comment "Accept DHCP traffic" \
 -j ACCEPT

${IPTABLES} -A INPUT -i ${INET_IFACE} \
 -p udp -m udp --dport 547 \
 -m comment --comment "Accept DHCP traffic" \
 -j ACCEPT
 

The remainder of this post is based upon this post on using DHCPv6 with prefix delegation.

The next thing we need to do is get an address from Comcast along with a prefix (subnet) to hand out to the computers on the internal network. Comcast doesn’t appear to be using router advertisements for IPv6, so we’ll need to use DHCP over IPv6. For this I could use the ISC DHCP server that I’m using for IPv4, but it doesn’t support prefix delegation which I need to give the other computers in my house IPv6 addresses. For this I installed wide dhcp client. Ubuntu includes this in the package wide-dhcpv6-client. A side advantage to using a different DHCP client for IPv6 is that you can turn it off to disable IPv6 support without messing with your IPv4 network. Once you install the client edit /etc/wide-dhcpv6/dhcp6c.conf to look like this. You will need to modify the interface used and possibly the sla-len. I found the sla-len by trial and error. You won’t get a prefix if the value is incorrect.

interface eth0 { # external facing interface (WAN)
 send ia-na 1;
 send ia-pd 1;

 request domain-name-servers;
 request domain-name;

 script "/etc/wide-dhcpv6/dhcp6c-script";
};

id-assoc pd 1 {
 prefix-interface eth1 { #internal facing interface (LAN)
 sla-id 0; # subnet. Combined with ia-pd to configure the subnet for this interface.
 ifid 1; # IP address "postfix". if not set it will use EUI-64 address of the 
         # interface. Combined with SLA-ID'd prefix to create full IP address of interface.
 sla-len 0; # prefix bits assigned. Take the prefix size you're assigned
            # (something like /48 or /56) and subtract it from 64. 
            # In my case I was assigned a /64, thus the value is 0
 };
};

id-assoc na 1 {
 # id-assoc for external interface
};

When you start the wide DHCP client and all is happy you will find that your external interface has an address. In my case it starts with 2001:558:6014. See the output of “ip addr show dev eth0” changing the interface as appropriate. Below is the output for my system with the IP addresses masked out.

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
 link/ether 00:d0:b7:3f:4d:18 brd ff:ff:ff:ff:ff:ff
 inet XXX.XXX.XXX.XXX/22 brd 255.255.255.255 scope global eth0
 valid_lft forever preferred_lft forever
 inet6 2001:558:6014:XXXX:XXXX:XXXX:XXXX:XXXX/128 scope global 
 valid_lft forever preferred_lft forever
 inet6 fe80::XXXX:XXXX:XXXX:XXXX/64 scope link 
 valid_lft forever preferred_lft forever

Once this is setup you can ping IPv6 addresses from your router. You can test this with “ping6 google.com”.

Now to allow your local network talk to the Internet via IPv6 you’ll need to allow forwarding and then assign them IPv6 addresses.

First we’ll tell the kernel to allow forwarding by modifying adding the file 70-ipv6-routing.conf to /etc/sysctl.d. Note that net.ipv6.conf.all.accept_ra is set to 2. Any other value will not work due to how the router advertisements are handled.

# only set this on the external interface, otherwise we don't get a
# default route for IPv6
net.ipv6.conf.EXT_IFACE.accept_ra=2
net.ipv6.conf.EXT_IFACE.forwarding=0

net.ipv6.conf.INT_IFACE.accept_ra=1
net.ipv6.conf.INT_IFACE.forwarding=1

net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.autoconf=1

 
Once you change these values you will need to reboot or use the sysctl utility to set them immediately.

Now to hand out IPv6 addresses to the rest of the network. This will be done by setting up radvd. The package ‘radvd’ on Unbuntu contains this daemon. Once installed you can setup /etc/radvd.conf for the prefix that Comcast gave you. However when your IP address changes you’ll need to update the file. So instead I have created a script that can be run from wide dhcp client. Put the following in “/usr/local/sbin/update-ipv6-setup.sh” and add a call to this script from the end of /etc/wide-dhcpv6/dhcp6c-script. You’ll need to change the interface in this script to be your internal interface.

#!/bin/sh

debug() { ! "${log_debug-false}" || log "DEBUG: $*" >&2; }
log() { printf '%s\n' "$*"; }
warn() { log "WARNING: $*" >&2; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "'$@' failed"; }

mydir=$(cd "$(dirname "$0")" && pwd -L) || fatal "Unable to determine script dir
ectory"

prefix=$(ip -6 addr show dev eth1 scope global \
 | grep inet6 \
 | awk '{print $2}') \
 || fatal "Unable to get prefix"

cat > /etc/radvd.conf.new <<EOF

interface eth1
{
 AdvSendAdvert on;
 AdvIntervalOpt on;
 MinRtrAdvInterval 60;
 MaxRtrAdvInterval 300;
 AdvLinkMTU 1280;
 AdvOtherConfigFlag on;
 AdvHomeAgentFlag off;
 
 prefix ${prefix}
 {
 AdvOnLink on;
 AdvAutonomous on;
 AdvRouterAddr on;
 };
};

EOF

diff /etc/radvd.conf.new /etc/radvd.conf > /dev/null
if [ $? -ne 0]; then 
 # only move if there are differences
  try mv -f /etc/radvd.conf.new /etc/radvd.conf
  try service radvd restart
fi
try /usr/local/sbin/firewall-ipv6-start

Now you have IPv6 setup on your router and your home network. I found that Linux, Windows and Mac automatically recognize the IPv6 router advertisements and grab addresses and setup routes appropriately.

Resources: