ssh-import-id-gh – Import your public SSH key from GitHub

The (WordPress) developers often use wp-cli to troubleshoot sites hosted in remote servers. While I don’t recommend working with a production site directly, these days most hosted WP companies offer staging sites with SSH access, with wp-cli pre-installed. In order to log into those, most of us use password authentication that can lead to a number of security issues. For example, finding the username means half the work done. It is easy to find username these days.

Importing the public SSH key is one of the recommended ways to get access to the remote environment these days. I have seen a number of issues while sharing my own public SSH keys to the clients and their DevOps, who experienced trouble before importing the keys successfully onto their servers such as while copy / pasting the key. This takes away precise time if the sites / servers are down.

I use a simple, quick and effective method that has never failed. In every Linux server, a command named ssh-import-id exists for years (since 2014 as far as I know). It goes with the format…

ssh-import-id launchpad_account_name

launchpad_account_name is the name from launchpad.net. My launchpad username is pothi. My SSH keys attached with launchpad can be viewed at launchpad.net/~pothi/+sshkeys. So, running ssh-import-id pothi will import my public SSH key into any Linux machine.

Since the popularity of GitHub, `ssh-import-id` started supporting SSH keys stored in GitHub. My Github username is pothi and my public SSH key can be found at github.com/pothi.keys and also at API URL. As you see, I use ed-25519 key with GitHub and rsa key with launchpad so that I can import either if one is not supported. To import my Github associated public SSH key, one of the following commands can be used…

ssh-import-id-gh pothi
# or
ssh-import-id gh:pothi

For more details on ssh-import-id, please checkout the corresponding man page at https://manpages.ubuntu.com/manpages/lunar/en/man1/ssh-import-id.1.html.

Do you use ssh-import-id or ssh-import-id-gh? If not, what else do you use to get the remote server access?

Bootstrapping DigitalOcean Servers

I manage multiple DigitalOcean servers. There are a number of configurations to be done in order to bring a secure DO droplet. For example, firewall, alerts, etc. I missed a step years ago that caused a low priority security alert lately. So, I automated most of the steps while configuring any DigitalOcean server (new or old).

Like most other things, I open-sourced the project in Github. Please check it out at https://github.com/pothi/doctl-automation .

The first step is to get an API key and to get doctl command line interface tool. Then you can initialize doctl with the API key as follows…

# you will be asked the access token
# <NAME> could be "team-name"
doctl auth init --context <NAME>

# Authentication contexts let you switch between multiple authenticated accounts.
doctl auth list
doctl auth switch --context <NAME>

# validate doctl
doctl account get

Firewall

Firewall is obviously the most important of any server configuration. With DigitalOcean, you don’t have to rely on the server-level firewall such as ufw. With a server-level firewall, it is possibly to lock yourself out of the server. With DigitalOcean (and most other cloud providers), the firewall can be configured and updated on the host level, a layer above the server or the operating system installed in it. Here I used a simple firewall with the name “Basics” that covers the basic stuff…

Firewall_Name=Basics
# create a firewall using minimal outbound rules
Outbound_Rules="protocol:icmp,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:0,address:0.0.0.0/0,address:::/0 protocol:udp,ports:0,address:0.0.0.0/0,address:::/0"
doctl compute firewall create --name $Firewall_Name --outbound-rules "$Outbound_Rules"

# Get FirewallID using FirewallName
Firewall_ID=$(doctl compute firewall ls --format ID,Name --no-header | grep $Firewall_Name | awk '{print $1}')

# Add tags, standard inbound rules and any custom inbound rules
doctl compute firewall add-tags $Firewall_ID --tag-names live,prod

Inbound_ICMP="protocol:icmp,address:0.0.0.0/0,address:::/0"
Inbound_HTTP="protocol:tcp,ports:80,address:0.0.0.0/0,address:::/0"
Inbound_HTTPS="protocol:tcp,ports:443,address:0.0.0.0/0,address:::/0"
Inbound_SSH="protocol:tcp,ports:22,address:0.0.0.0/0,address:::/0"

doctl compute firewall add-rules $Firewall_ID --inbound-rules $Inbound_ICMP
doctl compute firewall add-rules $Firewall_ID --inbound-rules $Inbound_HTTP
doctl compute firewall add-rules $Firewall_ID --inbound-rules $Inbound_HTTPS
doctl compute firewall add-rules $Firewall_ID --inbound-rules $Inbound_SSH

