Postgresql and Where the Wild Things Are: databases, tables and everything

I'd generally just search some directory inside /var, which might be quite obvious, but nothing will be better than reviewing the configuration that Postgresql is considering for its internal management. We don't want to do things in a remaining folder from a previous installation, so better know where we are. Plus, it's a safe way to access configuration files, independently of which distro or OS are you using. In my case, I want to know: where are the databases and tables inside the filesystem?

These are my databases:

postgres=# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-----------+----------+----------+------------+------------+-----------------------
 instagram | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
(4 rows)


Postgresql run-time configuration can be inspected via SHOW command on a PSQL shell. The configuration that matters here is data_directory:

postgres=# SHOW data_directory;
      data_directory      
--------------------------
 /var/lib/postgresql/data
(1 row)


Since I'm using Postgresql in a Docker container, I'll spawn a shell inside the container in order to navigate through the filesystem:

~ $ docker ps | grep lab_postgres
24999bd8c9ef   postgres   "docker-entrypoint.s…"   2 months ago   Up 5 hours   5432/tcp   lab_postgres
~ $ docker exec -it lab_postgres bash
root@24999bd8c9ef:/# cd /var/lib/postgresql/data

root@24999bd8c9ef:/var/lib/postgresql/data# ls -l
total 124
drwx------ 6 postgres postgres  4096 Jan 29 20:23 base
drwx------ 2 postgres postgres  4096 Jan 29 20:28 global
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_commit_ts
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_dynshmem
-rw------- 1 postgres postgres  4782 Nov 28 19:21 pg_hba.conf
-rw------- 1 postgres postgres  1636 Nov 28 19:21 pg_ident.conf
drwx------ 4 postgres postgres  4096 Jan 29 20:43 pg_logical
drwx------ 4 postgres postgres  4096 Nov 28 19:21 pg_multixact
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_notify
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_replslot
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_serial
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_snapshots
drwx------ 2 postgres postgres  4096 Jan 29 20:18 pg_stat
drwx------ 2 postgres postgres  4096 Jan 30 01:26 pg_stat_tmp
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_subtrans
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_tblspc
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_twophase
-rw------- 1 postgres postgres     3 Nov 28 19:21 PG_VERSION
drwx------ 3 postgres postgres  4096 Jan 29 20:40 pg_wal
drwx------ 2 postgres postgres  4096 Nov 28 19:21 pg_xact
-rw------- 1 postgres postgres    88 Nov 28 19:21 postgresql.auto.conf
-rw------- 1 postgres postgres 28085 Nov 28 19:21 postgresql.conf
-rw------- 1 postgres postgres    36 Jan 29 20:18 postmaster.opts
-rw------- 1 postgres postgres    94 Jan 29 20:18 postmaster.pid


There are config files and directories, including a particular directory called "base":

root@24999bd8c9ef:/var/lib/postgresql/data# cd base/
root@24999bd8c9ef:/var/lib/postgresql/data/base# ls -l
total 32
drwx------ 2 postgres postgres  4096 Nov 28 19:21 1
drwx------ 2 postgres postgres  4096 Nov 28 19:21 13394
drwx------ 2 postgres postgres 12288 Jan 29 20:27 13395
drwx------ 2 postgres postgres 12288 Jan 29 20:36 16736


These directories are listed on the system catalog pg_database.

The numbers are OIDs for the available databases:

  oid  |  datname  | datdba | encoding | datcollate |  datctype  | datistemplate | datallowconn | datconnlimit | datlastsysoid | datfrozenxid | datminmxid | dattablespace |               datacl                
-------+-----------+--------+----------+------------+------------+---------------+--------------+--------------+---------------+--------------+------------+---------------+-------------------------------------
     1 | template1 |     10 |        6 | en_US.utf8 | en_US.utf8 | t             | t            |           -1 |         13394 |          479 |          1 |          1663 | {=c/postgres,postgres=CTc/postgres}
 13394 | template0 |     10 |        6 | en_US.utf8 | en_US.utf8 | t             | f            |           -1 |         13394 |          479 |          1 |          1663 | {=c/postgres,postgres=CTc/postgres}
 13395 | postgres  |     10 |        6 | en_US.utf8 | en_US.utf8 | f             | t            |           -1 |         13394 |          479 |          1 |          1663 | 
 16736 | instagram |     10 |        6 | en_US.utf8 | en_US.utf8 | f             | t            |           -1 |         13394 |          479 |          1 |          1663 | 
(4 rows)


Let's enter on the directory that corresponds to the postgres database:

root@24999bd8c9ef:/var/lib/postgresql/data/base# cd 16736/
root@24999bd8c9ef:/var/lib/postgresql/data/base/16736# ls
112	   16739_vm   16871_fsm  2607_vm   2656  2704	   3351      3601      4160
113	   16746      16871_vm	 2608	   2657  2753	   3379      3601_fsm  4161
1247	   16748      16875	 2608_fsm  2658  2753_fsm  3380      3601_vm   4162
1247_fsm   16749      16877	 2608_vm   2659  2753_vm   3381      3602      4163
1247_vm    16751      16889	 2609	   2660  2754	   3394      3602_fsm  4164
1249	   16753      16891	 2609_fsm  2661  2755	   3394_fsm  3602_vm   4165
1249_fsm   16753_fsm  16891_fsm  2609_vm   2662  2756	   3394_vm   3603      4166
1249_vm    16753_vm   16891_vm	 2610	   2663  2757	   3395      3603_fsm  4167
1255	   16761      16896	 2610_fsm  2664  2830	   3429      3603_vm   4168
1255_fsm   16768      16898	 2610_vm   2665  2831	   3430      3604      4169
1255_vm    16770      174	 2611	   2666  2832	   3431      3605      4170
1259	   16770_fsm  175	 2612	   2667  2833	   3433      3606      4171
1259_fsm   16770_vm   2187	 2612_fsm  2668  2834	   3439      3607      4172
1259_vm    16776      2224	 2612_vm   2669  2835	   3440      3608      4173
13245	   16788      2328	 2613	   2670  2836	   3455      3609      4174
13245_fsm  16790      2336	 2615	   2673  2837	   3456      3712      5002
13245_vm   16790_fsm  2337	 2615_fsm  2674  2838	   3456_fsm  3764      548
13247	   16790_vm   2579	 2615_vm   2675  2838_fsm  3456_vm   3764_fsm  549
13249	   16796      2600	 2616	   2678  2838_vm   3466      3764_vm   6102
13250	   16798      2600_fsm	 2616_fsm  2679  2839	   3467      3766      6104
13250_fsm  16815      2600_vm	 2616_vm   2680  2840	   3468      3767      6106
13250_vm   16817      2601	 2617	   2681  2840_fsm  3501      3997      6110
13252	   16817_fsm  2601_fsm	 2617_fsm  2682  2840_vm   3502      4143      6111
13254	   16817_vm   2601_vm	 2617_vm   2683  2841	   3503      4144      6112
13255	   16823      2602	 2618	   2684  2995	   3534      4145      6113
13255_fsm  16825      2602_fsm	 2618_fsm  2685  2996	   3541      4146      6117
13255_vm   16837      2602_vm	 2618_vm   2686  3079	   3541_fsm  4147      826
13257	   16839      2603	 2619	   2687  3079_fsm  3541_vm   4148      827
13259	   16839_fsm  2603_fsm	 2619_fsm  2688  3079_vm   3542      4149      828
13260	   16839_vm   2603_vm	 2619_vm   2689  3080	   3574      4150      pg_filenode.map
13260_fsm  16844      2604	 2620	   2690  3081	   3575      4151      pg_internal.init
13260_vm   16846      2605	 2620_fsm  2691  3085	   3576      4152      PG_VERSION
13262	   16858      2605_fsm	 2620_vm   2692  3118	   3596      4153
13264	   16860      2605_vm	 2650	   2693  3119	   3597      4154
1417	   16860_fsm  2606	 2651	   2696  3164	   3598      4155
1418	   16865      2606_fsm	 2652	   2699  3256	   3599      4156
16737	   16867      2606_vm	 2653	   2701  3257	   3600      4157
16739	   16869      2607	 2654	   2702  3258	   3600_fsm  4158
16739_fsm  16871      2607_fsm	 2655	   2703  3350	   3600_vm   4159


There are a lot of files and all these numbers are (again) OIDs listed in another system catalog called pg_class. The files that have just a number on its name, are the pure tables inside the postgres database (16736).

For example, from these files, which one could be the one that is the table pg_user? Let's find out:

postgres=# SELECT oid, relname FROM pg_class WHERE relname = 'pg_user';
 12098 | pg_user


Let's inspect this table:

postgres=# \d pg_user;
 usename      | name                     |           |          | 
 usesysid     | oid                      |           |          | 
 usecreatedb  | boolean                  |           |          | 
 usesuper     | boolean                  |           |          | 
 userepl      | boolean                  |           |          | 
 usebypassrls | boolean                  |           |          | 
 passwd       | text                     |           |          | 
 valuntil     | timestamp with time zone |           |          | 
 useconfig    | text[]                   | C         |          | 

postgres=# SELECT * FROM pg_user;
 postgres|10  | t      | t      | t      | t         | ******** |          |


Indeed, is the table that holds user data from Postgres. I don't think I'm going to use this knowledge that much, to be honest. But at least, from now and on, I can have an idea of where all Postgres data is stored and how Postgres catalogs the data for its internal management. One more lesson learned :).

A reminder about SSH key pair access

I remember doing this (setting up SSH key pair access) like a ninja, without ServerFault or anything else. But these last years as Software Developer, have rusted the SysAdmin sword, let's say. I was getting crazy here, trying to understand what I was missing, and of course, it gotta be something silly. It's always something silly, and indeed it was. So, here's the first note of 2022, with high hopes on having better notes on this diary, discussing anything more interesting.


I generated my keypair...



I defined PubkeyAuthentication on the sshd daemon of the remote server...



But the access still fails...


That was really bugging me. It can't be Netfilter/IPTABLES, for the connection is established and under negotation. It can't be the user either, for my user exists on the remote server, so I don't need to pass the user while defining the remote IP address, and the PubkeyAuthentication is enabled.

But wait: did I added the pubkey of my user on the authorized_keys file of my user on the remote machine? (...)


And NOW, I can access the remote server..



Observe that the prompt has changed, now informing that a passphrase should be passed for the secret key. Without the authorized_keys defined on the remote server, the authentication was being negotiated via PasswordAuthentication option as yes, being a fallback authentication, which you should disable on your ssh server, for you don't want ssh access without recognized keys (protected by passwords, please).

Without that option, probably sshd daemon would complain about lack of authorized_keys file for my user.

May this note stay here as reminder, for who knows what the future holds...

Mastodon