Postpostmodern http://postpostmodern.com Speaking of web development. Wed, 11 Jan 2012 00:21:50 +0000 http://wordpress.org/?v=2.9.1 en hourly 1 Slicehost (and Linode) LAMP Cheatsheet http://postpostmodern.com/2009/11/17/slicehost-and-linode-lamp-cheatsheet/ http://postpostmodern.com/2009/11/17/slicehost-and-linode-lamp-cheatsheet/#comments Tue, 17 Nov 2009 23:51:35 +0000 Jason Johnson http://postpostmodern.com/?p=120 I have set up several Slicehost slices as Ubuntu LAMP servers, but since I’m not a server admin, I always have to reference the tutorials to remember the steps. So, I’ve compiled the list of steps here, as concisely as possible. This process sets up everything you need for hosting multiple sites on a single server, and it works equally well for most servers running Ubuntu including Slices and Linodes.

Disclaimer
Please use these only if you already know the whys and wherefores. If you don’t generally understand one or more of these steps, consult the Slicehost Articles or the Linode Articles before asking questions here. Most of the information here comes from the Slicehost Articles for Ubuntu. I have also added a few extra steps from sources cited in the footnotes.
Helping Me Out
If you need to sign up for a Slicehost or Linode account, and you plan on using this article as a guide to configure your server, please use these referral links:
Corrections to this article are also appreciated. Please note, however, that corrections != personal preference. If you have a different way of doing something, you’ll need to present a convincing case as to why it is better.
Assumptions
This guide/cheatsheet assumes you have already created a virtual server with Ubuntu installed.
You should also set up your DNS. If you’re using Slicehost, my Slicehost DNS script will help.
Conventions
For this article, I’m using:
  • xxx.xxx.xxx.xxx to indicate the IP address of your server
  • bob as the server’s name (hostname)
  • example.com as the domain name
  • demo as the admin user
  • nano as my editor because I have no vi skills.

Configure Server for Terminal.app (Mac users only)

Terminal.app behaves as dtterm, but Ubuntu doesn’t have the dtterm entry in its terminfo database. This fixes that.1

Save Terminal Info to a File

On your Mac (local machine)…

  1. infocmp > /tmp/dtterm
  2. scp /tmp/dtterm root@xxx.xxx.xxx.xxx:/tmp

Import Terminal Info

  1. Log into your server as root
  2. tic /tmp/dtterm

Some Basic Package Setup

Aptitude Upgrade

Still logged in as root…

  1. Make sure you have access to the universe repositories nano /etc/apt/sources.list and uncomment the universe repositories
  2. Update
    aptitude update
  3. Upgrade
    aptitude safe-upgrade aptitude full-upgrade

Install Build Essentials

  1. Install
    aptitude install build-essential

Install CURL

  1. Install
    aptitude install curl
  2. Install ca-certificates for ssl connections aptitude install ca-certificates

SSH and Users

Create New User and Allow sudo

Still logged in as root…

  1. Change root password, if desired passwd
  2. Add user
    adduser demo
  3. Set up sudo config
    visudo and add demo ALL=(ALL) ALL to the end
  4. Log out or switch to your local machine

Set up SSH Keys

  1. On your local machine, copy local public ssh key to server (assuming you have already created your public key on your local machine) scp ~/.ssh/id_rsa.pub demo@xxx.xxx.xxx.xxx:/home/demo/
  2. Switch back to your server or log back in as root
  3. Create authorized_keys file
    cd /home/demo mkdir .ssh mv id_rsa.pub .ssh/authorized_keys
  4. Set permissions chown -R demo:demo .ssh chmod 700 .ssh chmod 600 .ssh/authorized_keys

Configure sshd

  1. Open sshd_config nano -w /etc/ssh/sshd_config
  2. Set these:
    Port 30000 (change to a port of your choosing)
    Protocol 2
    PermitRootLogin no
    PasswordAuthentication no
    X11Forwarding no
    UsePAM no
    UseDNS no
    AllowUsers demo

