Captive Portal Restaurant Menu

I have been contacted several times in regards to my captive portal post. In India there seems to be a surge in popularity for restaurants to have an open WiFi that prompts a user to open up a menu/splash page. The caveat being the legal issues encountered when providing free, open wireless internet. In order to avoid legal issues, the device that broadcasts must be disconnected from the internet. Although I am curious if just blocking internet access for those connecting is enough. 

It seems like an interesting issue to tackle, but I think creating something out of a WiFi captive portal would be like hammering a square peg through a round hole. It might work (if given enough time and effort), but in the end, it is probably not the right tool for the job.

While writing this post, I was reminded how Google appears to be tackling this problem. On my Android phone, I let the NSA spy on my whereabouts by enabling location services. It also lets my wife pinpoint where I am physically located. With it enabled, I can visit most shops in my area and get a Google maps prompt with the business information, reviews, and a few pictures. (Side note: if you appear in court over a childish/dumb action, you validate the judge’s decision when you post a negative review of the court house. Also please do not butcher the English language when trying to review places.)

Utilizing GPS location as well as having an app that provides the information seems like the best route to go in this circumstance. An alternative would be to have an app with WiFi credentials hardcoded in, listen for when a WiFi connection is made, check to see if it matches a predefined SSID, and attempt to communicate with a local app server to process data. Of course doing something like that is outside the scope of my tutorials.

Jumping the ship on Evernote

I am a long time user of Evernote. Currently it has the best browser extensions, a wide range of supported operating systems, and it has a free tier; however, I am getting frustrated with it. In the past year, they have changed plans twice – now the free tier is only supported on 2 platforms. This has cost me to re-evaluate my use of Evernote. Lately all I have been using Evernote for is to sync a grocery list between devices and keeping my children’s memories in one location – their sayings, artwork, etc. In the past I also used it for note taking, article saving, and inputting ideas. I have also seriously considered buying a subscription just so I can continue uninterrupted.

While this may be a rant about a free user using a free service, I contribute to the monitization of their service by the viewing of advertisements. The free tier limits (except for maximum devices) are adequate for my occasional use and probably have cost Evernote around $3 total in the past several years. The valuation Evernote has placed on their second-level tier ($35/year) is much higher than I value it (~$12/year). While I may not be able to set the price on what Evernote costs, I can put a price on what I am willing to pay for a simple note service.

A recent article on opensource.com opened my eyes to looking at note taking alternatives. I was surprised at how mature Paperwork was; however, it contained one simple flaw that throws my grocery list experience out the window – no checkbox option. This caused me to evaluate Google Keep – yes, has check boxes, but functions more like sticky notes. Then I remembered Atlassian’s confluence has checkboxes. Their paid version is $10 for up to ten users (per year if it self hosted, monthly if in the cloud). This fits my budget, I can create grocery lists, take notes, and create notebooks/spaces. While I have not switched away yet, confluence seems like a viable option as I already have an always-on home server.

I do not use the kuerig – here is why…

The kuerig device is a visually pleasing design. It appears to belong in the modern kitchen. A few months ago, I was given a kuerig first generation with a reusable filter and used it as my primary coffee consumption device. It gave me a sense of faster coffee delivery in the morning – I was happy until I discovered these flaws:

Flaw #1 – I spent more time making coffee than with a drip machine.

While it had a reservoir of water, that only lasted for about 6 tall glasses of coffee. I would have to switch out the K cup if I wanted a cup in the morning and one to take with – very common thing for me to do. This led me to another flaw.

Flaw #2 – the kuerig is designed for casual coffee drinkers.

By casual I mean 3-6 cups a month. Even with a refillable K cup, I was spending twice the amount on coffee and found myself adding 5 minutes to my normal routine just for use of the kuerig.

Flaw #3 – coffee dust

The coffee ground too much in store bought K cups and my refillable K cup often found itself in the bottom of my glass. This was disgusting and I could not stand throwing away the last sip of coffee because it had coffee dust at the bottom. To combat this, I had to cut filters in the shape of my K cup.

After 2 months of trouble with the kuerig, I got frustrated with drinking coffee. What was designed to be a pleasant, easy experience in making coffee turned out to be painful, time consuming, and more expensive. I evaluated my habit with the kuerig and found I was doing the same exact items with my old drip system, but spent more time affixing it to the kuerig. Once I realized that, I switched back to my old ways, sold the kuerig and bought more coffee with the money.

