Installing and configuring PostgreSQL
I’ve tried quite a few times to get PostgreSQL up and running on my system. I’ve read plenty about how it’s ‘better’ than MySQL. Although I’ve not been convinced by that, purely the fact that I couldn’t install it was irritating me enough to give it another go.
For the first part, I was mostly able to follow the Ubuntu PostgreSQL documentation.
First, I installed it:
$ sudo aptitude install postgresql
then I connected using the postgres
default user:
$ sudo -u postgres psql template1
created a password for the postgres
user and quit:
template1=# \password postgres
template1=# \q
I like to be able to administer my databases under my own username, so next I created a user for me, gave it a password and created a database:
$ sudo -u postgres createuser --superuser myusername
$ sudo -u postgres psql
postgres=# \password myusername
postgres=# \q
$ createdb myusername
with these changes and the default Authentication
configuration, PostgreSQL is now configured to now accept my linux user as a valid user, all I need to do is type psql
at the command prompt and I’m away.
Next I wanted to be able to connect to databases within Python scripts. I also wanted to have a separate user for doing that, most likely a separate user per application.
psycopg2
appears to be the most prolific Python package for working with PostgreSQL. Installing it was unfortunately not as easy as pip install psycopg2
, but it almost was. Searching for the error I got pointed me straight at a Stack Overflow answer for how to install psycopg2 with pip on python. I’m not sure how the world got anything done before Stack Overflow.
$ sudo aptitude install libpq-dev python-dev
$ sudo pip install psycopg2
That worked fine, allowing me to write a quick test in Python:
#!python
import psycopg2
DSN = "dbname=myusername"
conn = psycopg2.connect(DSN)
curs = conn.cursor()
curs.execute("SELECT * from test")
print curs.fetchall()
conn.close()
I had already created a test
table with psql
. I then tested running the script as a different user:
$ sudo python postgres_test.py
as expected, it didn’t work; There is no user root
in PostgreSQL. Creating a new user for my application was almost as straightforward as creating my own user, with one extra bit at the end:
$ createuser myapp
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
$ createdb myapp
$ psql
myusername=# \password myapp
myusername=# ALTER DATABASE myapp OWNER TO myapp
The last line changes the owner of the myapp
database to belong to the myapp
user, that way only that user has any access to it, and nothing else. There’s probably a better way to do this, but this worked for me!
To test, I connected to the database as the myapp
user to check that everything was working:
$ psql -U myapp
psql: FATAL: Ident authentication failed for user "myapp"
Hmm. I then remembered from my previous excursions that there’s a configuration file for PostgreSQL that needs monkeying with. I found mine in /etc/postgresql/8.4/main/pg_hba.conf
$ sudo nano /etc/postgresql/8.4/main/pg_hba.conf
There’s a lot of comment-documentation in the file. By default, it only lets in linux users, so I could have created a new linux user myapp
and run psql
as that user (as I had been above as the postgres
user). I didn’t want to do that though.
Initially, I added a line to the file:
# Database administrative login by UNIX sockets
local all postgres ident
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all ident
local myapp myapp password
but it didn’t work, then I realised that PostgreSQL takes the rules in order and stops processing when it finds one that matches, the line above matches all users, so my line would need to go above it:
# "local" is for Unix domain socket connections only
local myapp myapp password
local all all ident
test again:
$ psql -U myapp
Password for user myapp:
perfect.
I could use my new user and database in python by changing the DSN
string:
#!python
DSN = "dbname=myapp user=myapp password=secret"
All working! Next I should probably get my head around SQLAlchemy.
I’m not really sure why I struggled so much in my past tries with PostgreSQL, I think I hadn’t quite gotten my head around how it dealt with users, and more than likely I made the same mistake in the pg_hba.conf
file but never noticed. It’s the kind of thing I do all the time!