Setup iptables

  1. Dump existing rules cd /etc iptables-save > iptables.up.rules
  2. Copy rules file from Slicehost example curl -o iptables.test.rules http://articles.slicehost.com/assets/2007/9/4/iptables.txt
  3. Edit it and set port number for sshd nano -w iptables.test.rules
  4. Load it iptables-restore < iptables.test.rules
  5. Check the new rules iptables -L
  6. Save the new rules iptables-save > iptables.up.rules
  7. Make sure the new rules are read every time nano -w network/interfaces and make it look like this:
    ...
    auto lo
    iface lo inet loopback
    pre-up iptables-restore < /etc/iptables.up.rules
    
    # The primary network interface
    ...

Restart and Test sshd

  1. Reload sshd
    /etc/init.d/ssh reload
  2. Try to log in from another terminal
  3. If successful, logout

User Config

Logged in as demo...

Configure Nano

  1. Set some configuration cp /etc/nanorc ~/.nanorc nano -w ~/.nanorc
  2. Uncomment these lines:
    # set brackets ""')>]}"
    # set nowrap (should be set by default in recent versions) # set tabsize 8
  3. Change tabsize to 2 or 4 or something:
    set tabsize 4

Add Bash Aliases

  1. Create aliases file nano -w .bash_aliases and add:
    alias lo='logout'
    alias mksite='sudo /usr/local/a2mksite/a2mksite.sh'
    alias free='free -m'
    alias ag='sudo apache2ctl graceful'
    if [ "$TERM" != "dumb" ] && [ -x /usr/bin/dircolors ]; then
        eval "`dircolors -b`"
        alias ls='ls -la --color=auto'
    fi
    
    # Git
    alias gst='git status'
    # alias gl='git pull'
    alias ga='git add'
    alias gp='git push'
    alias gd='git diff | mate'
    alias gc='git commit -v'
    alias gca='git commit -v -a'
    alias gb='git branch'
    alias gba='git branch -a'
    alias gco='git checkout'
    alias glog='git log --pretty=format:"# %aD : %an%n%n* %s%n%n%b%n"'
    alias glt='glog --since=yesterday'
    alias gly='glog --since="2 days ago" --until="1 day ago"'
  2. If necessary, activate aliases in .bashrc nano -w .bashrc and uncomment the part that loads .bash_aliases
  3. Get the aliases working source ~/.bashrc

Basic Server Config

Set Hostname2

  1. Name your server by setting a short hostname in /etc/hostname sudo nano /etc/hostname and type bob.example.com
  2. Set the fully-qualified domain name in hosts
    sudo nano /etc/hosts and add xxx.xxx.xxx.xxx bob.example.com bob
    below the 127.0.0.1 localhost entry
  3. Reboot sudo reboot
  4. Check hostname
    hostname
  5. Check FQDN
    hostname -f

Set Locale

  1. Generate locale info
    sudo locale-gen en_US.UTF-8
  2. Update locale
    sudo /usr/sbin/update-locale LANG=en_US.UTF-8

Set Timezone

  1. Start up timezone configurator and follow instructions
    sudo dpkg-reconfigure tzdata

Git

Install Git

  1. Install
    sudo aptitude install git-core

Subversion

Install svn

  1. Install
    sudo aptitude install subversion

Web Server

Install a2mksite

a2mksite is a script that I wrote that allows you to create an Apache virtual host with one command (including the document root, config files, log rotation, etc). One thing you should know is that it creates a directory structure for multiple web sites (virtual hosts), placing each site's public and log directories in its own directory like so: /var/www/sites/example.com

Read the description here to learn more about what it does.

  1. Clone a2mksite from Github git clone git://github.com/postpostmodern/a2mksite.git
  2. Move it to /usr/local sudo mv a2mksite /usr/local
  3. CHOWN it to root sudo chown 0:0 /usr/local/a2mksite
  4. Make sure you have the script aliased as mksite in your .bash_aliases file (see Bash Aliases snippet earlier in this post).

Install Logrotate

  1. Install
    sudo aptitude install logrotate

Install Apache

  1. Install sudo aptitude install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert
  2. Set up basic config using my httpd.conf as an example wget https://raw.github.com/gist/236374/httpd.conf sudo mv httpd.conf /etc/apache2/httpd.conf sudo nano /etc/apache2/httpd.conf
  3. Enable Modules
    sudo a2enmod auth_digest dav dav_lock rewrite
  4. Create errors dir
    sudo mkdir /var/www/errors
  5. Create maintenance dir
    sudo mkdir /var/www/maintenance
  6. CHOWN them
    sudo chown -R demo:demo /var/www/errors /var/www/maintenance
  7. Create global 404
    nano -w /var/www/errors/404.html
  8. Create maintenance page
    nano -w /var/www/maintenance/index.html
  9. Make default site
    mksite default and overwrite the original default