Debugging PHP web applications

In 2017, this topic seems a little dated and will probably not get me an opportunity to speak at a conference. While all of the elite programmers, cool kids, and CS grads are talking languages such as Go and Erlang – how to do tracing, performance testing, and the like – it seems very juvenile for me to write about PHP.

PHP is a language made specifically for the web. It is the first web language I learned after HTML 4/CSS. I learned it because it was easy. The syntax was easy, the variables – easy, running it – easy; however, when something broke, it was difficult as a beginner to troubleshoot. I would spend several hours looking at the code I just wrote only to find out I missed a semicolon or quote. This post is several things I wish I knew when I started with PHP. Continue reading Debugging PHP web applications

Few posts in the works

I have not posted in a few weeks. This was mainly due to getting a rest from posting every week of 2016! I have a few posts coming in the next few weeks. The first one will be about debugging PHP applications. The second one will be deploying a high availability MySQL cluster – what it looked like 10 years ago, and what it will look like 10 years from now. (HINT: Kubernetes + GlusterFS 😉 )

2016 behind, 2017 forward

With a year drawing to a close, I have a habit of looking back at my goals I set for myself, see how I have done, and set goals for the new year. My new year’s resolution for 2017 will be 1920×1080 (same as last year). I wish I could upgrade it to 5k, but it will have to do for now.

In 2016, I set a goal to post to my blog every week – I met that goal. I also planned to get more certs – of which I achieved my LFCE, COA, and Puppet Certified Professional. I also sharpened my ruby skills.

For 2017, I am not going to write on my blog every week. Instead I will write more lengthy blog posts and tutorials.

In 2016 we saw the Cubs win the world series, Microsoft join the Linux foundation, Google join the ASP.net foundation, and pigs actually flew. I can only imagine what 2017 will hold.

Easy unix epoch timestamps from CLI

While working on various projects and ultimately the need for a Unix timestamp for expiring swift objects in OpenStack, I needed a quick way to convert past, present, and future timestamps to the Unix epoch. Traditionally, I went to google, searched for a Unix timestamp converter, and retrieved my seconds that way. Unfortunately in exams, you are not allowed to visit external websites.

If you know how to read documentation, you will already know that the date command has this feature already built in. An excerpt from the docs is as follows:

 ...
       Show the local time for 9AM next Friday on the west coast of the US

              $ date --date='TZ="America/Los_Angeles" 09:00 next Fri'

DATE STRING
       The  --date=STRING  is  a mostly free format human readable date string
       such as "Sun, 29 Feb 2004 16:21:42 -0800" or "2004-02-29  16:21:42"  or
       even  "next Thursday".  A date string may contain items indicating cal‐
       endar date, time of day, time zone, day of week, relative  time,  rela‐
       tive date, and numbers.  An empty string indicates the beginning of the
       day.  The date string format is more complex than is easily  documented
       here but is fully described in the info documentation.
...

Further reading of the docs will point you in specifically formatting a return string by doing a date +%s. So when the time comes to expire an object from swift at 17:00 next Friday, you can do something like:

swift post container file -H 'X-Delete-On: `date +%s --date="17:00 next Friday"`'

OpenStack PS1 snippet

I have been studying for my OpenStack certification test (the COA) which is scheduled next week. One thing that was painful to keep track of was the user I was using to interface with OpenStack as the rc file you download from OpenStack does not update your PS1 prompt. I came up with the following solution and placed it in my ~/.bashrc:


function parse_os_user() {
    if [ ! "${OS_USERNAME}" == "" ]
    then
        echo "(${OS_USERNAME})"
    else
        echo ""
    fi
}

PS1='\u@\h \w `parse_os_user` \$ '

OpenStack certification

On Dec 20th, I am scheduled to take my COA exam. From the exam requirements page, it appears to be a somewhat moderately difficult exam. The few points I need work on are heat templates and swift object administration. A few things I know about the exam are what are publicly available via YouTube videos of the OpenStack summit sessions.

One of my troubles of studying for exams is creating content to test myself on the objectives of the exam. I look at the requirements and say to myself, “I know that,” and nothing gets written for that aspect. One thing I have done in the past is to search Github for exam prep questions. One I have found for OpenStack is AJNOURI/COA. He also made a nifty website for his test prep questions.

