All about git pull

All about git pull

Because you know
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull

Yeah, it’s pretty clear, I ain’t no guru
But I can break it, break it
Like I always do.
And now I got that pull request, that we all want.
With all the right code in all the right places.

I see that manual push with rsync
We know that shit aint right
It caused my script to stop.
If you got fixes fixes, just check ’em in
So every line of code is peer reviewed
from the bottom to the top

Yeah, my coworker he told me don’t worry about the style
He says “We just need a little more testing to make it right.”
You know I won’t trust the logs to /dev/null
So if that’s where you put them then you better use syslog.

Because you know
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull, no copies
I’m all about git pull
’bout git pull

Radio Musings

Completely unrelated to the post below, I discovered that some has forked a copy of my website on github. I’ve actually migrated from the static site to Mezzanine, but the repo is still in place. I was very surprised someone has forked it. I checked the user out and he recently forked a large number of repositories, all related to docker or coreos type things. It appears that “builtdock” is putting together some sort of platform as a service offering. I wonder if forking my site was an accident, or if they are planning to use it as a base of making their own static site.


I recently took my Raspberry Pi, connected a GPS, installed Xastir and have that setup as a sort of tactical display in my office. [](https://lh3.googleusercontent.com/–RicSliZ2kE/VDb9oB4auGI/AAAAAAAAT1M/eCkTaa8AIEg/w876-h1168-no/14%2B-%2B1 target=”_new”).

I have some interesting things I came across recently.

The first interesting project is from hackaday, a 0-30Mhz Portable SDR with transceive capabilities, opens-source design. It’d be interesting do this, but use a Pi+Touchscreen for the CPU portion.

http://hackaday.io/project/1538-portablesdr

The second one has been around for a while, and it’s called Earl. This is a crowd-funded, e-ink touchscreen android system with gps, built-in maps, and a VHF/UHF transceiver for GMRS/FRS/2m/70cm walkie talkie type capabilities. The radios are software defined, so something like DroidAPRS would be able to talk to the radio directly (perhaps with a bit of coding). I’ve been keeping and eye on this project (because I want one), but never thought it would actually materialize due to FCC rules concerning GMRS and FRS type radios. However they are now actively working through the FCC approval process and modifying the radio portions to get acceptance. I am hoping that enough get produced that some of these end up on ebay by non-hams that are disappointed in the radio communications aspect.

Python Modules and Single App OS

Emacs standing alone on a Linux Kernel. I’m not an emacs user, but I thought this was really fascinating. Basically, the author took the linux kernel, a statically compiled copy of emacs, the mount command, and that’s it. You could dd that to a hard drive and boot into only emacs. This gets me thinking about what I’m going to call SAOS – Single Application OS. Sort of like the python on a chip scene.

Python Apps the Right Way: entry points and scripts a very nice tutorial on making a python module, complete with setup.py. This one is very straightforward and simple. I’ll be referencing it and redoing some of the code I’ve worked on.

Salt The Earth

Learning Salt

I am just beginning to read up on SaltStack, but I am really liking it. It has a number of things I like from Ansible (separation from code and state), the targeting abilities of mcollective, and the centralized control of Puppet/Chef. Salt can be run masterless, but in a master/minion configuration, it uses a message queue (0mq) to control minions and get information back. All messages in this queue are encrypted using keys on both the minion and the master. If you distribute this key, you can consume salt generated data in other programs.

Running commands across all minions could look lik this:

salt '*' test.ping
salt '*' disk.percent

In these, test.ping and disk.percent are known as ‘execution modules’, which are essentially python modules that contain defined functions. For example, disk would be an ‘execution module’ and “percent” would be a function defined. Here, test.ping runs on all target hosts and returns “True”; disk.percent returns the percentage of disk usage on all minions.

You can also run ad-hoc commands.

salt '*' cmd.run 'ls -l /etc'

Of course, you can target blocks of systems by hostname (web* will match web, web1, web02, webserver,..). Salt also has something called Grains which everyone else calls facts. You can target based on the grains, or use salt to provide a report based on the grains. The following command will return the number of cpus for every 64-bit cpu.

salt -G 'cpuarch:x86_64' grains.item num_cpus

I think this would work as well:

salt -G 'cpuarch:x86_64 and num_cpus:4' test.ping

If not, these would work (Compound match):

salt -C '[email protected]:x86_64 and [email protected]_cpus:4' test.ping
salt -c '[email protected]:Ubuntu or [email protected]' test.ping

Salt States

In Puppet, your manifests and modules are very closely coupled in puppet code. In Ansible, they separate things into modules and “playbooks”. These playbooks are yaml files detailing what modules and values for ansible to use. Salt follows this pattern as well, separating execution modules from states with “Salt States”, aka SLS formulas (aka state modules).

A sample SLS formual for installing nginx would look like this:

nginx:
  pkg:
    - installed
  service:
    - running
    - require:
      - pkg: nginx

Assuming you save that in the right spot (/srv/salt/nginx/init.sls), you can apply this state module to all servers starting with the name ‘web’.

salt 'web*' state.sls nginx

So with one tool, you can query a large amount of data from all your minions, move them to a specific state, run ad-hoc style modules, etc. This can also all be expanded by writing your own python modules. Also, I’m mostly interested in the ability to target modules and groups of hosts in one command, but it’s worh noting that salt will do scheduling of jobs just like puppet and chef do.

Codebox in Docker

This is a quick note log. I was able to setup a self-hosted web IDE for programming. Today I tested out codebox.io,
but I also want to check out the open source Cloud9 IDE.

  • Codebox.io an open-source Web IDE for programming (in your browser)
  • Docker an open source container
  • Docker-Codebox. All I really want is this guy’s Dockerfile.

I already have Docker installed, that’s the easy bit.

Build the box:

git clone https://github.com/forty9ten/docker-codebox.git
cd docker-codebox
docker build -t ytjohncodebox .
# much building occurs

Run codebox in docker

This will run the codebox.io environment on port 8000 and you’ll be editing files that are stored in a directory
called workspace1. ~/workspace1 on the host gets mounted into /workspace1 in the container.

cd ~
mkdir workspace1
docker run -p 8000:8000 -v ./workspace1:/workspace1 -t ytjohncodebox -p 8000 run /workspace1
# many things happen
# I end up seeing this:
# Codebox is running at http://localhost:8000

Now, I can access my server on port 8000 (ie, http://192.168.1.32:8000/). This instance is unprotected, it just asks
for an email to get started. But the part I skipped over is that I am actually using nginx to proxy and password
protect this instance.

I can hit Ctrl+C on the terminal to cancel my instance and all my edited files are safely stored in ~/workspace1.

Interesting bits:
I create a new file in the web browser and save it, I see this bit of json in the console output:

[events] watch.change.create : { change: 'create',
  path: '/irule.txt',
  stats: 
   { current: 
      { dev: 64513,
        mode: 33188,
        nlink: 1,
        uid: 0,
        gid: 0,
        rdev: 0,
        blksize: 4096,
        ino: 262847,
        size: 27,
        blocks: 8,
        atime: Wed Feb 26 2014 05:18:44 GMT+0000 (UTC),
        mtime: Wed Feb 26 2014 05:18:42 GMT+0000 (UTC),
        ctime: Wed Feb 26 2014 05:18:42 GMT+0000 (UTC) },
     old: null } }

One thing I really need is the ability to open a web terminal. When I do though, the terminal window appears for a
few seconds, and then vanishes. In the console, I see this:

[log][shells.stream] new socket connected
[log][shells.stream] open shell  { shellId: 'term2020-44',
  opts: { rows: 80, columns: 24, id: 'term2020-44' } }
[log][events] shell.spawn : { shellId: 'term2020-44' }
[log][events] shell.attach : { shellId: 'term2020-44' }
[log][events] shell.open : { shellId: 'term2020-44' }
[log][events] shell.exit : { shellId: 'term2020-44' }
[log][shells.stream] socket disconnected
[log][shells.stream] socket disconnected
[log][hooks] use hook settings

I got this same issue going through my nginx proxy and connecting directly on port 8000. A bit of text flashes
quickly on the “terminal” in the web browser, but closes too quickly for me to catch it. Perhaps it’s attempting to
run something that is not installed in the Docker instance. If I can fix that, then I just need to come up with a cool
way to launch workspaces and tie them into my nginx setup (or switch over to hipache
as my front-end webserver).

Anyways, just wanted to record these steps here and show how easy it could be to get your own self hosted IDE.

C270 Review

Acer C270 Chromebook

Last week I picked up a Chromebook, specifically the Acer C270. One of my coworkers uses one and kind of convinced me that one would be worth checking. I compared what was out there and other than the Pixel, the C270 had the best specs, including battery life (8.5 hours). It’s an Intel chipset, 16GB space, 2Gb of RAM, 1.4Ghz.

The good:

  • You get a lot of functionality for $200.
  • 7 seconds from power off to browser up and running.
  • Both an ssh client and vim are installed by default.
  • The keyboard is fairly responsive.
  • Runs forever without needing a charge.
  • You can install a real OS alongside ChromeOS (using Crouton) and switch between the two without rebooting.
  • It can do web pages and has a built in terminal shell.
  • With Ubuntu installed in a chroot environment, it does everything my regular computer does (and I almost never have to fire up the gui, which would be a battery drain).
  • This does Netflix, Amazon Prime, Hulu and
  • I haven’t done this, but one could replace the drive with a 128GB SSD for $100.

The bad:

  • Unfortunately the SD card slot isn’t very deep. Any SD Card you insert will stick out the side. I was hoping to drop a 64GB sdcard inside here and store videos/music/projects on this card. But since it sticks out so far, I might as well use a USB drive.
  • The trackpad requires an annoying amount of pressure to right click or click and hold (dragging/highlighting). It also makes a loud click when you do this.

After working on this for the last week, I decided that this Chromebook is exactly what I was hoping my Asus 904 netbook would be. A responsive, long lasting, carry anywhere type computer. It has made me regret purchasing my Nexus 7. I get a lot more daily use out o fthe 11″ Chromebook.

So what am I using this for? A lot of things. Anything really. My primary use case for this was actually amateur radio. In my ubuntu chroot environment, I installed CHIRP to program my radios, flidgi for operating digital modes, xlog for QSO logging, and Wine+APRSISCE for APRS action. So far these programs seem to work without issue. I’ve been able to program radios, send PSK data to PSKDroid on my cell phone using acoustic coupling, and view APRS activity using APRSISCE. When I’m not doing ham radio activity, I leave the X-windows session shut down (and it only takes about 5 seconds to start it up again).

Beyond ham radio, I’m using it to browse the web (duh), ssh into my servers, write python code, and right now… writing this post. Earlier today I fired up a Jenkins server on AWS. I’ve been meaning to set one up for a long time, and I have a year of AWS’s free tier currently. So from this chromebook, I selected a jenkins instance from the AWS market, SSH’d into and add pelican to it. Then I was able to setup a simple jenkins job that would publish my website from github. Then I went over to github and added a commit hook that calls my new jenkins job. Now, anytime I commit into my website’s github repository (including editing it from github directly), jenkins will automatically publish it. Doing this on my tablet, even with the keyboard, would have been frustrating.

Basically, despite even Google’s marketing, their Chromebook is NOT a web browser only type device. It is a full computer. If you’re used to Linux desktops and servers, you can do anything on it that you can on your existing setup. Yes, the impressive battery life is obtainable by using ChromeOS and using X-Windows or other cpu heavy applications will bring that battery life down. But even when I left X-windows up for long periods of time (for instance, letting the linux side download updates) it only had a moderate impact on my battery life.

If you’re looking for a “carry anywhere, do anything” computing device, the C270 is well worth the price.

Foreman managed virtual datacenter

I ordered the KS2 from <www.ovh.com> – $50/month, 3.4ghz, 16gb ram, and a 1TB software raid setup. My plan is to set this
up as a single server virtual datacenter. They also have the SP2 with twice the ram and storage for $90, but I figured I’d test out
the cheaper option first. I can always upgrade and migrate to a larger server later if I get into heavier usage. The prices are rather cheap and they have scripts that will automatically provision physical servers.

I had this installed with Centos 6. I tried first using the “ovh secure” kernel, but I could not get KVM working with that kernel, so I had it reinstalled with the “vendor” kernel. I allocated 20GB to “/” and the remainder (898GB) to “/data”.

Installing kvm and libvirt is a simple yum command.

yum install kvm libvirt python-virtinst qemu-kvm

Then, on my workstation, I installed virt-manager, which allowed me to graphically create and install virtual machines (I can do this by hand on the server, but virt-manager is a nice way to get started). The connection is done over ssh, so it will either ask for your username/password, or it can use ssh-key authentication (preferred).

I created /data/isos and /data/vms to hold my installation isos and virual machines respectively. The trick I had to work out is that I couldn’t just add “/data” as a directory-based storage volume, I had to make one for isos and one for vms. I also found that the default directory (/var/lib/libvirt/images) is rather difficult to remove. I disabled it and removed it, but it showed back up later. When creating through the dialog, virt-manager wants to put your vm image in “default”.

Creating a new virtual machine using virt-manager and a downloaded ubuntu 12.04 iso image (in /data/isos) was rather slick. I created a new volume in /data/vms, set the memory and cpu and started it. The default networking is a NAT’d network in the 192.168.122.x/24 network. As ovh only provides 3 IP addresses for free, I’m content to start with this network for testing, but I plan to move to a different subnet mask.

If I need to nat ports, the libvirt site has a useful page on forwarding incoming connections.

iptables -t nat -A PREROUTING -p tcp --dport HOST_PORT -j DNAT --to $GUESTIP:$GUESTPORT
iptables -I FORWARD -d $GUESTHOST/32 -p tcp -m state --state NEW -m tcp --dport $GUESTPORT -j ACCEPT

I have been reading some good things about The Formean, and how you can manage an infrastructure with it, so my next real VM will be an install of foreman. This will hopefully let me setup an enviroment where I can build virtual machines and provision them automatically. I don’t know (yet) if The Foreman will handle iptable rules on the host, but it seems to have the ability to call external scripts and be customized, so I should be able to provision NAT on the host when provisioning a new VM.

Foreman utilizes DHCP and PXE to install “bare metal” VMs, so we need a network without DHCP. Now, to create my non-dhcp managed nat, I copy the default network xml file and modify it with my new range and remove the dhcp address

cd /usr/share/libvirt/networks
cp default.xml netmanaged.xml

Modified netmanaged.xml:

<network>
  <name>managednat</name>
  <bridge name="virbr1" />
  <forward/>
  <ip address="172.16.25.1" netmask="255.255.255.0">
  </ip>
</network>

It should show up with virsh net-list --all and I can activate it.

# virsh net-list --all
Name                 State      Autostart     Persistent
--------------------------------------------------
default              active     yes           yes
managednat           inactive   yes           yes
# virsh net-autostart managednat
Network managednat marked as autostarted

# virsh net-list --all
Name                 State      Autostart     Persistent
--------------------------------------------------
default              active     yes           yes
managednat           inactive   yes           yes

# virsh net-start managednat
Network managednat started

# virsh net-list --all
Name                 State      Autostart     Persistent
--------------------------------------------------
default              active     yes           yes
managednat           active     yes           yes

The gateway will be 172.16.25.1, and I will assign the IP 172.16.25.5 to my Foreman virtual machine, aptly called “builder”. Once the basic ubuntu machine is installed by hand (hopefully the last one we do in this environment), I’ll want access to it. Ideally, this would be behind a firewall with vpn access, but I haven’t got that far yet. So for now, I’ll just setup some NAT for port 22 and 443.

iptables -t nat -A PREROUTING -p tcp --dport 8122 -j DNAT --to 172.16.25.5:22
iptables -I FORWARD -d 172.16.25.5/32 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 8143 -j DNAT --to 172.16.25.5:443
iptables -I FORWARD -d 172.16.25.5/32 -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT

Using “foreman-installer” is the most recommended method, ensuring that we have current packages directly from theforeman.org. I’ve installed 12.04 LTS (precise), so it’s fairly straightforward, though I modified slightly from the installation documentation. The original instruction rely on running as root.

# get some apt support programs 
sudo apt-get install python-software-properties

# add the deb.theforeman.org repository
sudo bash -c "echo deb http://deb.theforeman.org/ precise stable > /etc/apt/sources.list.db/foreman.list"  
# add the key
wget -q http://deb.theforeman.org/foreman.asc -O- | sudo apt-key add -
# install the installer
sudo apt-get update && sudo apt-get install foreman-installer

# run the installer
sudo ruby /usr/share/foreman-installer/generate_answers.rb

At this point, Foreman is running on port 443, or in my case “https://externalip:8143/”. I can login with the username “admin” and the password “changeme”.

I’ve been reading the manual more at this point, but I think my next step is to watch the video Foreman Quickstart: unattendend installation. If I can grok that (and it looks nicely step by step) I’ll try and setup an unattended install.

Starting with Ruby and AWS

This weekend I decided to takle both learning Ruby and working with AWS
via the Ruby API. Having only played with both of these in the past,
this presents two learning challenges at once. However, from past
projects, this is how I learn best. I am somewhat familiar with AWS
terms and once made a script in Python to fire up an instance. This was
before Amazon came out with their management console, so I imagine
things have come a long way since then (hopefully easier). I also played
with Ruby for a while, but didn’t have a decent project for it. Having a
project with goals will hopefully keep me on track and give me a way to
measure my progress.

My goals for this project are as follows:

  1. Utilize a web based interface. Using rails seems to be the popular
    way to do this, and I’d like to base my template interface off of
    boilerstrap5, a combination of twitter-bootstrap and
    html5boilerplate. This will probably have the most trial and error
    to get it right.
  2. Connect to the AWS api and pull some basic information such as my
    account name.
  3. Fetch details about an AMI image. Maybe I’ll be able to parse a list
    of public images, or maybe I can just punch in an image ID and pull
    up the details.
  4. Start an instance from an AMI image. This might require some steps
    like setting up a an S3 bucket — we’ll see.
  5. List my running instances.
  6. Control a running instance – ie, power cycle it.
  7. Destroy an instance.
  8. BONUS: Do something similar with S3 buckets – create, list, destroy.

First off, I need to setup a ruby development environment. Since I have
used PyCharm in the past, I will try JetBrain’s RubyMine for my
editor environment. After installing this, the first thing I learned is
that rails is not installed. I could install using apt-get, but
Jetbrains recommends using RVM. It looks like a nice way to manage
different versions of Ruby, rails, and gems. I know when I have
installed Ruby applications requiring gems, gem versions was always a
source of concern. It is very easy to get mismatched gem versions in the
wild.

RVM install locally to ~/.rvm on linux, which is nice – you don’t mess
up any system wide ruby installations and keep everything local to your
development environment. After installation, I had to figure out a
couple bits with rvm.

  • rvm install 1.9.2 # installs ruby 1.9.2
  • rvm list # lists versions of ruby installed
  • rvm use 1.8.7 # use ruby 1.8.7

First, your terminal has to be setup as a login shell. This tripped me
up for a while until I changed the settings in my terminal emulator.
terminator has this as checkmark option.

[email protected]:~$ rvm list

rvm rubies

   ruby-1.8.7-p371 [ x86_64 ]
   ruby-1.9.2-p320 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

[email protected]:~$ rvm use 1.8.7

RVM is not a function, selecting rubies with 'rvm use ...' will not work.

You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for a example.

After switching to login

[email protected]:~$ rvm use 1.8.7
Using /home/ytjohn/.rvm/gems/ruby-1.8.7-p371

Finally, once you get ruby and rails working, you can create your rails
project. I’m starting with a rails project because it’s “all the rage”
and gives you a decent running start. Later, I’ll work on switching the
supplied templates with boilerplate + bootstrap based ones.

This gets me started. Next up, I’ll actually create the project from
within RubyMine and just work on basic web functionality.

dingus problems

This weekend I decided to takle both learning Ruby and working with AWS
via the Ruby API. Having only played with both of these in the past,
this presents two learning challenges at once. However, from past
projects, this is how I learn best. I am somewhat familiar with AWS
terms and once made a script in Python to fire up an instance. This was
before Amazon came out with their management console, so I imagine
things have come a long way since then (hopefully easier). I also played
with Ruby for a while, but didn’t have a decent project for it. Having a
project with goals will hopefully keep me on track and give me a way to
measure my progress.

My goals for this project are as follows:

  1. Utilize a web based interface. Using rails seems to be the popular
    way to do this, and I’d like to base my template interface off of
    boilerstrap5, a combination of twitter-bootstrap and
    html5boilerplate. This will probably have the most trial and error
    to get it right.
  2. Connect to the AWS api and pull some basic information such as my
    account name.
  3. Fetch details about an AMI image. Maybe I’ll be able to parse a list
    of public images, or maybe I can just punch in an image ID and pull
    up the details.
  4. Start an instance from an AMI image. This might require some steps
    like setting up a an S3 bucket — we’ll see.
  5. List my running instances.
  6. Control a running instance – ie, power cycle it.
  7. Destroy an instance.
  8. BONUS: Do something similar with S3 buckets – create, list, destroy.

First off, I need to setup a ruby development environment. Since I have
used PyCharm in the past, I will try JetBrain’s RubyMine for my
editor environment. After installing this, the first thing I learned is
that rails is not installed. I could install using apt-get, but
Jetbrains recommends using [RVM]. It looks like a nice way to manage
different versions of Ruby, rails, and gems. I know when I have
installed Ruby applications requiring gems, gem versions was always a
source of concern. It is very easy to get mismatched gem versions in the
wild.

RVM install locally to ~/.rvm on linux, which is nice – you don’t mess
up any system wide ruby installations and keep everything local to your
development environment. After installation, I had to figure out a
couple bits with rvm.

  • rvm install 1.9.2 # installs ruby 1.9.2
  • rvm list # lists versions of ruby installed
  • rvm use 1.8.7 # use ruby 1.8.7

First, your terminal has to be setup as a login shell. This tripped me
up for a while until I changed the settings in my terminal emulator.
terminator has this as checkmark option.

[email protected]:~$ rvm list

rvm rubies

   ruby-1.8.7-p371 [ x86_64 ]
   ruby-1.9.2-p320 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

[email protected]:~$ rvm use 1.8.7

RVM is not a function, selecting rubies with 'rvm use ...' will not work.

You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for a example.

After switching to login

[email protected]:~$ rvm use 1.8.7
Using /home/ytjohn/.rvm/gems/ruby-1.8.7-p371

Finally, once you get ruby and rails working, you can create your rails
project. I’m starting with a rails project because it’s “all the rage”
and gives you a decent running start. Later, I’ll work on switching the
supplied templates with boilerplate + bootstrap based ones.

This gets me started. Next up, I’ll actually create the project from
within RubyMine and just work on basic web functionality.

[RVM]:

Bootstrap and CDNs

Often when creating a “modern” web page, it’s very common to find yourself reinventing the wheel over and over again. I know any time I wanted to create a two-column layout, I would have to look at previous works of mine or search the Internet for a decent example. However, I recently came across Twitter’s Bootstrap framework. At it’s core, it’s just a css file that divide your web page into a 12-column “grid“. You create a “row” div, and inside that row you place your “span*” columns. Each span element spans from 1 to 12 columns, and should always add up to 12 for each row. You can also offset columns. There are css classes for large displays (1200px or higher), normal/default displays (980px), and smaller displays such as tablets (768px) or phones (480px). Elements can be made visible or hidden based on the device acessing the site (phone, tablet, or desktop). There is also a javascript component you can use for making the page more interactive.

If you download bootstrap, you get a collection of files to choose from. There’s js/bootstrap.js, img/glyphicons-halflings.png, img/glyphicons-halflings-white.png, css/bootstrap.css, css/bootstrap-responsive.css. There is also a compress .min. version of the javascript and css files. You can read further about the responsive version of the css, or how to use the icons.

Normally, one would take these downloaded files and put them into their own web application directory tree. However, there is a better way. Unless you are planning to use this on an Intranet with limited Internet access, you can use a copy of these files hosted on a “content delivery network (CDN)”. A good example of this is the jQuery library hosted on Google’s CDN. Google has a number of hosted libraries on their network. This has several advantages, one of which being caching. If everyone is pointing at a common hosted library, that library gets cached on the end-user’s machine instead of being reloaded on every site that uses that library.

While bootstrap is not hosted on google, there is another CDN running on CloudFlare called cdnjs that provides a lot of the “less popular” frameworks, including bootstrap. Here are the URLs to the most current version of bootstrap files (they have version 2.0.0 through 2.1.1 currently).

  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.css
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap-responsive.css
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap-responsive.min.css
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/bootstrap.js
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/bootstrap.min.css
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/img/glyphicons-halflings-white.png
  • http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/img/glyphicons-halflings.png

All one has to do in order to use these is to add the css and the javascript (optional) to their page. Since most CDNs support both http and https, you can leave the protocol identifier out.

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/bootstrap.min.js">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

Here’s an example you can use on your own.

<!DOCTYPE html>
<html lang="en">

<body>
<div class="container-fluid">
        <div class="row-fluid">
         <div class="span12 label label-info">
                <h1>Header</h1>
         </div>
        </div>

        <div class="row-fluid">
         <div class="span2">
                left column
                <i class="icon-arrow-left"></i>
         </div>
         <div class="span6">

                <p>center column

                <i class="icon-tasks"></i></p>

                <div class="hero-unit">
                 <h1>This is hero unit</h1>
                 <p>It is pretty emphasized</p>
                </div>

                <p>still in the center, but not so heroic</p>

         </div>
         <div class="span4">
                right column
                <i class="icon-arrow-right"></i>
         </div>
        </div>
</div><!-- end container -->

<!-- load everything at end for fast content loading -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/bootstrap.min.js">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
</body>
</html>

Finally, I found that NetDNA also hosts bootstrap on their CDN at [www.bootstrapcdn.com]. I would say that either CDN would be fairly reliable, as they are both sponsored by their CDN they are running on. One advantage of this site is that they provide a lot more than just the basic bootstrap hosting such as custom themes and fonts.

To use them, you can simply swap out your css and js scripts.

<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap-combined.min.css" rel="stylesheet">
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/js/bootstrap.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

UPDATE: I added jquery into the above examples because several parts of bootstrap rely on it (such as the Modal dialogs).

20120918