subcritical


Running a Django Server at Home

 Eric Williams | 26 April, 2016
 Comments
linux sysadmin django 

This is a quick run-down of how to host a Django website on your home broadband connection.

Why in the world would you want to do this? It has some advantages: Broadband has decent bandwidth these days, and cloud VMs generally can't compete with run-of-the-mill PC hardware in terms of memory, disk throughput, and CPU power.

There are disadvantages too, obviously, but for non-production systems running your own server can be a lot of fun!

Install Ubuntu Server

Ubuntu Server is fine and stable, and a brand new version just came out.

This post refers to 14.04 (Trusty), since I haven't gotten around to setting up a new version as of yet. 14.04 still has a few years of support left, so don't be afraid to deploy with it.

Install Apache

I know all the cool kids like Nginx, but Apache has modwsgi and modpython, so I find it suits my needs.

sudo apt-get install apache2-server libapache-mod-wsgi

Create a project directory

You can put your Django projects anywhere, but make sure it's readable / writable by the user or group that's running Apache: www-data.

sudo mkdir -p /srv/projects/
sudo chown myuser:www-data
cd /srv/projects

Create a virtual environment to host your Django stuff.

sudo apt-get install python-virtualenv
virtualenv .
. bin/activate
pip install django
django-admin startproject website

Now, setup your website Django project as you like.

Configure Apache

Setup a conf file for your website, /etc/apache/sites-available/website.conf

WSGIPythonPath /srv/projects/website/:/srv/projects/lib/python2.7:/srv/projects/lib/python2.7/plat-x86_64-linux-gnu:/srv/projects/lib/python2.7/lib-tk:/srv/projects/lib/python2.7/lib-old:/srv/projects/lib/python2.7/lib-dynload:/usr/lib/python2.7:/usr/lib/python2.7/plat-x86_64-linux-gnu:/usr/lib/python2.7/lib-tk:/srv/projects/local/lib/python2.7/site-packages:/srv/projects/lib/python2.7/site-packages


<VirtualHost *:80>
    ServerName internal.server.com
    ServerAlias subcritical.org
    ServerAlias www.subcritical.org
    ServerAlias media.subcritical.org
    SetEnv DJANGO_SETTINGS_MODULE website.settings

    WSGIScriptAlias / /srv/projects/subc/subc/wsgi.py

    Alias /static/ /var/www/static/
    Alias /media/ /var/www/media/

    <Directory "/srv/projects/website/website/">
        Require all granted
    </Directory>

    <Location /static/>
        Order allow,deny
        Allow from all
        SetHandler none
    </Location>
    <Location /media/>
        Order allow,deny
        Allow from all
        SetHandler none
    </Location>
</VirtualHost>

Enable the website

sudo a2dissite 00-default 
sudo a2ensite website 
sudo service apache2 restart

Check the website internally

wget http://internal.server.com

Forward your Router

Make sure to forward port 80 and 443 from your router to your internal server.

Setup Dynamic DNS

If you have a website on a dynamic IP address, which is usually the case with home IP connections, you need to have some way of keeping that IP address known.

PyDDNS can help with this, as long as your domain is hosted on Amazon's Route 53. Otherwise, you can use Dynamic DNS services like No-IP to take care of that.

Django Simpleticket

 Eric Williams | 20 April, 2016
 Comments
django reddit 

Just saw this flash past on Reddit:

The intent of this project is to provide a simple ticket-tracking app that can easily be dropped into a new or existing Django site. It aims for bare bones simplicity rather than elaborate features, minimizing dependencies and allowing the app to be set up in as little time as possible.

And while I enjoy seeing Apps for Django going by, I’m not sure I’m going to have the time to look at this one. I miss my sabbatical.

Getting started with Ansible

 Eric Williams | 16 June, 2014
 Comments
ansible devops 

Setting up an Ansible test environment with LXC

These examples are made using Ubuntu 12.04 LTS and LXC.

To make this as easy as possible, it's a good idea to be using a local dnsmasqd to handle DHCP, DNS, and dynamic DNS for container instances.

We're going to make a small environment that simulates a few webservers, a database server, and an HTTP load-balancer. This will make 6 LXC containers, including the Ansible workstation that we'll be using for the ansible commands.

First, create a few machines using the lxc-create command:

sudo lxc-create -t ubuntu -n ansible-workstation -- -r precise --auth-file ~/.ssh/id_rsa.pub
sudo lxc-start -n ansible-workstation -d
for i in {1..3}; 
do sudo lxc-create -t ubuntu -n ansible-web-${i} -- -r precise --auth-key ~/.ssh/id_rsa.pub
   sudo lxc-start -n ansible-web-${i} -d
done

SSH into the Ansible workstation and setup Ansible:

ssh -l ubuntu ansible-workstation
sudo locale-gen en_{US,GB}{.UTF-8,}
ssh-keygen
sudo apt-get install -y python-software-properties
sudo apt-add-repository ppa:rquillo/ansible
sudo apt-get update
sudo apt-get install -y ansible

Ansible should be installed now. We're going to setup the ansible clients (ansible-web-{1,2,3}), add our ssh key now, and update the sudoers file to make things easy. Ansible keeps its list of hosts under /etc/ansible/hosts:

$ cat /etc/ansible/hosts
[webservers]
ansible-client-[1:3].home.hokeypokeyland.org

Create the sudoers file:

cat 10_ubuntu
ubuntu ALL=(ALL) NOPASSWD:ALL

Now see if your connection to the clients is working:

$ ansible -m ping all
ansible-web-1.home.hokeypokeyland.org | success >> {
    "changed": false,
    "ping": "pong"
}

ansible-web-2.home.hokeypokeyland.org | success >> {
    "changed": false,
    "ping": "pong"
}

ansible-web-3.home.hokeypokeyland.org | success >> {
    "changed": false,
    "ping": "pong"
}

Copy our ssh key and sudoers file over to all those machines:

ansible all -m copy -a "src=~/.ssh/id_rsa.pub dest=~/.ssh/authorized_keys mode=0600" -k
ansible all -m copy -a "src=10_ubuntu dest=/etc/sudoers.d/10_ubuntu mode=0440 \
   owner=root group=root" --sudo --ask-sudo-pass

At this point, we should be able to run commands via sudo on these machines.

Using Playbooks to Install Packages

These machines are all going to be web servers, so we're going to do the most basic thing: Install Apache.

We'll create a simple playbook, apache.yml:

- hosts: webservers
  sudo: yes
  tasks:
      - name: Installs apache web server
      apt: pkg=apache2 state=installed update_cache=true

Apply it using the ansible-playbook command:

$ ansible-playbook apache.yml

PLAY [webservers] *************************************************************

GATHERING FACTS ***************************************************************
ok: [ansible-client-3.home.hokeypokeyland.org]
ok: [ansible-client-5.home.hokeypokeyland.org]
ok: [ansible-client-1.home.hokeypokeyland.org]
ok: [ansible-client-2.home.hokeypokeyland.org]
ok: [ansible-client-4.home.hokeypokeyland.org]

TASK: [Installs apache web server] ********************************************
failed: [ansible-web-1.home.hokeypokeyland.org] => {"failed": true}
msg: Could not import python modules: apt, apt_pkg. Please install python-apt package.
[...]
FATAL: all hosts have already failed -- aborting
[...]

Doh! We need to install python-apt on these machines.

ansible  -m shell -a 'sudo apt-get update && sudo apt-get install -y python-apt' webservers
ansible-playbook apache2.yml

You can run it again to see that everything is as expected:

$ ansible-playbook apache2.yml
PLAY RECAP ********************************************************************
ansible-client-1.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0
ansible-client-2.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0
ansible-client-3.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0
ansible-client-4.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0
ansible-client-5.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0
ansible-client-6.home.hokeypokeyland.org : ok=2    changed=0    unreachable=0    failed=0

Recap

  • Setup ansible
  • Setup LXC containers as ansible clients
  • Transfer files
  • Install packages via Ad Hoc commands
  • Run a simple playbook

Making Fedora Not Look Like Ass

 Eric Williams | 22 December, 2013
 Comments

It's been a while since I monkeyed around with Fedora. 10 years ago, I was all about SuSE; then I bought a PowerBook G4, which was immune to Linux for the most part, but I ran Debian on it a couple of times just to see what PowerPC Linux was looking like. Around 2005, I started using Fedora Core, and actually liked it quite a bit.

When I was toiling away at Red Hat, starting in 2007, I tried to use RHEL on the desktop. This lasted about 2 hours, at which point I blew it away and put Fedora 7 on it and never looked back. I never actually looked forward, either, and wound up running Fedora 7 until I left the company in 2010. This turned out to be a running gag with the team, who scoffed at my old-man-on-the-porch attitude towards newer releases, with their "features" and "SVGA displays".