A key aspect that has helped me pass all of my open book exams is to recall the locations of my troubled areas. Looking at the docs/reading the manual has often come a best practice of mine. Most of the time, exam questions are covered in the docs as the exams expect you to have read them.

Docker is not a source to blame

I have been reading a few articles that have been published recently regarding the use of docker in production. Of the articles I read, all seem to complain about the instability of docker, the docker ecosystem, and they lament persistent storage. While I have not run docker in production for a lengthy amount of time, I can determine these issues are from operator error and are not entirely docker’s fault.

One article I read came out and boldly said that docker created a new file system in one year and it is not humanly possible to have created one in such a short amount of time. I think this article writer has never heard of the DevOps philosophy nor the minimum viability product (MVP). Basically, you do not need 100% of the features to have a working product. This makes it clearly possible to build a single file system – though not have all of the features – within a short time frame. It is also noted that a year in this development process, a second file system was created. Just like in real life, if you wait to ship a product with 100% of the features, you will never ship the product.

If you are losing data due to not properly mounting the volumes to a HA storage network (such as GlusterFS or DRBD) – you deserve to have lost the data. I know what it is like to lose 50TB of unique data due to a failed storage device, no current backups, and the shame and cost of having to send it over to DriveSavers (which they are!) for recovery. That is a painful experience and not worth repeating. If you do the same thing and expect different results, the issue lies with the operator and not the tool. Drastic changes were made when loss occurred including developing a new backup solution and having 1-to-1 replication of the data. It has also fine grained a permanent memory in my subsystem to not let that happen ever again.

Personally, I think running docker in a public cloud is a waste of company resources – there is no price difference between a VM and 1 docker image on AWS’ EC2 container platform of the same capacity. Even if you spun up an Atomic Host or similar, you still have to deal with networking constraints for your file storage. This is something best handled in house as you can scale your network infrastructure to match your workload.

The most important factor in all of this fuss about docker is that it is open source software. If you do not have the capacity to find flaws, make patches, and submit those patches for review to upstream, you are better off using a proprietary product that does not have such needs. Again, the issue lies in the operators and not the tools.

Day after Thanksgiving ritual

My wife and I adopted a tradition on the day after Thanksgiving – after a full night’s sleep – we visit stores and go shopping around 10am. Yes, the lines are still crazy, but the people who woke up at 5am to wait in line are already gone. With grandparents watching our children, it is one of our best stress-free shopping experiences. No doubt – we are doing it again today.

Using Puppet to host a private RPM repository

A repository is a place where files are stored, indexed, and available through a package manager to anyone who has the repository information. With rpm based systems, a repository is created with a tool called createrepo. Most of the time, publicly available repositories already offer the packages your server needs. When you have a custom application you want to deploy (or even rebuild an existing application with your patches), it is best to distribute that package with a repository rather than a file share or some other means. Often a folder structure is created so that differing client OS versions can connect to the same repository and access versions compiled to that specific release. In my example below, I am not creating this folder structure as I am only serving one major release – Centos 7 – and the packages I am generating are website directories which are just a collection of portable code.