MySQL

Install MySQL

  1. Install
    sudo aptitude install mysql-server mysql-client libmysqlclient15-dev
  2. Set root password (follow instructions during installation)

PHP

Install PHP

  1. Install PHP sudo aptitude install libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd php5-imagick php5-mcrypt php5-memcache php5-mhash php5-mysql php5-pspell php5-snmp php5-sqlite php5-xmlrpc php5-xsl php5-xcache
  2. Edit xcache.ini sudo nano /etc/php5/apache2/conf.d/xcache.ini and set xcache.var_size to something other than zero
  3. Edit php.ini sudo nano /etc/php5/apache2/php.ini and set error output, max upload size, etc.
  4. Restart Apache sudo /etc/init.d/apache2 restart

Mail (for sending via PHP)

Reverse DNS

  1. Set Reverse DNS in SliceManager or Linode Manager to your server's FQDN, i.e. what you see when you type hostname -f
  2. Check it
    sudo aptitude install dnsutils dig -x xxx.xxx.xxx.xxx

Postfix

  1. Install Postfix
    sudo aptitude install postfix mailx
  2. Test Postfix
    mail someone@somewhereelse.com and send a message. Don't forget: ctrl-d ends the message.
  3. Optionally continue configuration as described here

A Backup Solution

The following is my own backup solution for my web sites. It backs up the MySQL databases and web site files. Then, it sends a copy to Amazon S3.

Install Ruby for S3Sync

  1. Install Ruby sudo aptitude install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby sqlite3 libsqlite3-ruby1.8
  2. Symlink locations sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby sudo ln -s /usr/bin/ri1.8 /usr/bin/ri sudo ln -s /usr/bin/rdoc1.8 /usr/bin/rdoc sudo ln -s /usr/bin/irb1.8 /usr/bin/irb
  3. Install Ruby Gems (optional) wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz tar xzvf rubygems-1.3.7.tgz cd rubygems-1.3.7 sudo ruby setup.rb cd .. rm -R rubygems-1.3.7* sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
  4. Update gems sudo gem update sudo gem update --system

Install S3Sync

  1. Download and move S3Sync wget http://s3.amazonaws.com/ServEdge_pub/s3sync/s3sync.tar.gz tar xvzf s3sync.tar.gz sudo mv s3sync /usr/local/ sudo chown 0:0 /usr/local/s3sync/ rm s3sync.tar.gz
  2. Make sure you installed the ca-certificates package earlier (see "Install CURL" above)

Install Web Server Backup Script

  1. Clone it from Github sudo git clone git://github.com/postpostmodern/web-server-backup.git /usr/local/web-server-backup
  2. Configure it according to the README sudo nano /usr/local/web-server-backup/backup.sh
  3. Test Run sudo /usr/local/web-server-backup/backup.sh

Schedule the Backup with Cron

  1. Create a cron job sudo nano /etc/cron.d/web_server_backup
  2. Make it look something like this:
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
    MAILTO=demo@example.com
    HOME=/root
    
    30 4 * * * root /usr/local/web-server-backup/backup.sh > /dev/null

There is no step 54.

Okay. That was a lot of steps, but everything should be running properly now. Though this article is mostly for my own reference, your comments are welcome.

  1. OS X Terminal Emulation Woes ↑ back up there
  2. Linux Hostname Configuration ↑ back up there
]]>
http://postpostmodern.com/2009/11/17/slicehost-and-linode-lamp-cheatsheet/feed/ 16
Terminal Tip: Prevent Creation of Mac Dot Files http://postpostmodern.com/2009/08/07/terminal-tip-prevent-creation-of-mac-dot-files/ http://postpostmodern.com/2009/08/07/terminal-tip-prevent-creation-of-mac-dot-files/#comments Fri, 07 Aug 2009 12:59:04 +0000 Jason Johnson http://postpostmodern.com/?p=412 I had no idea until recently that you can actually prevent creation of the ._filename files when using tar (and other commands, I assume) by setting an environment variable. On Leopard, it’s called COPYFILE_DISABLE.

