Thoughts from a sysadmin turned coder..:. brainsik / jeremy avnetTumblr (3.0; @brainsik) cron task – exit if already running<a href="">Python cron task – exit if already running</a>: <p>A simple way for Python cron tasks to exit if another process is currently running. Does not use a pidfile.</p> <div class="gist"><a href=""></a></div>, 14 Dec 2012 18:31:00 -0800pythoncronsysadminVirtualenvs with different interpreters<p><strong>Update 2011-09-27</strong>: Turns out virtualenv and virtualenvwrapper support this out of the box. Most of what&#8217;s written below is horrifically complex compared to just using the <code>-p</code> switch when you make your virtualenv. You simply need to do this:</p> <pre><code>$ mkvirtualenv -p /path/to/some/python coolname </code></pre> <p>That&#8217;ll create a new virtualenv called &#8220;coolname&#8221; that uses <code>/path/to/some/python</code> for it&#8217;s Python interpreter. I&#8217;ve tested this with <a href="">PyPy</a> and it worked great.</p> <hr><p>A recent comment on the <a href="">original Virtualenv Burrito announcement</a> asked whether it was possible to create virtualenvs using different Python interepreters. The answer is a cautious: <strong>yes</strong>!</p> <p>When <a href="">virtualenv-burrito</a> installs virtualenv, it prevents the <code>virtualenv</code> command from tying itself to a specific interpreter. I wanted to be able to switch between Python versions, creating virtualenvs for each. I haven&#8217;t publicized this feature, nor made it easy to use since there may be hidden pitfalls. That said, I&#8217;ve not run into any problems.</p> <p>The way it works is <code>mkvirtualenv</code> uses the same interpreter invoked by the <code>python</code> command to create the virtualenv. For example, normally when I run <code>mkvirtualenv</code> I get a Python 2.7 environment. Using <a href="">MacPorts</a>, I can switch from my 2.7 default to 2.6 with:</p> <pre><code>port select --set python26 </code></pre> <p>Now running <code>mkvirtualenv</code> creates a 2.6 environment.</p> <p>Regardless of what your current default Python interpreter is, once the virtualenv is made, <em>it stays tied to the Python used during creation</em>.</p> <p>If you don&#8217;t have a nice way to switch your default Python, you can still hack it. The key is making the <code>python</code> command use the interpreter you want.</p> <p>The following<sup id="fnref:p8685119046-1"><a href="#fn:p8685119046-1" rel="footnote">1</a></sup> will also make a Python 2.6 virtualenv even though 2.7 is the default:</p> <script src=""></script><p><a href="/ask">Let me know if it works</a> for you. Especially if you are trying out something other than a CPython!</p> <div class="footnotes"> <hr><ol><li id="fn:p8685119046-1"> <p>A new directory is made with a symlink pointing <code>python</code> to the <code>python2.6</code> executable. When calling <code>mkvirtualenv</code>, the PATH environment is set with this new directory first so the 2.6 interpreter is used. <a href="#fnref:p8685119046-1" rev="footnote">↩</a></p> </li> </ol></div>, 09 Aug 2011 03:05:00 -0700pythonvirtualenvElasticfox Forever<p>Tired of (yet again) fixing the <a href="">Elasticfox</a> Firefox extension to work with the latest version of Mozilla Firefox, I finally just made <a href="">one with an absurd maximum version defined</a>.</p> <center><img src="/tumblr_ln8geb7TcX1qa5gs9.jpg" alt=""/></center> <p>You can easily create one yourself. Since xpi files are zip files, it&#8217;s something like:</p> <ol><li><code>mkdir tangerine; cd tangerine</code></li> <li><code>unzip /path/to/elasticfox.xpi</code></li> <li>edit install.rdf so maxVersion is <code>99.0</code></li> <li><code>zip -r9X ../elasticfox-forever.xpi .</code></li> <li>drag <code>elasticfox-forever.xpi</code> onto Firefox</li> </ol><p>Or cop out and click this: <a href="">elasticfox-forever.xpi</a></p> <p><em>Update 2011-09-23</em>: Using <code>*</code> for the maxVersion still didn&#8217;t cut it so I&#8217;ve updated the article and <code>xpi</code> file to use a maxVersion of <code>99.0</code>.</p> <p><small>Image modified from <a href="">I&#8217;m with the band</a> by <a href="">theilr</a>. <a href="">CC:by-sa</a>.</small></p>, 23 Jun 2011 06:30:00 -0700firefoxec2SSH Agent Forwarding<p><em>This is part of the mini-series <a href="">OpenSSH for Devs</a>.</em></p> <p>SSH agent forwarding let&#8217;s you lock down remote hosts while making them easier to access and use in automated ways. One co-worker succinctly describes agent forwarding as &#8220;the shit&#8221;.</p> <h2>Example</h2> <p>Securely connect to a remote host from a remote host without a password.</p> <pre><code>laptop:~$ ssh -A Linux host1 2.6.35-25-server #44-Ubuntu SMP Fri Jan 21 19:09:14 UTC 2011 x86_64 GNU/Linux host1:~$ scp . some.config 100% 1612 1.6KB/s 00:00 host1:~$ logout Connection to closed. </code></pre> <h2>Secret Agent</h2> <p>The SSH agent has become so integrated into our local systems many people don&#8217;t realize it&#8217;s being used. Devs use it daily to avoid having to retype their SSH key<sup id="fnref:p6487162976-1"><a href="#fn:p6487162976-1" rel="footnote">1</a></sup> password every time they connect to a remote host. The typical workflow is:</p> <ol><li>Login to laptop</li> <li>SSH to a remote host</li> <li>Type SSH key password into popup</li> <li>No more password typing</li> </ol><div align="center"> <p><img src="/tumblr_lgvrapP33n1qa5gs9.png" alt="OS X built-in askpass app"/></p> </div> <p>The agent serves us by holding onto our private key and transparently authenticating to remote hosts when we connect instead of making us type a password.<sup id="fnref:p6487162976-2"><a href="#fn:p6487162976-2" rel="footnote">2</a></sup></p> <h2>What is SSH agent forwarding?</h2> <p>Simply put, agent forwarding allows you to access a remote machine from a remote machine.</p> <p>Let&#8217;s look at the scenario above: connect to host1 and download a file from host2. Without agent forwarding, you&#8217;re lucky if you just get to type your password again. If host2 has password authentication disabled or your account has no password set, there&#8217;s two options. Option 1: download the file from host2 to your local machine and then upload it to host1. Option 2: upload your SSH <em>private</em> key to host1 and authenticate to host2 using your key password. Compare these to agent forwarding where you run <code>scp</code> and the file is downloaded without question.</p> <p>If you&#8217;ve run into this problem more than a few times, learning about agent forwarding may feel like this:</p> <div align="center"> <p><a href=""><img src="/tumblr_lgvu1gsRtb1qa5gs9.png" alt="ssh -A is the shit! No more moving private keys around for chained ssh connections!! Thanks @brainsik!"/></a></p> </div> <h2>Where can it take you?</h2> <p>The SSH agent provides a rare pairing of increased security and better user experience.</p> <p>From a per-host perspective, you can disable password authentication on all your remote machines and rely on SSH keys for superior auth. Leaked passwords are no longer a vector for unauthorized access since you can&#8217;t login with them. Forget about generating random passwords for every user on every new server. If sudo access isn&#8217;t needed, don&#8217;t set a password at all. If sudo access is required you can get away with reusing passwords, keeping your <a href="">devops</a> team <a href="">lean</a><sup id="fnref:p6487162976-buzzwords"><a href="#fn:p6487162976-buzzwords" rel="footnote">3</a></sup>.</p> <p>From a network perspective, you ideally want your private servers only accessible via a <a href="">bastion host</a> or other intermediary. With agent forwarding, instead of this setup being a pain to get into, it&#8217;s a single command:</p> <pre><code>$ ssh -At ssh private1.internal Linux private1 2.6.35-25-server #44-Ubuntu SMP Fri Jan 21 19:09:14 UTC 2011 x86_64 GNU/Linux private1:~$ logout Connection to private1.internal closed. Connection to closed. </code></pre> <h2>Use it</h2> <p>Agent forwarding can be turned on via the command-line by passing <code>-A</code> or via <a href="">your SSH config</a> by setting <code>ForwardAgent yes</code>.</p> <p>I&#8217;d be negligent if I didn&#8217;t recommend setting this <em>only</em> for hosts you trust. While it&#8217;s not possible to steal a private key through an agent, it&#8217;s trivial for a malicious <strong>root</strong> user to login to remote hosts with your public key.</p> <p>Is there another way you use SSH agent forwarding? You should post a comment or <a href="/ask">send me a message</a>.</p> <div class="footnotes"> <hr><ol><li id="fn:p6487162976-1"> <p>This article assumes you already use an <strong>SSH key</strong> to access remote hosts. If you don&#8217;t, <a href="/ask">send me a note</a>. If I get enough questions about SSH keys, I&#8217;ll do a writeup on them. <a href="#fnref:p6487162976-1" rev="footnote">↩</a></p> </li> <li id="fn:p6487162976-2"> <p>Some systems aren&#8217;t setup with an askpass program and the agent running in the background. In those cases, some devs will generate their SSH private key without a password to get the effect of not needing to type in their password for every SSH connection they make. Regardless of the security implications, that setup loses a beneficial feature of SSH: agent forwarding! <a href="#fnref:p6487162976-2" rev="footnote">↩</a></p> </li> <li id="fn:p6487162976-buzzwords"> <p>Buzzwords aside, having to search for a password randomly generated 2 months ago before getting on with your task is sure way to <a href="">wipe stored state</a> and kill a task&#8217;s momentum. <a href="#fnref:p6487162976-buzzwords" rev="footnote">↩</a></p> </li> </ol></div>, 13 Jun 2011 06:31:07 -0700devopshowtosshSSH Config<p><em>This is part of the mini-series <a href="">OpenSSH for Devs</a>.</em></p> <p>An SSH config let&#8217;s you set options you use often (e.g., the user to login as or the port to connect to) globally or per-host. It can save a lot of typing and helps make SSH Just Work.</p> <h2>Example</h2> <p>Instead of typing:</p> <pre><code>ssh -p734 </code></pre> <p>You can type:</p> <pre><code>ssh sencha </code></pre> <p>By having this in your <code>~/.ssh/config</code>:</p> <pre><code>Host sencha HostName Port 734 User teamaster </code></pre> <h2>What&#8217;s a per-user SSH config?</h2> <p>In your home is a <code>.ssh</code> directory. This is where your SSH keypair and <code>known_hosts</code><sup id="fnref:p6283709781-known_hosts"><a href="#fn:p6283709781-known_hosts" rel="footnote">1</a></sup> files are. This directory is not made of unicorns. Create a file named <code>config</code> and your SSH tools<sup id="fnref:p6283709781-ssh tools"><a href="#fn:p6283709781-ssh%20tools" rel="footnote">2</a></sup> will use it&#8217;s settings.</p> <p>If your laptop username is different than the one on your remote hosts, create it with:</p> <pre><code>User jon.postel </code></pre> <p>If you use a non-standard SSH port to avoid the bots, create it with:</p> <pre><code>Port 22022 </code></pre> <p>Have different settings for different hosts? No problem. Just keep in mind the first match wins and put specific settings <em>before</em> generic ones:</p> <pre><code># ancient box we never upgraded Host User oldusername # still on port 22 Host * Port 22022 ForwardAgent yes # defaults for all hosts Host * User bofh </code></pre> <h2>It gets better</h2> <p>You&#8217;re probably familiar with the dance you do when connecting to a host for the first time:</p> <pre><code>$ ssh The authenticity of host ' (' can't be established. RSA key fingerprint is 39:9b:de:ad:9e:be:ef:95:ca:fe:1b:53:b0:00:00:b5. Are you sure you want to continue connecting (yes/no)? </code></pre> <p>It looks impressive, but it&#8217;s worthless. If you&#8217;re worried about <a href="">man-in-the-middle attacks</a>, there are <em>much</em> better things to do. Start by disabling password authentication<sup id="fnref:p6283709781-passauth"><a href="#fn:p6283709781-passauth" rel="footnote">3</a></sup> and require people to have an SSH key on the server. Expecting people to check these hashes means you&#8217;ve already failed.</p> <p>To get rid of the dance add something like:</p> <pre><code>Host * StrictHostKeyChecking no </code></pre> <p>First time connections will give you a warning, but you&#8217;ll make it in.</p> <h2>Aliases</h2> <p>You can create aliases<sup id="fnref:p6283709781-aliases"><a href="#fn:p6283709781-aliases" rel="footnote">4</a></sup> by using <strong>Host</strong> to match a name and <strong>HostName</strong> to say where to connect.</p> <pre><code>Host web1 HostName </code></pre> <p>The advantages over modifying <code>/etc/hosts</code> are you don&#8217;t need to be root and SSH will use the same host key for web1 and The disadvantage is that only SSH tools see this. For example, your browser has no idea web1 is an alias for that EC2 host. Because of this, I sometimes create both the SSH alias and hosts entry for the best of both worlds.</p> <h2>Options</h2> <p>There are <a href="">a lot of options</a>, but these are the ones I&#8217;ve seen used most:</p> <ul><li><strong>Host</strong> — Matches the hostname argument. Accepts <a href="">patterns</a> and causes options following it to apply only to hosts matching the pattern.</li> <li><strong>User</strong> — Username to connect with.</li> <li><strong>Port</strong> — Port to connect to.</li> <li><strong>ForwardAgent</strong> — Set to <code>yes</code> to turn on <a href="">SSH agent forwarding</a>.</li> <li><strong>StrictHostKeyChecking</strong> — Set to <code>no</code> to skip the &#8220;authenticity of host&#8221; dance.</li> <li><strong>HostName</strong> — Server to connect to. Used to create an alias from <strong>Host</strong> to another remote server. </li> </ul><p>Do you have a favorite option not mentioned here? You should post a comment or <a href="/ask">send me a message</a>.</p> <div class="footnotes"> <hr><ol><li id="fn:p6283709781-known_hosts"> <p>The <code>known_hosts</code> file contains the keys for all the remote hosts you&#8217;ve connected to. The stored key is compared to the remote key when you connect to warn of a <a href="">man-in-the-middle attack</a>. <a href="#fnref:p6283709781-known_hosts" rev="footnote">↩</a></p> </li> <li id="fn:p6283709781-ssh tools"> <p><code>ssh</code>, <code>scp</code>, <code>sftp</code>, <a href=""><code>sshfs</code></a>, <a href="">well-written paramiko</a> based Python tools, and probably more. <a href="#fnref:p6283709781-ssh%20tools" rev="footnote">↩</a></p> </li> <li id="fn:p6283709781-passauth"> <p>In the server&#8217;s <code>sshd_config</code> set <code>PasswordAuthentication no</code>. <a href="/ask">Contact me if you are interested in a post on securing the SSH server</a>. <a href="#fnref:p6283709781-passauth" rev="footnote">↩</a></p> </li> <li id="fn:p6283709781-aliases"> <p>I made this term up. There may be a better one. <a href="#fnref:p6283709781-aliases" rev="footnote">↩</a></p> </li> </ol></div>, 07 Jun 2011 06:30:06 -0700howtosshdevopsOpenSSH for Devs<p>There have been many surprises as I&#8217;ve moved from Sysadmin to Coder. Some of them are a product of switching contexts: what was once &#8220;common knowledge&#8221; is now &#8220;tips &amp; tricks&#8221; (and vice versa). One tool that has regularly come up is SSH. It can be painful to watch developers jump through unnecessary hoops (over and over again) in order to access remote hosts.</p> <p>In that light, presented here is a short series of posts covering useful OpenSSH features for developers. My peers and I use these everyday and it&#8217;s made our jobs easier.</p> <ul><li><a href="/post/6283709781/ssh-config">SSH Config</a></li> <li><a href="/post/6487162976/ssh-agent-forwarding">SSH Agent Forwarding</a></li> <li>SSH Tunnels <em>check back soon</em></li> </ul>, 06 Jun 2011 18:51:00 -0700devopssshBrewer's CAP Theorem<a href="">Brewer's CAP Theorem</a>: <p>Starting with the punk rock creation story, discusses the fascinating, <em>proven</em>, theorem that you can’t have all three of consistency, availability, and partition-tolerance in a distributed system.</p> <p>A very interesting follow-up is: <a href="">A CAP Solution (Proving Brewer Wrong)</a>. It approaches the problem by dynamically guaranteeing different CAP properties instead of trying to guarantee them all at once.</p>, 26 May 2011 08:21:00 -0700cloudReleased Virtualenv Burrito 2<p>This Python breakfast just got tastier. A major update to the way Virtualenv Burrito works was released this weekend. There is now full support for extension points and a less hackish way of managing the packages<sup id="fnref:p5766370205-packages"><a href="#fn:p5766370205-packages" rel="footnote">1</a></sup> under the hood.</p> <p>Already have Virtualenv Burrito installed? Run this:</p> <pre><code>virtualenv-burrito upgrade </code></pre> <p>New to Virtualenv Burrito? <a href="">Read about it</a> or run this:</p> <pre><code>curl -s <a href=""></a> | bash </code></pre> <p>Virtualenv Burrito&#8217;s goal is to have a working virtualenv + virtualenvwrapper environment with just one command. <a href="">Read about it on Github</a> or <a href="">see the original announcement</a>.</p> <div class="footnotes"> <hr><ol><li id="fn:p5766370205-packages"> <p><a href="">distribute</a>, <a href="">virtualenv</a>, and <a href="">virtualenvwrapper</a> <a href="#fnref:p5766370205-packages" rev="footnote">↩</a></p> </li> </ol></div>, 23 May 2011 06:30:00 -0700pythonvirtualenvAnnouncing Virtualenv Burrito<p>Over the weekend I finished<sup id="fnref:p4002626727-futurework"><a href="#fn:p4002626727-futurework" rel="footnote">1</a></sup> a tool called <a href="">Virtualenv Burrito</a>. It&#8217;s goal was to be a single command which would setup <a href="">Virtualenv</a> and <a href="">Virtualenvwrapper</a> so you could start hacking on Python projects as quickly as possible. As a bonus, it installs the <code>virtualenv-burrito</code> command which will upgrade those packages to the latest versions I&#8217;ve tested.</p> <p>Virtualenv Burrito was inspired by <a href="">Pycon sprinters</a> wasting precious time setting up virtual environments instead of sprinting. For many people, it&#8217;s sadly complicated to get a virtualenv + virtualenvwrapper environment. The worst part, it&#8217;s almost always yak shaving in the way of a real goal.</p> <p>No more! To have a working virtualenv + virtualenvwrapper environment, run this command<sup id="fnref:p4002626727-insane"><a href="#fn:p4002626727-insane" rel="footnote">2</a></sup>:</p> <pre><code>curl -s <a href=""></a> | bash </code></pre> <p>That&#8217;s it. Whenever you login, you&#8217;ll have <a href="">the full arsenal of virtualenvwrapper commands</a> at your disposal.</p> <h2>Virtualenv quickstart</h2> <p>Create a new virtualenv:</p> <pre><code>mkvirtualenv newname </code></pre> <p>Once activated, pip install (<em>without</em> using sudo) whichever Python packages you want. They&#8217;ll only be available in that virtualenv. Make as many virtualenvs as you like.</p> <p>To switch to another virtualenv you&#8217;ve created:</p> <pre><code>workon othername </code></pre> <h2>Upgrade</h2> <p>To get the latest tested virtualenv + virtualenvwrapper packages:</p> <pre><code>virtualenv-burrito upgrade </code></pre> <h2>Credits</h2> <p>The real hard work is done by the creators of <a href="">Virtualenv</a> and <a href="">Virtualenvwrapper</a>. Virtualenv is maintained by <a href="">Ian Bicking</a>. Virtualenvwrapper is maintained by <a href="">Doug Hellman</a>.</p> <div class="footnotes"> <hr><ol><li id="fn:p4002626727-futurework"> <p>For this release, <a href="">extension points</a> (e.g., postactivate) are not supported. While this doesn&#8217;t affect the project goal of getting people coding quickly, it&#8217;s a cool feature, and (more importantly) I need it for work. :-) I&#8217;ll be adding support soon and making it available via <code>virtualenv-burrito upgrade</code>. <a href="#fnref:p4002626727-futurework" rev="footnote">↩</a></p> </li> <li id="fn:p4002626727-insane"> <p>Truth be told, I think piping the web into your shell is insane. Be safe, and <a href="">read the code</a>. <a href="#fnref:p4002626727-insane" rev="footnote">↩</a></p> </li> </ol></div>, 21 Mar 2011 06:30:00 -0700pythonvirtualenvAdam Simpson's 2011 BAFTA illustrations<a href="">Adam Simpson's 2011 BAFTA illustrations</a>: <p>Gorgeous illustrations for the 5 Best Film nominees. Also see his <a href=",1634,BA.html#jump6">BAFTA mask illustration</a> used for the tickets.</p>, 21 Feb 2011 13:23:00 -0800artLatent Figure Protocol<a href="">Latent Figure Protocol</a>: <p>Paul Vanoue’s Latent Figure Protocol “utilizes known sequences in online [DNA] databases to produce ‘planned’ images” of ☠ and ©. Fantastic work!</p>, 14 Feb 2011 09:00:06 -0800artscienceBomb crater swimming pools<a href="">Bomb crater swimming pools</a>: <p>"A trained civil engineer, he then turned the hole into a kidney-shaped swimming pool, flourished with a fine biomorphic indentation."</p>, 13 Feb 2011 16:28:00 -0800artCarniverous furniture<a href="">Carniverous furniture</a>: <p>Disturbing and intriguing.</p>, 13 Feb 2011 16:27:00 -0800artrobotsscienceTools never die. Waddaya mean, never?<a href="">Tools never die. Waddaya mean, never?</a>, 13 Feb 2011 12:26:00 -0800techMy neutrophils can kick your white blood cells' butt<a href="">My neutrophils can kick your white blood cells' butt</a>, 13 Feb 2011 12:25:00 -0800artAutoinstall Ubuntu servers with a CD<p>Although it&#8217;s been a few years since I switched from full-time Sysadmin to full-time Coder, being in a startup means getting <a href="">saddled with an opsy task</a> now and again regardless of your &#8220;title&#8221;.</p> <p>The problem: We bought a bunch of servers which need minimal OS, IP and a hostname before they&#8217;re racked. In otherwords, we want to drop them in a datacenter, turn them on, and leave knowing there&#8217;s remote SSH access. Data centers are environmentally hostile (hot rows, cold rows, too loud). It&#8217;s ideal to get in and out as quickly as possible and do any remaining config while <a href="">listening to music</a> and <a href="">having a cup of tea</a>.</p> <p>The solution: An <a href="">automated Ubuntu install using <em>preseeding</em></a>. One goal is to get a solution setup as quickly as possible. We don&#8217;t have 100s or 1000s of servers that need install, but we don&#8217;t want to setup temporary network infrastructure, and we don&#8217;t want all the developers (there&#8217;s not many) sitting around hitting <code>&lt;enter&gt;</code> every few minutes. In my past life I may have gone for <a href="">netbooting</a> and a DHCP server handing out the IPs and hostnames, but this life lead to the shorter road of burning an Ubuntu Server disc with <a href="">a preseed file</a>.</p> <h2>Configuring the disc image</h2> <p>Open an existing <a href="">Ubuntu Server image</a> and copy it&#8217;s contents somewhere. I used <code>rsync -a</code> to copy the image volume to my drive. This directory is the contents of the <em>new</em> disc image. All that&#8217;s needed is a preseed file and modifying the boot config to load it.</p> <h3>Creating a seed file</h3> <p>Start with <a href="">the example Maverick preseed file</a>. The comments are good so you can get most of the way just going through it. However, I ended up in a short trial and error process to get it fully baked.</p> <h4>Gotcha 1: LVM partitioning</h4> <p>During LVM partitioning, the install got stuck while waiting for confirmation on &#8220;Write the changes to disk and configure LVM?&#8221;:</p> <div align="center"> <p><img src="/tumblr_lg16dvXBxX1qa5gs9.png" alt="LVM partitioning confirmation"/></p> </div> <p>Set this undocumented (AFAICT) option:</p> <pre><code>d-i partman-lvm/confirm_nooverwrite boolean true </code></pre> <h4>Gotcha 2: Apt security update from the network</h4> <p>Althought this doesn&#8217;t stop the install, it takes a while for Apt to give up trying to contact the host. To keep things speedy, disable it by setting a null security repo host:</p> <pre><code>d-i apt-setup/security_host string </code></pre> <h4>Bonus: Setup the apt/sources.list</h4> <p>With all the Apt repositories disabled, no useful lines are added to <code>/etc/apt/sources.list</code>. This doesn&#8217;t matter too much if next you&#8217;ll be running an install script on the box (fix the sources.list in the script), but if not, it&#8217;s an annoying yak you&#8217;ll shave when you want to upgrade or install a package. Regardless, it&#8217;s so easy to make it right, you might as well:</p> <pre><code>d-i preseed/late_command string echo 'deb <a href=""></a> maverick main restricted universe multiverse' &gt;&gt; /target/etc/apt/sources.list; echo 'deb maverick-updates main restricted universe multiverse' &gt;&gt; /target/etc/apt/sources.list; echo 'deb <a href=""></a> maverick-security main restricted universe multiverse' &gt;&gt; /target/etc/apt/sources.list </code></pre> <p>Your preseed config is done so save it to <code>preseed/local.seed</code> (or whatever/wherever) in the directory you made.</p> <h3>Modifying the boot config</h3> <p>To make the CD use your seed on boot, <a href="">modify <code>isolinux/isolinux.cfg</code></a> to timeout quick and use the file you saved. Mine looks like this:</p> <pre><code># D-I config version 2.0 include menu.cfg default autoinstall prompt 0 timeout 1 ui gfxboot bootlogo LABEL autoinstall menu label ^Minimal autoinstall kernel /install/vmlinuz append preseed/file=/cdrom/preseed/local.seed debian-installer/locale=en_US console-setup/layoutcode=us localechooser/translation/warn-light=true localechooser/translation/warn-severe=true initrd=/install/initrd.gz ramdisk_size=16384 root=/dev/ram rw quiet -- </code></pre> <h2>Creating the disc image</h2> <p>To make a bootable ISO you&#8217;ll need <strong>mkisofs</strong>. If you&#8217;re on Mac OS X (like me) you can <a href="">use MacPorts</a> — <code>sudo port install cdrtools</code> — or the <a href="">hipster package manager</a><sup id="fnref:p3088899594-1"><a href="#fn:p3088899594-1" rel="footnote">1</a></sup>, Homebrew. Once you have the tool you need, just <a href="">follow this command-line</a>:</p> <pre><code>mkisofs -r -V 'Ubuntu Autoinstaller' -cache-inodes -J -l -b isolinux/isolinux.bin -c isolinux/ -no-emul-boot -boot-load-size 4 -boot-info-table -o custom_ubuntu_autoinstaller.iso /path/to/your/files </code></pre> <p>And … your done. Use <a href="">Virtualbox</a> to test the boot image and tweak the preseed file to make it do what you want. Don&#8217;t forget to re-run the <code>mkisofs</code> command whenver you change the seed or <code>isolinux.cfg</code> files!</p> <div class="footnotes"> <hr><ol><li id="fn:p3088899594-1"> <p>Just kidding. I&#8217;m a fan of <a href="">mxcl&#8217;s projects</a>. Got <a href=""></a> running right now! <a href="#fnref:p3088899594-1" rev="footnote">↩</a></p> </li> </ol></div>, 03 Feb 2011 09:47:00 -0800sysadminubuntuhowtocloud