Enable EPEL Repository on Amazon Linux

Amazon Linux provides an easy way to install / enable the EPEL yum repository from the command line.

Use the amazon-linux-extras command to enable the epel feature, and then install the repository:

amazon-linux-extras enable epel
yum install epel-release

To see which packages are available via amazon-linux-extras, just type the command without any arguments.

Rails new fails to create all of the content…

I recently deployed a Rails app on a CentOS 8 container and was surprised to see that the ‘rails new’ command did not create the entire application directory structure that I would expect, ie:

[root@607ebc931c48 app]# rails _5.2.3_ new centos_app_2
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."

I didn’t know that git was a requirement now for rails apps, so the issue was resolved by installing the git client.

# dnf install -y git

To get a rails application created using a CentOS 8 docker container, use the following steps. This will assume rails 5.2.3 and ruby 2.6.3:

docker run -i -t --rm -v ${PWD}:/usr/src/app centos:8 bash
dnf install curl git gnupg2 which -y
gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source /etc/profile.d/rvm.sh
rvm requirements
rvm install 2.6.3
gem install rails -v 5.2.3
rails _5.2.3_ new centos_app

Note that the container actually takes quite a bit to build, so making an image would be more useful as subsequent rails commands could be run more easily.

Unique UserAgent

I saw this line in a server log this morning and thought it was humorous – if you’re going to spoof the UserAgent, why not do it right? - $virtual_host.com - [06/Feb/2020:07:21:11 -0800] "GET /.env HTTP/1.1" 301 238 "-" "Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36"

I better go find Mozlila with my Moblie!

This is a poor hack attempt to get an .env file that would have environment credentials in it. That’s a pretty common method of deploying credentials to Rails apps.

MacBook Pro – Swollen Battery – Heat Management

I’ve been using the MacBook Pro platform for daily business operations for years now.

One issue I’ve suspected is that if you leave the laptop display closed for extended periods of time, the laptop can heat up enough to cause the battery to swell.

This happened on my most previous MacBook and I’ve just noticed it happening on my current MacBook. The first symptom is that the laptop will not stay closed all the way and sealed around the edges. I’ve found that if I leave the lid open, the laptop will run much, much cooler. I’ve also purchased a laptop stand that will hold it vertical that I may try, although I’d prefer to keep the lid open and have it lay flat.

Anyone else experienced this issue? I checked on the last laptop and it was not covered by the recall.

Why is rails 5.2 joining to the same table twice?

I was working on a Rails project for a client recently where I was trying to figure out why a model search operation was joining to the same table twice, resulting in a huge performance hit. The answer turned out to be an incomplete understanding of the ‘has_many’ ‘:through’ relationship.

Given a model with the following relationships (using the rails documentation example):

class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments

I added a search method to return results based on web form input of a begin timestamp, end timestamp, and search term. I am also using the will_paginate gem. Also, my dataset is large enough that I do not want to return results without input parameters:

  def self.search(search, current_page, begin_timestamp, end_timestamp)
    if search
      if search.length > 0 
        Physician.includes(:patients, :appointments).where('patients.updated_at BETWEEN ? AND ?  and patients.name LIKE ?', "#{begin_timestamp}", "#{end_timestamp}", "%#{search}%").references(:patients, :appointments).paginate(page: current_page, per_page: 15).order('patients.name ASC').distinct

This resulted in a query (as seen in the mysql console and the rails application logs) that joined to the appointments table twice. Once for the has_many, through association, and once for the includes, references as added to the model.

The answer ended up being to remove the reference to appointments in the Physician model.

  def self.search(search, current_page, begin_timestamp, end_timestamp)
    if search
      if search.length > 0 
        Physician.includes(:patients).where('patients.updated_at BETWEEN ? AND ?  and patients.name LIKE ?', "#{begin_timestamp}", "#{end_timestamp}", "%#{search}%").references(:patients).paginate(page: current_page, per_page: 15).order('patients.name ASC').distinct

This optimization increased performance by a huge margin. The application is now usable.

Serving static content with Nginx via Docker

I was playing around with the nginx docker container recently and wanted to serve the content from the local directory that I was in (pwd). This is how I ended up doing it:

docker run --name nginx -d --rm -p 8080:80 -v $(pwd):/usr/share/nginx/html nginx:1.7 

That will launch an nginx docker container and serve whatever is in the local directory, as static content, and map the docker container port 80 to the localhost port 8080.

Note that the


flag will remove the container when stopped.

Ubiquiti Cloud Key Upgrade – Can’t Login to Web UI


A recent update to the UCK (Ubiquiti Cloud Key) controller software to add controller version caching caused the device to not start properly. Updating the unifi package via apt and rebooting solved the issue. SSH using the root account and your user password.

apt update
apt upgrade -y
shutdown -r now


I recently upgraded the firmware on my Ubiquiti Cloud Key and was not able to login to the UI this morning. I was able to get to the non-SSL port but was having trouble logging in using any combination of known credentials.

I was able to login via SSH and perform some investigation on the Cloud Key. To login via SSH, use the root account with your account password.

Controller software: v5.11.50
Cloud Key software: v1.1.6

The nginx config for the Web UI indicates the service will listen on all interfaces, using IPv6:

server {
        listen [::]:80 ipv6only=off;
server {
        listen [::]:443 ssl ipv6only=off;
        ssl_protocols TLSv1.2;

I changed this to use IPv4 only, and restarted nginx:

server {
        # listen [::]:80 ipv6only=off;
        listen *:80;

server {
        # listen [::]:443 ssl ipv6only=off;
        listen *:443 ssl;
        ssl_protocols TLSv1.2;

I was still not able to access the Web UI on port 8443, so I checked /etc/ for whatever was listening on that port, that was not working:

root@UniFi-CloudKey:~# egrep -iR 8443 /etc/
/etc/bt-proxy/services.d/unifi.json:    "host": "https://localhost:8443",

It looks like the unifi service is not started. I looked for the right service to restart using systemctl:

root@UniFi-CloudKey:~# systemctl | egrep -i unifi
bt-proxy.service                                                                             loaded active running   UniFi CloudKey Bluetooh API
ubnt-unifi-setup.service                                                                     loaded active exited    Ubiquiti UniFi Setup service
unifi.service                                                                                loaded active running   unifi

I then restarted the service:

sysctmctl restart unifi

That did not work. Even a reboot results in the same behavior.

Maybe we’re out of disk space?

root@UniFi-CloudKey:~# df -h
Filesystem                     Size  Used Avail Use% Mounted on
aufs-root                      2.9G  222M  2.7G   8% /
udev                            10M     0   10M   0% /dev
tmpfs                          404M  444K  404M   1% /run
/dev/disk/by-label/userdata    2.9G  222M  2.7G   8% /mnt/.rwfs
/dev/disk/by-partlabel/rootfs  329M  329M     0 100% /mnt/.rofs
tmpfs                         1009M     0 1009M   0% /dev/shm
tmpfs                          5.0M     0  5.0M   0% /run/lock
tmpfs                         1009M     0 1009M   0% /sys/fs/cgroup
tmpfs                         1009M   64K 1009M   1% /tmp
/dev/mmcblk0p8                  11G  1.1G  9.3G  10% /srv
/dev/mmcblk1p1                 7.2G   17M  7.2G   1% /data

The /dev/disk/by-partlabel/rootfs volume is 100% full, but that might be a read only device with firmware. More to look at there.

In reviewing the filesystem further, it looks like the unifi logs are at /srv/unifi/logs/server.log. This log suggests that the [mongo] database cannot be upgraded to the version requested:

[2019-12-03T09:17:32,155]  WARN  db     - DbServer cannot start due to memory error, restarting with repair
[2019-12-03T09:22:21,198]  ERROR db     - We do not support upgrading from 5.12.35.

Firmware version: UCK.mtk7623.v1.1.6.c289a3c.191031.0856

A little searching for the unsupported upgrade error resulted in finding a thread that suggested upgrading via apt, followed by a reboot:

apt update
apt upgrade -y
shutdown -r now

It looks like the root cause of this issue is that version 1.1.6 of the controller includes caching and this may have caused the break.

Rails timestamp search using datetime_field_tag

I recently worked on an issue when creating a Rails form to search and display objects by timestamp and spent far too much time troubleshooting an issue with the datetime_field_tag form helper.

The issue began with the following two lines in my view:

    <%= datetime_field_tag(:begin_timestamp, params[:begin_timestamp]) %>
    <%= datetime_field_tag(:end_timestamp,   params[:end_timestamp]) %>

Evidently, you cannot place more than one space between the name assigned to the form helper and the value to populate in the form helper. The above two lines don’t format well in this wordpress blog post, but there are 3 spaces between ‘:end_timestamp’ and ‘params[:end_timestamp]’. The parameter was passed to the controller, and the code worked, but it would not display the current selection in the datetime_field_tag on submit.

The fix was to remove the additional formatting spaces, ie:

    <%= datetime_field_tag(:begin_timestamp, params[:begin_timestamp]) %>
    <%= datetime_field_tag(:end_timestamp, params[:end_timestamp]) %>

Hope this helps somebody. I spent far too much time on this.

More info:

> rails server
=> Booting Puma
=> Rails 5.2.3 application starting in production
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.6.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: production
* Listening on tcp://
Use Ctrl-C to stop

Windows Permissions – Unable to enumerate container…access denied

One of the greatest reasons I prefer not working with Microsoft Windows is that the intent behind managing Windows seems to be to make it as difficult as possible for an administrator to do their job. In theory, I suppose the intent is to make it difficult for a determined hacker to break the defenses but in practice it wastes a ridiculous amount of time and resources in the form of management and upkeep. (This is a lot like a government creating laws to control the lawless – it merely serves to inconvenience or criminalize the law-abiding.)

I was working on a recent issue with Windows Server 2012 R2 where I needed to add some local accounts to a directory that was used by Tableau Server. After having started the license service using a powershell window that had been started with elevated administrator privileges in a previous session, I was then blocked from starting the license service in the current one. I was also blocked from opening the log file, which happened to be the issue here. I was blocked from changing permissions on the file to be owned by any domain administrator accounts, any local administrator accounts, and the local administrator account.

The end result was that I logged into the machine using RDP, I navigated to the directory location using the CIFS share, via UNC, and then deleted the file using a domain account that was in the local administrators group. Be sure to reboot after this step. I hear that this might be a bug that might be patched.

What a waste of my time, having to figure this out. Thanks to a few experts on the MS technet site for having had to waste their time figuring this out.

Easy Jenkins Deployment on AWS

Easy steps to install / configure Jenkins on AWS Amazon Linux:

Install latest updates, set the hostname, and reboot.

yum -y update
hostnamectl set-hostname jenkins
shutdown -r now

Configure the Jenkins yum repository, install Jenkins, java, git, set Jenkins to start and persist on reboot:

sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
yum -y install java-1.8.0-openjdk
yum -y install jenkins
chkconfig jenkins on
yum -y install git

Install and configure nginx to proxy request for Jenkins — reboot and validate:

yum -y install nginx
sudo amazon-linux-extras install nginx1.12
chkconfig nginx on
shutdown -r now