So, put this in your .bash_profile: export COPYFILE_DISABLE=true and you can avoid having to do this.

]]>
http://postpostmodern.com/2009/08/07/terminal-tip-prevent-creation-of-mac-dot-files/feed/ 2
Terminal Tip: Delete Those Mac Dot Files http://postpostmodern.com/2009/06/08/terminal-tip-delete-those-mac-dot-files/ http://postpostmodern.com/2009/06/08/terminal-tip-delete-those-mac-dot-files/#comments Mon, 08 Jun 2009 16:40:32 +0000 Jason Johnson http://postpostmodern.com/?p=396 Unzipping/untaring an archive that was created on a Mac can produce a lot of ._blah and .DS_Store files. Rid yourself of them with:

find . \( -name '._*' -o -name '.DS_Store' \) -exec rm {} \;

or, if you’re using GNU find (e.g. on Ubuntu) you can use -delete:

find . \( -name '._*' -o -name '.DS_Store' \) -delete

]]>
http://postpostmodern.com/2009/06/08/terminal-tip-delete-those-mac-dot-files/feed/ 4
A Body with Class http://postpostmodern.com/2009/02/20/a-body-with-class/ http://postpostmodern.com/2009/02/20/a-body-with-class/#comments Fri, 20 Feb 2009 23:07:12 +0000 Jason Johnson http://postpostmodern.com/?p=228 This Short Version

Add a class attribute to your tag for each part of the page’s path in the URL. E.g.: The page http://example.com/about/history should have a body tag that looks like <body class="about history">. It makes styling those sections of your site nice and simple.

The Explanation

Often times, specific styling/formatting is shared between similar pages. The traditional way to deal with this is to include additional CSS files when special formatting is needed. I’ve found body classing to be more useful and more efficient.1

Since the pages that share styling often also share a path in the url, it’s really simple to add the path parts as classes to the body tag. For example, say the about section of a web site needs special formatting because it has an extra sidebar or maybe some sort of widget. I would add the class ‘about’ to the body tag of all of the about pages. This method continues down the hierarchy. The page at /about/history would have a body class of ‘about history’, and so on. It’s very simple and very handy.

It’s also very simple to add this functionality to your layouts whether you’re using Rails or any other framework. My PHP framework, Phooey, does it for you automatically.

For Rails, you can include this in your layout:

<body class="<%= controller_name -%> <%= action_name -%>">

…or, if you’re using Haml (which I highly recommend):

%body{:class => "#{controller_name} #{action_name}"}

Agree? Disagree? Confused? Let me know down there in the comments.

  1. I am of the opinion that you should only include one CSS file per media type in any page of your site (except for the IE stylesheets). I usually include only the following stylesheets in every page of every site: all.css, screen.css, print.css. And each one of those is minified. More on this in my forthcoming article on Sass. ↑ back up there
]]>
http://postpostmodern.com/2009/02/20/a-body-with-class/feed/ 5
Pseudo Pseudo Classes http://postpostmodern.com/2009/02/10/pseudo-pseudo-classes/ http://postpostmodern.com/2009/02/10/pseudo-pseudo-classes/#comments Tue, 10 Feb 2009 05:16:19 +0000 Jason Johnson http://postpostmodern.com/?p=384 The :first-child and :last-child pseudo classes in CSS are super-handy for stying things like lists. For example, if you want a horizontal line between list items, you can set:

ul li {
  border-bottom: solid 1px #e0e0e0;
}
ul li:last-child {
  border: none;
}

Unfortunately, most current browsers can’t stomach :first-child and :last-child. :(

But just a teaspoon of jQuery will make that pseudo-class medicine go right down:

function firstLast()
{
  $('ul li:first-child').addClass('first');
  $('ul li:last-child').addClass('last');
}
jQuery(firstLast);
]]>
http://postpostmodern.com/2009/02/10/pseudo-pseudo-classes/feed/ 1
Git Yr Remote Set Up http://postpostmodern.com/2009/02/05/git-yr-remote-set-up/ http://postpostmodern.com/2009/02/05/git-yr-remote-set-up/#comments Fri, 06 Feb 2009 01:46:02 +0000 Jason Johnson http://postpostmodern.com/?p=323 Last week…
Jason
I started using Unfuddle for [redacted]
I like it so far.
Trey
it’s a good service
I’m going to move all my private repos there
Jason
if you just want online repo storage, why not just use your Slice?
Trey
I should do that
Jason
It’s super easy
Trey
yeah?
you should blog it
Jason
ok.