A private repository is not a tricky feat – all you have to do is serve the repository via https and require http basic authentication. You then configure the clients to connect to the repository with the basic authentication in the URL string (i.e. baseurl=https://user:pass@repo.example.com/). The HTTPS protocol is not required to serve a repository, but it does prevent network snoopers from seeing your repository credentials.

Now that we know what is needed for a private repository, we can then define it in our puppet code.

node 'repo.example.com' {

  file { '/var/yumrepos':
    ensure => directory,
  }

  createrepo { 'yumrepo':
    repository_dir => '/var/yumrepos/yumrepo',
    repo_cache_dir => '/var/cache/yumrepos/yumrepo',
    enable_cron    => false, #optional cron job to generate new rpms every 10 minutes
  }

  package { 'httpd':
    ensure => installed,
  }

  httpauth { 'repouser':
    ensure    => present,
    file      => '/usr/local/nagios/etc/htpasswd.users',
    password  => 'some-long-password',
    mechanism => basic,
    require   => Package['httpd'],
  }

  file { '/usr/local/nagios/etc/htpasswd.users':
    ensure => file,
    owner  => 'nginx',
    mode   => '0644',
  }

  class{'nginx':
    manage_repo    => true,
    package_source => 'nginx-mainline',
  }

  nginx::resource::vhost{"$::fqdn":
    www_root             => '/var/yumrepos/yumrepo',
    index_files          => [],
    autoindex            => 'on',
    rewrite_to_https     => true,
    ssl                  => true,
    auth_basic           => 'true',
    auth_basic_user_file => '/usr/local/nagios/etc/htpasswd.users',
    ssl_cert             => "/etc/puppetlabs/puppet/ssl/public_keys/$::fqdn.pem",
    ssl_key              => "/etc/puppetlabs/puppet/ssl/private_keys/$::fqdn.pem",
    vhost_cfg_prepend    => {
      'default_type'     => 'text/html',
    }
  }

}

For the above code to work, we need the required modules:

mod 'palli/createrepo', '1.1.0'
mod "puppet/nginx", "0.4.0"
mod "jamtur01/httpauth", "0.0.3"

We can then use the following declaration on our nodes to use this repository.

yumrepo {'private-repo':
  descr           => 'My Private Repo - x86_64',
  baseurl         => 'https://repouser:some-long-password@repo.example.com/',
  enabled         => 'true',
  gpgcheck        => 'false',
  metadata_expire => '1',
}

You now have a fully functional private repository – deploy your awesome software.

Website protection

There are several factors that go into securing a web application. Most are second nature to seasoned system administrators, but it is still too common to talk to someone who does not know how to properly secure a web application. Here is the common checklist I go through when I determine if a website is secured.

  • Is it using a firewall?
  • Am I using unique passwords that are over 20 characters?
  • Are passwords required to alter data?
  • Is my codebase up to date?
  • Are the only public facing ports HTTP and HTTPS?
  • Do I protect data in transit from the user to my site by enforcing HTTPS?
  • Do I protect data from my website to the database with SSL?
  • Is my database only accessible to my application?
  • Do I have my database and application on different servers?
  • Can a malicious user drop/delete/alter data from my database from a form/switch/button that is publicly accessible on my website or do they need to login to perform that operation?
  • Do I have separate connections and users to the database for writing and reading data?
  • Do I rate limit connections via web application firewall or utility like fail2ban?
  • Am I reading and blocking malicious inputs via web application firewall or mod_security?
  • Can anyone brute force a login or am I blocking it after 5 tries?

So the Cubs won the world series

I am still in shock that the Chicago Cubs won the World Series in Baseball which ended their 108 year drought. Last time the Cubs won the world series, they won it back-to-back. I can expect nothing less this time around. 😀

GlusterFS overview

GlusterFS is a distributed file system. Think of it as a replacement of traditional file storage (a single NFS/samba server), an alternative to Microsoft’s DFS, or a modern implementation of SAN. It really shines when you have multiple locations and need a file server which must have the same data and be continually in sync. It is also superb for virtual machine disks as they will then become highly available.

You can use GlusterFS in a replica, distributed, and distributed-replica models. Replica is where a copy of file a is located on all GlusterFS hosts. Distributed is where file a is on some hosts and file b is on the other hosts. Distributed-replica is a combination of both – in other words a subset of two distributed hosts in a parent of replicas.

To get started with GlusterFS, all you need is commodity hardware. Nothing has to match – not even the harddrive space. GlusterFS will configure the storage allocation pool automatically. I do recommend at least a 1GB NIC connection and a large internet pipe between locations. Partitioning your system appropriately must also be considered – have a separate mount for /var/log and /data. Keeping /data as the location of your shares makes adding and removing nodes consistent with the documentation.

You need at least a multiple of 2 GlusterFS hosts to experience replica, distributed (minimum of 2 hosts), and (minimum of 4) distributed-replica. If you plan on serving Virtual machines off of the GlusterFS volume, multiples of 3 are recommended. Clusters can also be geographically bound so that if one node fails, your clients will connect to another gluster server in that region rather than just any gluster node.

The quick start documentation goes over setting up two nodes, pairing them together, connecting via the GlusterFS protocol on your client, and creating 100 files. In total, this is about 6 commands.

For managing a large cluster of GlusterFS servers, one may want to take a look at heketi which manages the lifecycle of GlusterFS. Facebook also developed a tool called AntFarm, but it is currently closed source.