The Czech keyboard layout on a physical US Mac keyboard has some keys which are
pretty much useless. For example the key |
aka \
next to the enter is
actually also available on tilde key next to left shift in Czech layout and
since I am used to wide enter key I end up pressing it when I want to hit
enter. It renders to a weird “double tilde” character which I never use anyway.
Well, an easy help. This can be remapped pretty easily:
hidutil property --set '{"UserKeyMapping":
[{"HIDKeyboardModifierMappingSrc":0x700000031,
"HIDKeyboardModifierMappingDst":0x700000058}]
}'
That’s all, really. No need to restart anything, but to do this after each boot a property list for launcher must be created. Here it is:
cat << EOF | sudo tee -a /Library/LaunchDaemons/org.custom.keyboard-remap.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.custom.keyboard-remap</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/hidutil</string>
<string>property</string>
<string>--set</string>
<string>{"UserKeyMapping": [{"HIDKeyboardModifierMappingSrc":0x700000031, "HIDKeyboardModifierMappingDst":0x700000058}] }</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
EOF
sudo launchctl load -w /Library/LaunchDaemons/org.custom.keyboard-remap.plist
Worry do not, this is still a Linux blog. I just ended up using MacOS on desktop a bit more lately, I still run Linux remote shells :-)
We stream our community demos on youtube via Google Meet and there are borders on each side which makes the content to be smaller and less readable. Luckily, it is in the middle of the screen, so the following command will crop the image to its 1/1.29 of the size, stretch it back to 720p and reencodes it for YouTube copying the audio stream.
ffmpeg -i intput.mp4 -vf "crop=iw/1.29:ih/1.29,scale=-1:720" -y output.mp4
If your source video is different, just play around with the 1.29 constant to
get the desired output. Use -t
option to encode just the first 10 seconds of
the video to speed testing up:
ffmpeg -i intput.mp4 -vf "crop=iw/1.29:ih/1.29,scale=-1:720" -t 00:00:10.0 -y output.mp4
That is all.
I have been avoiding this for like ten years now, but today is the day when I will setup a FreeIPA with Foreman Proxy for development and testing purposes and here are my notes.
The goal is to deploy a libvirt VM with IPA server and Foreman Proxy intergated
with it. The domain will be ipa.lan
and the host named ipa.ipa.lan
. This is
NOT how you should deploy production Foreman FreeIPA integration! For that,
reading our official
documentation
and using foreman-installer
is suggested instead.
We need a VM, let’s go with CentOS 8.
virt-builder centos-8.2 --output /var/lib/libvirt/images/ipa.img --root-password password:redhat --hostname ipa.ipa.lan
virt-install --name ipa.ipa.lan --memory 2048 --vcpus 2 --disk /var/lib/libvirt/images/ipa.img --import --os-variant rhel8.3 --update
virsh console ipa.ipa.lan
We need a static IP for this VM:
nmcli con modify enp1s0 \
ip4 192.168.122.5/24 \
gw4 192.168.122.1 \
ipv4.dns 192.168.122.1
nmcli con down enp1s0
nmcli con up enp1s0
Make sure the hostname is correct:
hostnamectl set-hostname ipa.ipa.lan
Make sure to fix hosts file, FQDN must resolve to the IP address not localhost:
grep ipa /etc/hosts
192.168.122.5 ipa.ipa.lan ipa
The installation is very smooth, expect just couple of questions like administrator password or the actual domain:
dnf module enable idm:DL1
dnf module install idm:DL1/dns
ipa-server-install --setup-dns --auto-forwarder --auto-reverse
Ensure firewall ports are enabled:
firewall-cmd --add-service=http --add-service=https --add-service=ldap --add-service=ldaps \
--add-service=ntp --add-service=kerberos --add-service=dns --add-port=8000/tcp --permanent
Next up, install Foreman Proxy:
dnf -y install https://yum.theforeman.org/releases/2.4/el8/x86_64/foreman-release.rpm
dnf -y install foreman-proxy
Create the foreman user with minimum required permissions to manage Foreman
hosts, create and configure keytab file. When asked for admin
password, use
the one used when installing the IPA server:
foreman-prepare-realm admin realm-smart-proxy
mv freeipa.keytab /etc/foreman-proxy/freeipa.keytab
chown foreman-proxy:foreman-proxy /etc/foreman-proxy/freeipa.keytab
Configure and start the Foreman Proxy service. This is for development
purposes, so let’s only use HTTP. You may also want to add some trusted_hosts
entries to allow access from Foreman:
cat /etc/foreman-proxy/settings.yml
---
:settings_directory: /etc/foreman-proxy/settings.d
:http_port: 8000
:log_level: DEBUG
Enable Realm module:
cat /etc/foreman-proxy/settings.d/realm.yml
---
:enabled: true
:use_provider: realm_freeipa
And enable FreeIPA plugin:
cat /etc/foreman-proxy/settings.d/realm_freeipa.yml
---
:keytab_path: /etc/foreman-proxy/freeipa.keytab
:principal: realm-smart-proxy@IPA.LAN
:ipa_config: /etc/ipa/default.conf
:remove_dns: true
:verify_ca: true
And start it up:
systemctl enable --now foreman-proxy
Realm feature should be available:
curl http://ipa.ipa.lan:8000/features
["realm"]
To show a host entry in IPA via CLI:
kinit admin
ipa host-show rex-dzurnak.ipa.lan
Host name: rex-dzurnak.ipa.lan
Class: ipa-debian-10
Password: True
Keytab: False
Managed by: rex-dzurnak.ipa.lan
Add the foreman proxy into Foreman and start developing or testing. Have fun!
My graphics card died and thanks to COVID and Bitcoin, it will be a long wait until it’s back. I am on Mac M1 at the moment and it looks like there are not many good IRC clients on MacOS.
Let’s run a simple web-based IRC client which can also work as a bouncer (no need of ZNC). I randomly selected one which is called The Lounge, looks nice and works okay for me. This one is written in NodeJS and since there is no package in Fedora, I’ve decided to build it via yarn. It needs only one native dependency I think - sqlite3 so do not expect any problems on that front:
# dnf install nodejs yarn sqlite-devel
# dnf groupinstall "Development Tools"
# mkdir ~/.thelounge
# cd ~/.thelounge
# yarn add thelounge
If you prefer installing it into /usr/local
then run yarn global add
thelounge
.
Create a user service, I will be running it as a regular user:
# cat /home/lzap/.config/systemd/user/thelounge.service
[Unit]
Description=The Lounge IRC client
After=network-online.target
[Service]
ExecStart=/home/lzap/.thelounge/node_modules/.bin/thelounge start
[Install]
WantedBy=multi-user.target
Start it to create a default configuration file:
# systemctl --user daemon-reload
# systemctl --user enable --now thelounge
Optionally, stop the service for now and review the configuration. There are couple of things I recommend to tune. By default the service listens on HTTP (9090), no HTTPS is configured, it stores all logs in both sqlite3 and text files and it is configured as “private” instance, meaning you need to login with a username and password:
# vim ~/.thelounge/config.js
Create new user:
# ~/.thelounge/node_modules/.bin/thelounge add lzap
Visit http://localhost:9090 or https://localhost:9090 if you’ve configured SSL.
There you can create one or more IRC connections, join all channels, everything
will be written into a separate ~/.thelounge/users/user.js
configuration file
which is nice. If you disabled sqlite3 logging, everything is stored in text
files which I appreciate a lot.
If you want a simple letsencrypt tutorial for Fedora, read my prevous blog post:
# grep "https: {" -A5 ~/.thelounge/config.js
https: {
enable: true,
key: "/etc/pki/tls/private/home.zapletalovi.com.key",
certificate: "/var/lib/acme/certs/home.zapletalovi.com.crt",
ca: "",
},
No intermediate CAs are needed for letsencrypt so you can leave the field blank. Have fun.
I was looking for a simple letsencrypt tutorial for my home server running Fedora but it looks like the official (and quite capable) certbot is not availble in Fedora repos. So I have decided to go a more simple route of using acme-tiny shell script which is present and does the same, at least if you are running Apache httpd.
First off, install Apache httpd, SSL support and acme script itself:
# dnf install httpd mod_ssl acme-tiny
Let’s assume that the Apache server is already serving some files and is available on the desired domain via HTTP (not HTTPS yet):
# systemctl enable --now httpd
# curl -s http://home.zapletalovi.com | grep -o "Test Page"
Test Page
We are almost there, trust me. Generate a new certificate request. OpenSSL tool will ask several questions like name, organization and this stuff. Make sure that the Common Name (CN) is correct.
# cd /etc/pki/tls
# ln -s /var/lib/acme/csr .
# openssl req -new -nodes -keyout private/home.zapletalovi.com.key -out csr/home.zapletalovi.com.csr
# chmod 0400 private/home.zapletalovi.com.key
The next step is the actual communication with the authority, putting the
challenge hash into /var/www/challenges
directory which is exported by Apache
httpd and downloading the signed request:
# systemctl start acme-tiny
See system journal for any errors. If you encounter one, just start the script manually but make sure to use acme user account not root:
# su acme -s /bin/bash
# /usr/libexec/acme-tiny/sign
And that’s really all! You should have your certificate signed by letsencrypt now. Configure the desired software to use the new certificate and the key from the following paths:
# find /var/lib/acme /etc/pki/tls/private
/var/lib/acme
/var/lib/acme/certs
/var/lib/acme/certs/home.zapletalovi.com.crt
/var/lib/acme/csr
/var/lib/acme/csr/home.zapletalovi.com.csr
/var/lib/acme/private
/var/lib/acme/private/account.key
/etc/pki/tls/private/home.zapletalovi.com.key
For example I want to actually configure the Apache httpd itself:
# grep zapletalovi /etc/httpd/conf.d/ssl.conf
SSLCertificateFile /var/lib/acme/certs/home.zapletalovi.com.crt
SSLCertificateKeyFile /etc/pki/tls/private/home.zapletalovi.com.key
If you are like me and running under SELinux enforcing, make sure that the newly generated certificates have the proper label:
# semanage fcontext -a -f a -t cert_t '/var/lib/acme/certs(/.*)?'
# restorecon -rv /var/lib/acme/certs
The final and the most important step - enable systemd timer which will automatically extend the certificate for you:
# systemctl enable --now acme-tiny.timer
That was easy.
QEMU/KVM libvirt virtual machine can be acessed via serial console. When a new VM is created, serial console device is created. However to fully utilize this, several steps are needed on the guest machine.
The first option is to start getty service on serial console to get a login prompt when system finishes booting. This is as easy as:
# systemctl enable --now serial-getty@ttyS0.service
To access serial console via libvirt command line do:
# virsh console virtual_machine_name
This approach is simple enough, but when something goes wrong and VM does not boot, it is not possible to access the VM during early boot or even bootloader. In that case, perform the additional configuration:
# grep console /etc/default/grub
GRUB_TERMINAL_INPUT="console serial"
GRUB_TERMINAL_OUTPUT="console serial"
GRUB_CMDLINE_LINUX="... console=ttyS0"
Then write new grub configuration, for EFI systems do the following:
# grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
For BIOS systems do:
# grub2-mkconfig -o /boot/grub2/grub.cfg
Reboot and connect early to access grub or to see early boot messages. These commands will work on Fedora, CentOS, Red Hat Enterprise Linux and clones.
My home network is extremely slow, because I have CAT5e cables everywhere. I was wondering if I can use Thunderbolt ports which I have both on the new Mac M1 and Intel NUC with Fedora. So without my breath, since some Thunderbolt docks are known to brick the new Macs, I connected the two guys. And it worked automatically!
Fedora’s (33) kernel automatically recognized thunderbolt0 device and NetworkManager created a new connection named “Wired connection 1”. There must be some autonegotiation in the spec, because the two devices created 169.254/16 network and picked some IP addresses. I was not expecting that, I mean maybe if this was Linux to Linux but with MacOS involved I thought this is not gonna work. Let’s see how fast is my 100Mbps connection:
mac$ nc -v -l 2222 > /dev/null
linux$ dd if=/dev/zero bs=1024K count=512 | nc -v 192.168.1.55 2222
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.1.5:2222.
512+0 záznamů přečteno
512+0 záznamů zapsáno
536870912 bajtů (537 MB, 512 MiB) zkopírováno, 45,8012 s, 11,7 MB/s
Ncat: 536870912 bytes sent, 0 bytes received in 45.86 seconds.
That’s expected on a 100Mbps ethernet. On a gigabit network, which I considered to upgrade to, we should see something like 117 MB/s for my ideal case (just a switch). But let’s see how Thunderbolt works for me:
linux$ dd if=/dev/zero bs=1024K count=512 | nc -v 169.254.145.73 2222
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Connected to 169.254.145.73:2222.
512+0 záznamů přečteno
512+0 záznamů zapsáno
536870912 bajtů (537 MB, 512 MiB) zkopírováno, 0,788541 s, 681 MB/s
Ncat: 536870912 bytes sent, 0 bytes received in 0.79 seconds.
Holy Moly! It’s not 1.1 Gbps but almost 900 MB/s that’s insane. This is a USB-C cable which is the best thing I currently have (this came with my LG screen). I am dropping a proper Thunderbolt3 into a basket to see how faster this can be. I mean in theory, I don’t have that fast SSD in my Intel NUC server.
Allright, so that’s looks like should be my preferred connection between my desktop and Linux. Let’s rename the connection first:
nmcli con modify "Drátové připojení 1" connection.id thunderbolt0
Oh gosh, I need to switch back to English from Czech language. Next up, set static IP address.
nmcli con modify thunderbolt0 ipv4.method static ipv4.address 192.168.13.4/24
nmcli con down thunderbolt0
nmcli con up thunderbolt0
And after quick update in a MacOS network dialog and /etc/hosts
change, the
connection between my new desktop and my working Linux machine is 10Gbps.
When my disks wake up during the day, I am angry. I want silence, so I started investigating which process makes them to do that. I suspect that something is browsing Samba share, but to confirm I created this simple SystemTap script:
# cat syscall_open.stp
#!/usr/bin/env stap
#
# System-wide strace-like tool for catching file open syscalls.
#
# Usage: stap syscall_open filename_regexp
#
probe syscall.open* {
if (filename =~ @1) {
printf("%s(%d) opened %s\n", execname(), pid(), filename)
}
}
It’s as easy as starting this up and waiting until the process is found. It accepts regular expression, not a glob:
# dnf install systemtap systemtap-runtime
# stap syscall_open.stp '/mnt/int/data.*'
This will work on all SystemTap operating systems, I tested this on Fedora and any EL distribution should work too.
Btrfs have been available in Fedora for quite some time and starting from Fedora 33, new installations of Workstation edition use it by default. Btrfs is pretty capable file system with lots of options, let’s take a look on one aspect: transparent per-file compression.
There’s little bit of misunderstanding how this works and some people recommend
to mount with compress
option. This is actually not necessary and I would
actually strongly suggest NOT to use this option. See, this option makes btrfs
to attempt to compress all files that are being written. If the beginning of a
file cannot be effectively compressed, it’s marked as “not for compression” and
this is never attempted again. This can be even forced via a different option.
This looks nice on paper.
The problem is, not all files are good candidates for compression. Compression takes time and it can dramatically worsen performance, things like database files or virtual machine images should never be compressed. Performance of libvirt/KVM goes terribly down by order of magnitude if an inefficient backing store is used (qcow2).
I suggest to keep the default mount options Anaconda installer deploys, note
there is none related to compression. Instead, use per-file (per-directory)
feature of btrfs to mark files and directories to be compressed. A great
candidate is /usr
which contains most of the system including binaries or
documentation.
One mount option is actually useful which Anaconda does not set by default and
that is noatime
. Writing access times for copy on write file system can be
very inefficient. Note this option implies nodiratime
so it’s not necessary
to set both.
To enable compression for /usr
simply mark this directory to be compressed.
There are several compression algorithms available: zlib (slowest, best ratio),
zstd (decent ratio, good performance) and lzo (best performance, worse ratio).
I suggest to stick with zstd which lies in the middle. There are also
compression level options, unfortunately the utility does not allow setting
those at the time of writing. Luckily, the default level (3) is reasolable.
# btrfs property set /usr compression zstd
Now, btrfs does not immediately start compressing contents of the directory. Instead, everytime a file is written data in those blocks is compressed. To explicitly compress all files recursively, do this:
# btrfs filesystem defragment -r -v -czstd /usr
Let’s find out how much space have we saved:
# compsize /usr
Processed 55341 files, 38902 regular extents (40421 refs), 26932 inline.
Type Perc Disk Usage Uncompressed Referenced
TOTAL 50% 1.1G 2.2G 2.3G
none 100% 337M 337M 338M
zstd 42% 844M 1.9G 1.9G
Exactly half of space is saved on a standard installation of Fedora 33 Server
when /usr
is compressed using zstd algorithm with the default level. Note
some files are not compressed, these are too small files when it does not make
any sense (a block would be used anyway). Not bad.
To disable compression perform the following command:
# btrfs property set /usr compression ""
Unfortunately, at the time of writing it is not possible to force decompression of a directory (or files), there is no defragment command to do this. If you really need to do this, create a script which reads and writes all files but be careful.
Keep in mind the btrfs property
command will force all files to be
compressed, even if they do not compress well. This will work pretty well for
/usr
just make sure there is no 3rd party software installed there writing
files. There is also a way to mark files for compression and if they don’t
compress well btrfs could give up on it. You can do that by setting chattr +c
on files or directories. Unfortunately, you can’t set compression algorithm
that way - btrfs will default to slower zlib
.
Remember: Do not compress everything, specifically directory /var
should
definitely not be compressed. If you happened to accidentally mark files
within /var
to be compressed, you can fix this with:
# find /var -exec btrfs property set {} compression "" \;
Again, this will only mark them not to be compressed, it’s currently not
possible to explicitly decompress them. Use the compsize
utility to find out
how much of data is still compressed.
That’s all for today, I will probably sharing some more btrfs posts.
I am reinstalling my home server from scratch, I want to start using BTRFS which seems like a great fit for what I am doing (NAS, backups). Installation was smooth, no problems, however I noticed that Fedora Server 33 installed both journald and rsyslogd and journal was configured to do persistent logging.
You know, this is weird. On Red Hat Enterprise Linux 7 and 8, journald is
configured in volatile mode and it’s set to forward all logs to syslog. On
Fedora 33, it looks like both rsyslog and journald are logging
(/var/log/messages
and /var/log/journal
respectively). No forwarding is
going on. This is weird, I am going to file a BZ for folks to investigate.
However, I like to only use journald these days, here is how to do it. Stop the journald:
# systemctl stop systemd-journald
Configure journald, if you want use persistent logging there is actually nothing to configure and just make sure the directory exists:
# mkdir /var/log/journal
# systemd-tmpfiles --create --prefix /var/log/journal
If you want to use volatile logging (only in memory), configure as follows (feel free to modify the maximum memory I am just feeling that few megabytes is okay):
# cat /etc/systemd/journald.conf
[Journal]
Storage=volatile
RuntimeMaxUse=5M
Optionally, delete existing logs if you plan using volatile logging:
# journalctl --rotate
# journalctl --vacuum-size=0
Finally, start up the service:
# systemctl start systemd-journald
You may uninstall rsyslog too:
# systemctl disable --now rsyslog
# dnf remove rsyslog
Done!