So here is how to get your remote git up and go

Setting up a remote Git repo and connecting via ssh in a nutshell:

First, we install git on the server. I’m using aptitude on Ubuntu for this. Next, we have two options: we can just set up a bare git repo and push to it using an existing user; or, if we want to be able to safely share the repo with others, we can set up a git user. After setting up the git user, we create the bare git repo, chown it to the git user, and push to it from our local machine.

On your slice…

  1. Install Git

    sudo aptitude git-core

  2. Add the Git User (If you want to use an existing user, skip to step #7.)

    sudo adduser git

  3. Set up ssh key (standard procedure)

    su - git mkdir .ssh chmod 700 .ssh nano -w ~/.ssh/authorized_keys

    (Yes, I use nano. What of it?)

    [ paste in public key and save the file ]

  4. Exit su

    exit

  5. Give the Git User a special shell that only allows git commands

    sudo nano /etc/passwd

    [ Change git’s shell from /bin/sh to /usr/bin/git-shell ]

    [ Save /etc/passwd ]

  6. If you have set up your sshd_config to only allow specific users, you’ll need to add git

    sudo nano /etc/ssh/sshd_config

    [ Add git to AllowUsers (near the end of the file), e.g.: AllowUsers jason git ]

  7. Reload sshd

    sudo /etc/init.d/ssh reload

  8. Create a dir for your repos

    sudo mkdir /var/git

    sudo chown `whoami` /var/git

  9. Create your first bare repo (--bare means no working dir; i.e. just the contents of .git)

    cd /var/git mkdir test.git cd test.git git --bare init sudo chown -R git .

Back on your local machine…

  1. Go to there

    cd /path/to/test

  2. Add your remote (just as if it were somewhere like Github)

    git remote add origin ssh://git@slice1.example.com/var/git/test.git

  3. Push all your branches

    git push --all

N.B.

  • If you use something other than Ubuntu and aptitude, your git-shell may be located somewhere else. Try which git-shell to find it.
  • If you’ve changed your ssh port to something other than 22, you’ll need to do something like this: git remote add origin ssh://git@slice1.example.com:8822/var/git/test.git
  • To allow others to contribute, put their public key in /home/git/.ssh/authorized_keys, but remember, you can’t log in as git; so, you’ll need to edit it as root with sudo.

Questions? Comments? Recommendations? Let me know.

]]>
http://postpostmodern.com/2009/02/05/git-yr-remote-set-up/feed/ 3
Gitup! http://postpostmodern.com/2009/02/01/gitup/ http://postpostmodern.com/2009/02/01/gitup/#comments Sun, 01 Feb 2009 18:49:34 +0000 Jason Johnson http://postpostmodern.com/?p=296 Gitup + Transmit = Really Simple Publishing

Deploy vs Publish

There are many ways to deploy a new version of a web site. If it’s a web app, you normally want to use a complete deployment solution like Capistrano or Moonshine. But if you need to update a static HTML site or a simple PHP site, you usually just need to upload the changed files. This is often referred to as publishing as opposed to deployment. There are obviously several ways of doing this. Many file transfer apps have synchronization features. Publishing features can also be found in many editors/IDEs.

The Pain of Publishing

I’m a simple man. All those fancy publish/sync features always seem to be a hassle or else they’re built-in to a less-than-ideal coding environment (I’m looking at you, Coda and Espresso). Editing in Textmate and dock-sending to Transmit is about as fancy as I get. No sync. Just uploading files. The problem is, it’s hard sometimes to keep track of all the updated files that need to be uploaded once a new page is added, feature is complete, etc. Git knows what’s changed (if you’re not using Git or some other SCM, you should be), but going through the logs is a pain.

Gitup and Go