Once I left Red Hat and started working for Canonical, I put Ubuntu on my MacBook Air; it was enjoyable for the most part. Ubuntu's a nice desktop distribution, and a good match for the MacBook Air's SSD and compact display. By the time Precise came out last year, installation was painless and the hardware support pretty top-notch.

Leaving Canonical, I figured it was time to revisit Fedora. I tore down my Precise installation and went about trying to get Fedora 19 installed. This resulted in gigantic failure, mainly because of this bug. Don't bother trying to install this version, it won't work and you'll just be beating your head against a wall. Go for either Fedora 18 or the Fedora 20 beta.

Antialiasing

When you're done installing Fedora 20, you'll notice the fonts look like ASS compared to Ubuntu or Mac OS X. This appears to be due, in part, to the version of Freetype that Fedora uses.

This is taken from here.

  • Install the 'nonfree' version of freetype-freeworld from rpmfusion
  • Set the Xft.lcdfilter property in your Xresources file
  • Set up the hinting and antialising styles in gsettings
$ cat ~/.Xresources
  Xft.lcdfilter: lcddefault
$ gsettings "set" "org.gnome.settings-daemon.plugins.xsettings" "hinting" "slight"
$ gsettings "set" "org.gnome.settings-daemon.plugins.xsettings" "antialiasing" "rgba"
$ xrdb -query
Xft.antialias: 1
Xft.dpi: 96
Xft.hinting: 1
Xft.hintstyle: hintslight
Xft.lcdfilter: lcddefault
Xft.rgba: rgb

Now, I don't know why one has to do that, but one does. After this, you'll notice that the standard fonts start looking great. Even in Terminator.

Missing Fonts

I did find on occasion that I'd run across web pages, emails, etc. that included fonts that, once again, looked like 1997 Linux. Figuring this was because of shit font substitution, I installed the following:

  • Microsoft ttf core fonts
    • Arial
    • Times New Roman
    • Tahoma
    • etc

  • The Ubuntu font collection
  • Mac OS X Fonts

    • Lucida Grande
    • Apple Garamond

Even after doing all of this, though, I still have to put put up with font horridness. DejaVu Sans, specifically. It is jaggy and horrible, and unfortunately it can't be uninstalled because of LibreOffice's ill-advised package dependency on it. It basically just means that whenever I go to Fedora Project sites, I get eye-raped by unreadable fonts.

jaggy-ass-fonts

Despite the eye-rape, I quite like GNOME Shell, and GNOME 3.10 in general. It's a nice, productive desktop, and very attractive to look at. With natural scrolling turned on and apps running full-screen, it's a great match with the MacBook Air.

I do think that it makes inefficient use of my 11-inch screen, though. The title bars in application windows are gigantic, for example, with a big gray stripe that does nothing except waste my pixels and remind you that yes, you are running GNOME 3.

I quite like the fact that when I setup online accounts in the control panel, they actually do something. In Ubuntu, the underlying GNOME infrastructure does less and less, but they don't bother taking out the user interface bits that make you think that when you configure something, it will actually be used somewhere.

Changing the hostid in Linux

 Eric Williams | 14 November, 2011
 Comments
linux sysadmin 

The hostid on some systems, like Suns, is set in the hardware and uniquely identifies the system. On Linux, the hostid is more of a suggestion than a hard-and-fast rule. It's usually generated at install time, and can be changed with a few lines of python code:

      #!/usr/bin/python
      from struct import pack
      hostid = pack("I",int("0x210a2500",16))
      filename = "/etc/hostid"
      open(filename,"wb").write(hostid)

You can check this then with the hostid command.

  # hostid
  210a2500

Protip: It's always a good idea to back up /etc/hostid first, just in case.

This can help workaround issues with applications like flexlm, that naively assume that hostid is in some way significant on Linux.

Launchd in Ubuntu

 Eric Williams | 1 September, 2011
 Comments
linux sysadmin launchd 

In the various flavors of UNIX, you usually have an init or init-like process which wrangles all the sundry system services. Things like your mail server, your ftp server, etc. all have to be started by something.

