Wildcard Subdomains in /etc/hosts

This post illustrates how you use a DNS forwarder to manage wildcard subdomains so that you don’t have to explicitly list each subdomain in /etc/host file.

PROBLEM

When trying to map multiple subdomains (ex: a.localhost, b.localhost, c.localhost, d.localhost) to the same IP, it is not possible to do the following in /etc/hosts:

# /etc/hosts

1.2.3.4 *.localhost

Rather, each subdomain has to be explicitly defined:

# /etc/hosts

1.2.3.4 a.localhost b.localhost c.localhost d.localhost

It requires you to babysit and manage these wildcard subdomains over time, but you do have a good job security.

SOLUTION

Configuration

Install a DNS forwarder using Homebrew.

brew install dnsmasq

Create a configuration to map the wildcard subdomains to the same IP.

sudo bash -c \
  'echo "address=/localhost/1.2.3.4" > /usr/local/etc/dnsmasq.d/localhost.conf'

Restart the service.

sudo brew services restart dnsmasq

Create /etc/resolver directory.

sudo mkdir -p /etc/resolver

Create a custom DNS resolver where the file name is the domain name.

sudo bash -c \
  'echo "nameserver 127.0.0.1" > /etc/resolver/localhost'

Verification

Flush the DNS cache first.

sudo killall -HUP mDNSResponder

Verify that ping command on each subdomain resolves to the correct IP.

$ ping -c 1 a.localhost
PING a.localhost (1.2.3.4): 56 data bytes

$ ping -c 1 b.localhost
PING b.localhost (1.2.3.4): 56 data bytes

$ ping -c 1 a.b.c.localhost
PING a.b.c.localhost (1.2.3.4): 56 data bytes

GCP: Accessing GUI-Based App in GCE from Mac using X11

PROBLEM

You want to access a GUI-based software that is installed in a GCE instance without using NoMachine.

SOLUTION

GCE Instance (One Time Configuration)

Ensure X11Forwarding is enabled and set to yes. If not, change it.

grep X11Forwarding /etc/ssh/sshd_config

If a change is made to this file, restart the service.

sudo systemctl restart sshd

Mac (One Time Configuration)

Apple no longer include X11 since OS X 10.8 Mountain Lion. So, you need to install XQuartz, which is an open source version of X.

Using Homebrew, install XQuartz.

brew install xquartz

Reboot the machine. If you don’t reboot, it will not work.

Once rebooted, add the following line to ~/.ssh/config. If this file does not exist, create it.

ForwardX11 yes

This configuration prevents us from explicitly passing the -X option to the SSH command.

Accessing GUI-based software from Mac

Log into GCP.

gcloud auth login

SSH into the GCE instance.

gcloud compute ssh [INSTANCE] --project [PROJECT] --zone [ZONE]

Once you are in the GCE instance, run any GUI-based software from the command line.

Ansible: Handling Multiple Hosts via SSH

PROBLEM

To run Ansible playbook in multiple hosts via SSH.

SOLUTION

Configuring SSH environment

Ensure SSH keypair exists on the current machine (ex: ~/.ssh/id_rsa for private key and ~/.ssh/id_rsa.pub for public key). If you do not have one, create one:

ssh-keygen

Copy the public key (ex: ~/.ssh/id_rsa.pub) to each remote host’s ~/.ssh/authorized_keys. If this file doesn’t exist, create it.

Ensure the current machine’s .ssh/ directory and file have correct permission.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

In the current machine’s /etc/hosts, add all remote hosts.

127.0.0.1      localhost  # current machine
192.168.1.100  donkeykong # remote host 1
192.168.1.200  supermario # remote host 2

In each remote host, enable the remote login and grant yourself the access to this service.

Enabling Remote Login on Mac

Test SSH connection to remote host to ensure they work first before working on Ansible playbook.

ssh user@donkeykong
ssh user@supermario

Creating Ansible Playbook

Create ansible.cfg and define the location of inventory file.

[defaults]
inventory = inventory.yml

Create inventory.yml and define both localhost and remote hosts.

all:
  hosts:
    localhost:
      ansible_connection: local
    donkeykong:
      ansible_user: user
      ansible_ssh_private_key_file: ~/.ssh/id_rsa
    supermario:
      ansible_user: user
      ansible_ssh_private_key_file: ~/.ssh/id_rsa

Run a test to ensure the connection to remote hosts are successful.

ansible all -i inventory.yml -m ping

If successful, the output looks something like this:

localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
donkeykong | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
supermario | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Create main.yml with a very simple task.

- name: all-hosts
  hosts: all
  tasks:
    - name: Capture current dir
      shell: pwd
      register: output

    - name: Display output
      debug: msg='{{ output.stdout }}'

Run the playbook.

ansible-playbook main.yml

If successful, the output looks something like this:

PLAY [all-hosts] *******************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]
ok: [donkeykong]
ok: [supermario]

TASK [Capture current dir] *********************************************************************************************
changed: [localhost]
changed: [donkeykong]
changed: [supermario]

TASK [Display output] **************************************************************************************************
ok: [localhost] => {
    "msg": "/Users/user/myshittycode"
}
ok: [donkeykong] => {
    "msg": "/Users/user"
}
ok: [supermario] => {
    "msg": "/Users/user"
}

PLAY RECAP *************************************************************************************************************
donkeykong                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
supermario                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Controlling the Hosts

Sometimes, you want finer controls on what tasks to be ran in certain hosts.

To run in just one host (ex: donkeykong):

- name: one-host
  hosts: donkeykong
  tasks:
    - ...

To run in all remote hosts except localhost:

- name: all-hosts-except-localhost
  hosts: all:!localhost
  tasks:
    - ...