So, yesterday, I wrote a Ruby script to do simple publishing. It’s called Gitup. You tell Gitup which Git commits you want to publish, and it finds all of the changed files and sends them to Transmit. If you have Transmit’s dock send feature set up, Transmit will upload the files to the appropriate server and directory. Gitup will even let you preview the list of files that it plans on uploading.

It’s super-simple and quick. Much quicker than any ‘publish’ feature I’ve seen.

Examples

Send files modified in the last commit to Transmit (Gitup will let you know how many files will be sent and offer you the option to view a list of the files or abort.):

gitup

Send files modified in the last 3 commits to Transmit:

gitup -3

Send files modified in the last 3 commits to Transmit immediately (no prompting or anything):

gitup -s -3

Send files modified since yesterday to Transmit:

gitup --since=yesterday

Send files modified since Monday to Transmit (quotes are required):

gitup --since="last monday"

Send files since the specified commit to Transmit:

gitup dcd2c68..

Open files added/updated between the two specified commits in Textmate:

gitup --application=Textmate dcd2c68..bf75dd6

Disclaimer

Please note that Gitup is brand new. It could be buggy. I’m just sayin’.

]]>
http://postpostmodern.com/2009/02/01/gitup/feed/ 0
Global AJAX Cursor Change http://postpostmodern.com/2009/01/06/global-ajax-cursor-change/ http://postpostmodern.com/2009/01/06/global-ajax-cursor-change/#comments Tue, 06 Jan 2009 22:08:54 +0000 Jason Johnson http://postpostmodern.com/?p=290 I don’t know if I’ve ever mentioned this before, but in case I haven’t:

Something to this effect should be used on all AJAX web pages:

function globalAjaxCursorChange() 
{
  $("html").bind("ajaxStart", function(){
     $(this).addClass('busy');
   }).bind("ajaxStop", function(){
     $(this).removeClass('busy');
   });
}

Along with this CSS:

html.busy, html.busy * {
  cursor: wait !important;
}

The javascript above is jQuery, but I used to do the same type of thing back when I used Prototype.

Developers sometimes go to great lengths to supplement the native behavior of a system with custom ‘busy’ indicators. And that’s great, but don’t forget what’s built-in. Users instinctively know that something’s working when they see the old hourglass/watch cursor.

]]>
http://postpostmodern.com/2009/01/06/global-ajax-cursor-change/feed/ 13
Leopard-Style iTerm Icon, Take 2 http://postpostmodern.com/2008/12/18/leopard-style-iterm-icon-take-2/ http://postpostmodern.com/2008/12/18/leopard-style-iterm-icon-take-2/#comments Fri, 19 Dec 2008 01:56:11 +0000 Jason Johnson http://postpostmodern.com/?p=279 Several days ago, I posted a suggestion for a new icon for iTerm, a terminal app that many developers prefer over the standard Terminal app. The first version was just a few standard Leopard icons thrown together. A few days later, I updated the icon with a more balanced, albeit less-colorful, version featuring a vectory globe.

At the developers’ request, I have updated it once again. The color has been brought back to the globe, and the smaller versions (32px and 16px) have been simplified a bit for a cleaner appearance. I encourage you to try the new version. You can click it to download the .icns file, which may be placed inside iTerm.app/Contents/Resources. Enjoy.

iTerm Icon

]]>
http://postpostmodern.com/2008/12/18/leopard-style-iterm-icon-take-2/feed/ 8
Leopard-Style iTerm Icon http://postpostmodern.com/2008/12/05/leopard-style-iterm-icon/ http://postpostmodern.com/2008/12/05/leopard-style-iterm-icon/#comments Sat, 06 Dec 2008 03:28:12 +0000 Jason Johnson http://postpostmodern.com/?p=251 This article has been superceded. See here.

Speaking of iTerm, isn’t it about time we had an updated icon? I’ve cobbled one together using bits of the Terminal icon with elements from the previous iTerm icons. Not exactly original. Same concept as the old icon. It’s just more Leopardy now. Click it to download the .icns file. I recommend downloading the revised version below.

iTerm Icon

Let me know what you think.

Update – Dec 7

Here is an updated version that’s a little more balanced, and looks better at small sizes. Click it to download the .icns file.

Gray iTerm Icon
]]>
http://postpostmodern.com/2008/12/05/leopard-style-iterm-icon/feed/ 6