In Ubuntu, we use Upstart since Lucid. It's a modern, event-based init daemon. Red Hat Enterprise Linux 5 uses the fine old SysVInit system. In RHEL 6, you also have Upstart, but it's being run in a SysVInit-compatibility mode. RHEL's cousin, Fedora, uses systemd.

Under Mac OS X Tiger and later, there's launchd. This not only replaces init, but also cron and a couple of other traditional UNIX facilities.

According to The Book of Knowledge

The Ubuntu Linux distribution considered using launchd in 2006. However, launchd was rejected as an option because it was released under the Apple Public Source License – which at the time was described as an "inescapable licence problem".

In August 2006, Apple relicensed launchd under the Apache License, Version 2.0 in an effort to make adoption by other open source developers easier.

I'm not so convinced that licensing was the main reason that launchd was passed over. I wasn't around Ubuntu or Canonical at the time, and I've heard conflicting accounts from various Canonical employees on the matter.

With as much time and effort as we've put into Upstart in the meanwhile, it's turned out to be a pretty good solution.

People complain about the upstart configuration file syntax. If you compare it aginast the property list approach, though, it's like writing hot buttered biscuits and bacon.

For comparison, here's a property list for postfix (stolen from Macworld):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
            <key>Label</key>
            <string>org.postfix.master</string>
            <key>Program</key>
            <string>/usr/libexec/postfix/master</string>
            <key>ProgramArguments</key>
            <array>
                    <string>master</string>
            </array>
    </dict>
    </plist>

Postfix isn't upstartified in Ubuntu (yet), but here's a comparable rsyslog upstart config:

#
# rsyslog is an enhanced multi-threaded replacement for the traditional
# syslog daemon, logging messages from applications

description     "system logging daemon"

start on filesystem
stop on runlevel [06]

expect fork
respawn

script
    . /etc/default/rsyslog
    exec rsyslogd $RSYSLOGD_OPTIONS
end script

Launchd might be stable, and it's what all the cool BSD kids are running these days, but it breaks one of the commandments: XML is not to be considered human-writable. It's a data format.

Heading to Canada

 Eric Williams | 16 April, 2011
 Comments
travel Canadia 

I'm getting ready to head over to Montreal, or "Mon' cccchhhhrayall" as the indigenous people of Canadia refer to it. It's all about business, though, and I unfortunately will not be seeing any hockey playoffs, except maybe on TV.

Not that it's sounding bad at the moment, mind you. I'm sitting in a bar in Heathrow's Terminal 5 watching two televisions. TV #1 is displaying cricket, which is England's version of baseball. TV #2 is playing Fawlty Towers with subtitles, which is England's version of waterboarding. God damn, I hate Fawlty Towers.

Montreal looks to have some sights to see, but I'm not sure what the opening hours look like. I've been living on the goofy side of the pond for going on 13 years now, and I'm actually accustomed to things like paying a license fee for television ownership and bars closing at 10 o'clock at night. Not to mention dog tax. With that in mind, it could be that bars are open 24x7, the restaurants never close, and we'll never get any older and we won't ever die. This is my expectation, and you should know I don't react well to disappointment.

This will be my first trip to Canada. I've been to a fair number of countries, but the list has been pretty static for a while now. In the past months I've expanded it with Greece and Canada. Next month, I'll be heading to Hungary for the first time.

Coming up: How to handle a full passport.

Asimo Freaks Me Out

 Eric Williams | 4 February, 2010
 Comments
robots freak 

This creepy-ass little robot crossed with an Aibo would just about weird the shit out of anybody.

Pro tip: If you really want to feel your skin crawl, watch that video with Bauhaus's "Bela Lugosi's Dead" playing in the background.

OS News Makes You Stupid

 Eric Williams | 9 September, 2007
 Comments
osnews 

I like reading OSNews for some reason. I think I like to catch the geeky news about SkyOS, or the occasional retro curmudgeonry that rolls by about Lotus 1-2-3 or OS/2. Being the old-timer that I am, it's hard to resist a paean from my youth about 10-finger productivity.

Unfortunately, they've become the epicenter of stupid for the tech press. Check out this article, which explodes the myths about competition being good: "Competition is not Good"

'It gives consumers more choice'

Choice is good when there's one agreed base standard, and a number of compatible approaches. For example, there are many Linux distributions, but they are all Linux, and they can all run the same software. They are 'flavours' of the same thing, that is a good choice. People like different flavours.

Competition does not produce easier choices for consumers. All they get is added un-interoperability and complexity with competitive choices.

