How do I make Rails use SSL to connect to PostgreSQL?
As you wrote, normally the Ubuntu 12.x packages are set up so that SSL is activated, works out of the box, and in addition is the first method tried by rails
, or any client that lets libpq
deal with this stuff, which means almost all clients.
This automatic enabling is not necessarily true with other PostgreSQL packages or with a self-compiled server, so the answers or advice applying to these other contexts don't help with yours.
As your setup should work directly, this answer is a list of things to check to find out what goes wrong. Preferably, use psql
first to test a connection setup rather than rails
, so that generic postgresql issues can be ruled out first.
Client-side
The client-side sslmode
parameter controls the sequence of connect attempts.
To voluntarily avoid SSL, a client would need to put sslmode=disable
somewhere in the connection string, or PGSSLMODE=disable
in the environment, or mess up with one of the other PGSSL*
variables. In the unlikely case your rails process had this in its environment, that would explain the error you're getting, given that pg_hba.conf
does not allow non-SSL connections.
Another reason to not try SSL is obviously when libpq
is not compiled with SSL support but that's not the case with the Ubuntu packages.
The default for sslmode
is prefer
, described as:
prefer (default)
first try an SSL connection; if that fails, try a non-SSL connection
The SSL=off
at the end of your error message relates to the last connect attempt that fails. It may be that SSL was tried and failed, or not tried at all, we can't know from this message alone. The connect attempt with SSL=off
is rejected normally by the server per the policy set in pg_hba.conf
(hostssl
in the first column).
It's more plausible that the problem is server-side, because there are more things than can go wrong.
Server-side
Here are various things to check server-side:
There should be
ssl=on
inpostgresql.conf
(default location:/etc/postgresql/9.1/main/
)when connecting to localhost with
psql
, you should be greeted with a message like this:
psql (9.1.13)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
The
ca-certificates
package should be installed and up-to-date.The
ssl-cert
package should be installed and up-to-date.Inside the postgres data directory (
/var/lib/postgresql/9.1/main
by default), there should be soft links:server.crt -> /etc/ssl/certs/ssl-cert-snakeoil.pem
or another valid certificate, andserver.key -> /etc/ssl/private/ssl-cert-snakeoil.key
or another valid key./etc/ssl/certs
and parent directories should be readable and cd'able by postgres.The
postgres
unix user should be in thessl-cert
unix group (check withid -a postgres
) otherwise it can't read the private key.If changing
postgresql.conf
, be sure that postgresql gets restarted before doing any other test.There shouldn't be any suspicious message about SSL in
/var/log/postgresql/postgresql-9.1-main.log
at startup time or at the time of the failed connection attempt.
Rails uses the PG gem for postgres to connect see here for the implementation:
https://github.com/rails/rails/blob/02a3c0e771b3e09173412f93d8699d4825a366d6/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L881
The PG gem uses libpg (c library) and the documentation on "PG::Connection.new" found here: http://deveiate.org/code/pg/PGconn.html
Suggests the following options:
host
server hostname
hostaddr
server address (avoids hostname lookup, overrides host)
port
server port number
dbname
connecting database name
user
login user name
password
login password
connect_timeout
maximum time to wait for connection to succeed
options
backend options
tty
(ignored in newer versions of PostgreSQL)
sslmode
(disable|allow|prefer|require)
krbsrvname
kerberos service name
gsslib
GSS library to use for GSSAPI authentication
service
service name to use for additional parameters
So this would indicate that the connection string will not work (since it is not recognised by the adapter, this might be a mysql adapter option)
Also this indicates that the sslmode=required
option should work, as this is a basic feature of libpg.
So:
database.yml
staging:
...
sslmode: "require"
...
should definitely do the trick, are you sure you use staging mode? // add sslmode to the other environments too to be sure.
Also libpg uses SSL by default as first try, maybe you see the error with SSL Off because SSL mode failed first, then libpq retried without ssl and eventually raised an error.