# delete a firewall rule
doctl compute firewall remove-rules $Firewall_ID --inbound-rules=$Inbound_SSH

Internal Firewall

If you’d like to allow traffic between servers, you may use the following…

# Internal Firewall
Firewall_Name=InternalNetwork

Internal_10="protocol:tcp,ports:0,address:10.0.0.0/8"
Internal_10_udp="protocol:udp,ports:0,address:10.0.0.0/8"
Internal_172="protocol:tcp,ports:0,address:172.16.0.0/12"
Internal_172_udp="protocol:udp,ports:0,address:172.16.0.0/12"
Internal_192="protocol:tcp,ports:0,address:192.168.0.0/16"
Internal_192_udp="protocol:udp,ports:0,address:192.168.0.0/16"

doctl compute firewall create --name $Firewall_Name --inbound-rules "$Internal_10 $Internal_10_udp $Internal_172 $Internal_172_udp $Internal_192 $Internal_192_udp"

Once the firewalls are created, you may attach them to any existing droplets or new droplets (while creating the droplets) using tags. DigitalOcean has some powerful tagging system that works nicely.

Monitoring

A big part of any server setup is monitoring and alerting us upon any usual activities. While monitoring is a complex topic, DigitalOcean allows us to monitor the resources such as the disk space, memory usage, CPU spikes, etc. All these things can be configured in a flash using the following code that becomes applicable to all droplets (existing and new)…


ADMIN_EMAIL=$(doctl account get --format "Email" --no-header)

doctl monitoring alert create --compare "GreaterThan" --value "90" --emails $ADMIN_EMAIL --type "v1/insights/droplet/cpu" --description "CPU is running high"
doctl monitoring alert create --compare "GreaterThan" --value "75" --emails $ADMIN_EMAIL --type "v1/insights/droplet/disk_utilization_percent" --description "Disk Usage is high"
doctl monitoring alert create --compare "GreaterThan" --value "90" --emails $ADMIN_EMAIL --type "v1/insights/droplet/memory_utilization_percent" --description "Memory Usage is high"

What’s still not implemented?

While the existing API is matured enough, it doesn’t have all the functionalities that can be done on the DigitalOcean dashboard. For example, a few months ago, DigitalOcean introduced uptime monitoring that can not be configured via doctl, yet!

Nevertheless, DO API is stable and I highly recommend it if you plan to use DigitalOcean to host your sites or your clients’ sites.

Happy Hosting!

Brotli on Nginx

Brotli compression was introduced by Google, exactly 3 years ago. It is yet to come by default with the standard Nginx packages of OS vendors or the official Nginx repo. Google maintains its own repo for brotli support on Nginx web server. However, it’s been two years since we had the last commit. Fortunately, a Googler, named Eugene Kliuchnikov, continues to develop a fork of Google’s repo. There are even plan to merge both repos. Still, there isn’t an easy way to compile Nginx from source.

Continue reading “Brotli on Nginx”

Local LEMP Box

I develop sites locally, then migrate the changes to the staging site or to the live site. I never make changes without testing them in my local server. I already have a repo to bootstrap a live server with Nginx, MySQL, PHP and a few more other goodies. However, there are lot of areas to improve to speed-up the development of local sites. For example, PhpMyAdmin runs on its own domain named https://pma.dev (it doesn’t exist on the internet, just a local domain). Since, I do not expose my local server to the internet, I wouldn’t want to enter the credentials whenever I type it in my browser. It saves time! So, here’s my next project… local LEMP server.

Note: This works only on Linux servers and desktops (such as Juno from Elementary OS). Particularly tested on Ubuntu 18.04 based distros. There are a number of alternatives available if you wish you to develop sites locally on a mac or on a Windows PC. Since, I host most of the sites on the latest LTS version of Ubuntu, it make sense to closely resemble the live environment.

Continue reading “Local LEMP Box”

Oops Moments in DevOps

A post on a new year is usually about resolutions! But, isn’t the best time to revisit the last year’s mistakes and resolve to never repeat it this year (and years to come)?! Since, my strong skills are with DevOps, I’d like to share some oops moments (you may call them blunders) that you’d never want to do it, if you are starting on DevOps or if you just want to understand where things go wrong in DevOps. In general, you go by the defaults, you’d be in trouble in the future. Whatever software you use, make sure you understand the default values and what each of them does! Here are the top three mistakes that I did… Continue reading “Oops Moments in DevOps”

css.php