Now, if you go read that article, which I do not recommend, you'll slowly come to the realization that this moron is just annoyed that he has to make the effort to choose between HD-DVD and Blu-Ray. He's willing to surrender his entire free will to some (hopefully) benevolent dictator, abolish brand names, and forsake the free market economy because choosing which format to buy the Firefly special edition box set in is hard. What a hopeless, whiny-assed sissy.

Of course, things don't get better when they start tossing political analysis at you. "Net Neutrality" is one monikers that has overshadowed the thing named. The discussion is often framed in a way that an uninformed listener would assume there was lobbying going on to abolish some sort of laws that are now protecting consumers from big, bad tiered-Internet ninjas.

But: There is no net neutrality legislation, there never was, and hopefully, there never will be. The argument over "Net Neutrality" is about whether or not the U.S. government should introduce legislation forbidding bandwidth throttling by ISPs. It's the "have you stopped beating your wife?" straw man for the Slashdot crowd. You'll notice that this article calls the Supreme Court's decision that the U.S. government shouldn't step in and configure the ISPs' Cisco routers for them, "Backing for Two-Tier Internet":

The US Justice Department has said that internet service providers should be allowed to charge for priority traffic. The agency said it was opposed to 'network neutrality', the idea that all data on the net is treated equally. The comments put the agency at odds with companies such as Microsoft and Google, who have called for legislation to guarantee equal access to the net.

Of course, this would also mean that an enforcement infrastructure would also have to be put in place, making sure that everyone got their "fair share" of said bandwidth, as if backbone routers and POPs just fell off a tree somewhere. God forbid ISPs be allowed to tune the services that they developed and paid for as they wish. Let's let the government decides who gets bandwidth, and how much is enough! That will make it all fair and neutral-like. Whenever a politician uses the word "fair", hang on to your wallet.

Crappy Wordpress

 Eric Williams | 9 September, 2007
 Comments
wordpress crap 

Well, my trackbacks are now working, it seems. There's some ugly Python spaghetti-code going on behind the scenes that translates back and forth between absolute urls, non-absolute relative urls, and upper-lower-camel case; but it works.

Trackbacks are only good for Movable Type, though. Which I can't stand anymore. MT used to be the only thing out there, but there's something that really, really, really galls me about the way it rebuilds your entire site into static HTML pages everytime you update a post. I'm sure it's awesomeness if you've got your server running on an old TV remote, but nowadays we're all running our web servers on 100-core 64-bit terahertz moonshot computers that can simultaneously compute π, encode MPEG video, and mix the best goddam margaritas you've ever tasted, all without breaking a sweat.

So yeah, I figured out how to implement trackbacks in Django, to a point where they more or less work. Now why is Wordpress fucking with me? It seems to be thrown off by the fact that Wordpress sends a HEAD request before it downloads and parses the page, in the vain hope that the X-Pingback header will be set. I can't figure out how to do that in Django's generic views, so I just use the secondary method, that being a link element in the XHTML code. But now, whenever a Worpdress blog pings me, I get this kind of crap:

  [09/Sep/2007 15:04:23] "GET /blog/2007/sep/08/vacation/ HTTP/1.1" 200 27367
Traceback (most recent call last):
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 273, in run
    self.finish_response()
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 312, in finish_response
    self.write(data)
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 396, in write
    self._write(data)
  File "/usr/local/lib/python2.4/socket.py", line 248, in write
    self.flush()
  File "/usr/local/lib/python2.4/socket.py", line 235, in flush
    self._sock.sendall(buffer)
error: (104, 'Connection reset by peer')
Traceback (most recent call last):
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 273, in run
    self.finish_response()
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 312, in finish_response
    self.write(data)
  File "/home/rubeon/lib/python2.4/django/core/servers/basehttp.py", line 396, in write
    self._write(data)
  File "/usr/local/lib/python2.4/socket.py", line 248, in write
    self.flush()
  File "/usr/local/lib/python2.4/socket.py", line 235, in flush
    self._sock.sendall(buffer)
error: (32, 'Broken pipe')

Being the half-assed programmer that I am, I am at a total loss. I can't even do a Lazyweb request here, seeing as my 4 visits a day are unlikely to bring the Django HTTP gurus by. I won't be able to sleep at night, thinking of all the enlightened Wordpress Users who are probably out there try to "Keep the discussion going" with me.