Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jun 8, 2025. It is now read-only.

Commit d918a64

Browse files
committed
Initial commit
0 parents  commit d918a64

File tree

13 files changed

+356
-0
lines changed

13 files changed

+356
-0
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ACME_EMAIL=
2+
POSTGRES_DOMAIN=

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.env
2+
postgres_data/

LICENSE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# The MIT License (MIT)
2+
3+
Copyright © `2024` `Chandan <[email protected]>`
4+
5+
Permission is hereby granted, free of charge, to any person
6+
obtaining a copy of this software and associated documentation
7+
files (the “Software”), to deal in the Software without
8+
restriction, including without limitation the rights to use,
9+
copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following
12+
conditions:
13+
14+
The above copyright notice and this permission notice shall be
15+
included in all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
18+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24+
OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# PostgreSQL Setup
2+
3+
I'm making my Postgres setup open source. This is what I use for self-hosting PostgreSQL myself.
4+
5+
It comes with a lot of room for customization and notably:
6+
7+
- Automatic SSL certificate generation/renewals with Traefik as a reverse proxy
8+
- PgBouncer as a connection pooler that uses auth query instead of userlist.txt
9+
- Automatic incremental backups to S3-compatible storage
10+
- Script to create databases and users with granular, scoped permissions within the single cluster
11+
12+
I would like to hear your thoughts, suggestions, and recommendations regarding this setup, and if anything can be improved.
13+
14+
I want to keep this setup small and without bloatware. It can be used as is, but I expect it to be customized according to your needs.
15+
Current config files expect 4 GB of RAM. If you have less or more, change the settings in the postgres.conf file and the Docker Compose service memory limits.
16+
17+
Currently, tools to view Postgres are not added as part of the setup.
18+
You can access the database through psql or tools like [pgAdmin 4](https://github.com/pgadmin-org/pgadmin4), [Beekeeper Studio](https://github.com/beekeeper-studio/beekeeper-studio), or [DBeaver](https://github.com/dbeaver/dbeaver).
19+
20+
## Usage
21+
22+
**Assumptions:** You have a Linux server used solely for hosting PostgreSQL with Docker.
23+
24+
### Steps
25+
26+
1. `git clone https://github.com/realchandan/postgres_setup.git`
27+
28+
2. `cd postgres_setup`
29+
30+
3. Copy environment files:
31+
32+
```bash
33+
cp .env.example .env
34+
cp ./config/postgres.env.example ./config/postgres.env
35+
cp ./config/pgbackup.env.example ./config/pgbackup.env
36+
```
37+
38+
Then, modify the environment files with the appropriate values.
39+
40+
Here's an explanation of environment variables:
41+
42+
> **.env**
43+
> | Variable Name | Explanation |
44+
> | --------------- | ---------------------------------------------------------------------------------- |
45+
> | ACME_EMAIL | The email to be used for ACME/LetsEncrypt |
46+
> | POSTGRES_DOMAIN | The domain where you want to host the database over SSL, e.g. postgres.example.com |
47+
48+
> **./config/postgres.env**
49+
> | Variable Name | Explanation |
50+
> | ----------------- | ------------------------------------------------------------------------------------------------- |
51+
> | POSTGRES_DB | The name of the default database. Ideally, you shouldn’t change it (by default, it's postgres). |
52+
> | POSTGRES_PASSWORD | The password of the PostgreSQL superuser (set a very strong one here). |
53+
> | POSTGRES_USER | The username of the superuser (ideally, don’t change it). |
54+
55+
> **./config/pgbackup.env**
56+
> Refer [here](https://github.com/realchandan/pgbackup?tab=readme-ov-file#usage). If you don't want backups, comment out the pgbackup service in the Docker Compose file.
57+
58+
4. Point your domain A/AAAA records to the server’s public IPv4/IPv6 addresses.
59+
60+
5. Allow ports 443 and 5432 (TCP) through the firewall. Depending on your firewall, steps may vary. Port 443 is needed for Let’s Encrypt TLS challenge, and 5432 is used by PgBouncer.
61+
62+
6. Add public permissions to the `./config/pg` folder with `chmod -R 777 ./config/pg`.
63+
64+
7. Run `docker compose --env-file .env up -d` to bring up all the services.
65+
66+
8. Create a new database using:
67+
68+
```bash
69+
docker exec -it postgres bash -c "/docker-entrypoint-initdb.d/create-user.sh awesome_db passw0rd"
70+
```
71+
72+
This command creates a user called `awesome_db_user` with the password `passw0rd` and gives them access to a database named `awesome_db`.
73+
74+
9. Enjoy and star this repo! (Helps me flex!)

config/pg/conf/pg_hba.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
local all all trust
2+
host all pgbouncer 10.10.10.105/32 trust
3+
host all pgbouncer fd00:bbbb:cccc:dddd::105/128 trust
4+
host all all all md5
5+
host replication postgres all md5

config/pg/conf/postgresql.conf

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
listen_addresses = '*'
2+
max_connections = 30
3+
password_encryption = md5
4+
port = 5432
5+
6+
# We got 4 GB RAM for postgres
7+
autovacuum_max_workers = 3
8+
effective_cache_size = 2GB # between 50% and 75% of the memory
9+
effective_io_concurrency = 180 # for NVME SSD
10+
log_min_duration_statement = 1000ms
11+
maintenance_work_mem = 64MB
12+
max_prepared_transactions = 30 # same as max_connections
13+
random_page_cost =1
14+
seq_page_cost = 1
15+
shared_buffers = 1GB # 25% of the memory
16+
work_mem = 5MB
17+
18+
hba_file = '/etc/conf/pg_hba.conf'
19+
20+
summarize_wal=on
21+
checkpoint_timeout = 5min
22+
max_wal_size = 1GB
23+
log_checkpoints = 'on'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
set -e
3+
4+
password=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 64)
5+
6+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE USER pgbouncer WITH ENCRYPTED PASSWORD '$password';"
7+
8+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "
9+
CREATE
10+
OR REPLACE FUNCTION user_search (uname TEXT) RETURNS TABLE (usename name, passwd text) as \$\$
11+
SELECT
12+
usename,
13+
passwd
14+
FROM
15+
pg_shadow
16+
WHERE
17+
usename = uname;
18+
\$\$ LANGUAGE sql SECURITY DEFINER;
19+
"

config/pg/scripts/create-user.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
set -e
3+
4+
function create_database() {
5+
local database="$1"
6+
local password="$2"
7+
8+
local username="${database}_user"
9+
local role="${database}_role"
10+
11+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE ROLE $role NOLOGIN;"
12+
13+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE DATABASE $database OWNER $role;"
14+
15+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "REVOKE ALL ON SCHEMA public FROM PUBLIC;"
16+
17+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "REVOKE ALL ON DATABASE $database FROM PUBLIC;"
18+
19+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT CONNECT ON DATABASE $database TO $role;"
20+
21+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT ALL PRIVILEGES ON DATABASE $database TO $role;"
22+
23+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT ALL PRIVILEGES ON SCHEMA public TO $role;"
24+
25+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO $role;"
26+
27+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO $role;"
28+
29+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO $role;"
30+
31+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO $role;"
32+
33+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO $role;"
34+
35+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO $role;"
36+
37+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE USER $username WITH ENCRYPTED PASSWORD '$password';"
38+
39+
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "GRANT $role to $username;"
40+
}
41+
42+
if [[ -z "$1" || -z "$2" ]]; then
43+
echo "Usage: $0 <database_name> <password>"
44+
exit 0
45+
fi
46+
47+
create_database "$1" "$2"

config/pgbackup.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
DB_HOST=postgres
2+
DB_PORT=5432
3+
REMOTE_FOLDER=my_db_backups
4+
S3_ACCESS_KEY=
5+
S3_BUCKET_NAME=
6+
S3_ENDPOINT=
7+
S3_REGION=
8+
S3_SECRET_KEY=
9+
SCHEDULE=*/5 * * * *

config/pgbouncer.ini

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[databases]
2+
*=host=postgres port=5432
3+
4+
[pgbouncer]
5+
listen_addr = *
6+
listen_port = 6432
7+
8+
; default_pool_size = max_connections / (total number of databases)
9+
auth_type = md5
10+
default_pool_size = 15
11+
max_client_conn = 1500
12+
; pool_mode = session
13+
pool_mode = transaction
14+
server_idle_timeout = 600
15+
server_lifetime = 3600
16+
auth_user=pgbouncer
17+
auth_query = SELECT usename, passwd FROM user_search($1)
18+
auth_dbname=postgres
19+
20+
; https://github.com/pgbouncer/pgbouncer/releases/tag/pgbouncer_1_21_0
21+
max_prepared_statements = 100

0 commit comments

Comments
 (0)