From a7b9134047305046524a3e45e96ec346eb2b3f0c Mon Sep 17 00:00:00 2001 From: ahmadk953 <103906421+ahmadk953@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:55:52 -0400 Subject: [PATCH] chore: switched to redis and cleanup --- .github/workflows/docker.yml | 11 +-- .env.example => docker/.env.example | 1 - .../docker-compose.yml | 79 ++++++++----------- docker/pgbouncer/README.md | 16 ++-- docker/redis.conf | 7 ++ drizzle.config.ts | 4 +- generate-certs.sh | 66 ++++++---------- src/db/db.ts | 4 +- src/db/redis.ts | 6 +- 9 files changed, 84 insertions(+), 110 deletions(-) rename .env.example => docker/.env.example (73%) rename docker-compose.yml => docker/docker-compose.yml (54%) create mode 100644 docker/redis.conf diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index dcfb252..87a14f0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,12 +2,12 @@ name: Docker Build and Push on: schedule: - - cron: '43 0 * * *' + - cron: "43 0 * * *" push: - branches: [ "main" ] - tags: [ 'v*.*.*' ] + branches: ["main"] + tags: ["v*.*.*"] pull_request: - branches: [ "main" ] + branches: ["main"] env: REGISTRY: ghcr.io @@ -56,7 +56,8 @@ jobs: cache-from: type=gha,scope=pgbouncer cache-to: type=gha,scope=pgbouncer,mode=max - - name: Sign the published Docker image for pgbouncer + - name: Sign the published Docker image for PgBouncer + if: ${{ github.event_name != 'pull_request' }} env: TAGS: ${{ steps.meta.outputs.tags }} DIGEST: ${{ steps.build-and-push.outputs.digest }} diff --git a/.env.example b/docker/.env.example similarity index 73% rename from .env.example rename to docker/.env.example index 558a922..5298d68 100644 --- a/.env.example +++ b/docker/.env.example @@ -1,4 +1,3 @@ POSTGRES_USER=your_postgres_user POSTGRES_PASSWORD=your_postgres_password POSTGRES_DB=your_database_name -VALKEY_PASSWORD=your_valkey_password diff --git a/docker-compose.yml b/docker/docker-compose.yml similarity index 54% rename from docker-compose.yml rename to docker/docker-compose.yml index 5edbaa8..885ce32 100644 --- a/docker-compose.yml +++ b/docker/docker-compose.yml @@ -2,20 +2,20 @@ services: postgres: image: postgres:17-alpine container_name: postgres - restart: always + restart: unless-stopped + volumes: + - ../certs/psql-cert.pem:/var/lib/postgresql/cert.pem:ro + - ../certs/psql-key.pem:/var/lib/postgresql/key.pem:ro + - postgres_data:/var/lib/postgresql/data environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} - volumes: - - ./certs/psql-server.crt:/var/lib/postgresql/server.crt:ro - - ./certs/psql-server.key:/var/lib/postgresql/server.key:ro - - postgres_data:/var/lib/postgresql/data command: > postgres -c ssl=on - -c ssl_cert_file=/var/lib/postgresql/server.crt - -c ssl_key_file=/var/lib/postgresql/server.key + -c ssl_cert_file=/var/lib/postgresql/cert.pem + -c ssl_key_file=/var/lib/postgresql/key.pem healthcheck: test: [ @@ -28,49 +28,44 @@ services: networks: - services - valkey: - image: valkey/valkey:8-alpine - container_name: valkey - restart: always + redis: + image: redis:8-alpine + container_name: redis + restart: unless-stopped ports: - '6379:6379' volumes: - - ./certs/cache-server.crt:/certs/server.crt:ro - - ./certs/cache-server.key:/certs/server.key:ro - - ./certs/cache-ca.crt:/certs/ca.crt:ro - - valkey_data:/data + - ../certs/cache-cert.pem:/usr/local/etc/redis/cert.pem:ro + - ../certs/cache-key.pem:/usr/local/etc/redis/key.pem:ro + - ../certs/rootCA.pem:/usr/local/etc/redis/ca.pem:ro + - ./redis.conf:/usr/local/etc/redis/redis.conf:ro command: > - valkey-server - --requirepass ${VALKEY_PASSWORD} - --tls-port 6379 - --port 0 - --tls-cert-file /certs/server.crt - --tls-key-file /certs/server.key - --tls-ca-cert-file /certs/ca.crt + redis-server /usr/local/etc/redis/redis.conf healthcheck: - test: [ + test: + [ 'CMD-SHELL', - 'valkey-cli - -a - ${VALKEY_PASSWORD} - --tls - --cacert - /certs/ca.crt - --cert - /certs/server.crt - --key - /certs/server.key - ping', + 'redis-cli --tls --cacert /usr/local/etc/redis/ca.pem ping | grep PONG', ] interval: 10s timeout: 5s retries: 5 + start_period: 10s networks: - services pgbouncer: image: ghcr.io/ahmadk953/poixpixel-discord-bot-pgbouncer container_name: pgbouncer + restart: unless-stopped + depends_on: + - postgres + ports: + - '5432:5432' + volumes: + - ../certs/pgbouncer-cert.pem:/certs/cert.pem:ro + - ../certs/pgbouncer-key.pem:/certs/key.pem:ro + - ../certs/rootCA.pem:/certs/ca.pem:ro environment: DB_USER: ${POSTGRES_USER} DB_PASSWORD: ${POSTGRES_PASSWORD} @@ -80,18 +75,11 @@ services: POOL_MODE: transaction ADMIN_USERS: ${POSTGRES_USER} CLIENT_TLS_SSLMODE: require - CLIENT_TLS_CERT_FILE: /certs/server.crt - CLIENT_TLS_KEY_FILE: /certs/server.key - CLIENT_TLS_CA_FILE: /certs/ca.crt + CLIENT_TLS_CERT_FILE: /certs/cert.pem + CLIENT_TLS_KEY_FILE: /certs/key.pem + CLIENT_TLS_CA_FILE: /certs/ca.pem SERVER_TLS_SSLMODE: require - ports: - - '5432:5432' - depends_on: - - postgres - volumes: - - ./certs/pgbouncer-server.crt:/certs/server.crt:ro - - ./certs/pgbouncer-server.key:/certs/server.key:ro - - ./certs/pgbouncer-ca.crt:/certs/ca.crt:ro + SERVER_TLS_CA_FILE: /certs/ca.pem healthcheck: test: [ @@ -103,7 +91,6 @@ services: volumes: postgres_data: - valkey_data: networks: services: diff --git a/docker/pgbouncer/README.md b/docker/pgbouncer/README.md index 027c5bf..5e6ab87 100644 --- a/docker/pgbouncer/README.md +++ b/docker/pgbouncer/README.md @@ -1,19 +1,19 @@ -# Pgbouncer +# PgBouncer -Pgbouncer is a lightweight connection pooler for PostgreSQL that helps optimize database connections by reusing established sessions. +PgBouncer is a lightweight connection pooler for PostgreSQL that helps optimize database connections by reusing established sessions. ## Overview -This directory contains all the necessary files to build and run Pgbouncer as part of the Poixpixel Discord Bot project. It is based on Alpine Linux and includes support for c-ares. +This directory contains all the necessary files to build and run PgBouncer as part of the Poixpixel Discord Bot project. It is based on Alpine Linux and includes support for c-ares. ## Contents -- **Dockerfile**: Builds the Pgbouncer image with c-ares support. -- **entrypoint.sh**: Generates and configures the Pgbouncer configuration file at container startup. +- **Dockerfile**: Builds the PgBouncer image with c-ares support. +- **entrypoint.sh**: Generates and configures the PgBouncer configuration file at container startup. ## Building the Docker Image -To build the Pgbouncer Docker image, run: +To build the PgBouncer Docker image, run: ```sh docker build -t my-pgbouncer ./docker/pgbouncer @@ -58,7 +58,7 @@ docker run --rm \ - **Dockerfile**: Modify build arguments or dependencies as needed. - **entrypoint.sh**: Adjust how the configuration file is generated and updated. -- **Environment Variables**: Almost all settings found in the `pgbouncer.ini` file can be set as environment variables, except for a few system-specific configuration options. For an example, check out [the example Docker compose file](../../docker-compose.yml). For all configuration options, check the [pgbouncer configuration documentation](https://www.pgbouncer.org/config.html). +- **Environment Variables**: Almost all settings found in the `pgbouncer.ini` file can be set as environment variables, except for a few system-specific configuration options. For an example, check out [the example Docker compose file](../../docker-compose.yml). For all configuration options, check the [PgBouncer configuration documentation](https://www.pgbouncer.org/config.html). - **Configuration File**: You can specify your own `pgbouncer.ini` file by mounting it as a volume like so: ```sh docker run --rm \ @@ -66,7 +66,7 @@ docker run --rm \ -e DB_PASSWORD=pass \ -e DB_HOST=postgres-host \ -e DB_NAME=database \ - -v pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro \ + -v PgBouncer.ini:/etc/PgBouncer/PgBouncer.ini:ro \ -p 5432:5432 \ ghcr.io/ahmadk953/poixpixel-discord-bot-pgbouncer ``` diff --git a/docker/redis.conf b/docker/redis.conf new file mode 100644 index 0000000..98416d0 --- /dev/null +++ b/docker/redis.conf @@ -0,0 +1,7 @@ +# redis.conf +port 0 +tls-port 6379 +tls-cert-file /usr/local/etc/redis/cert.pem +tls-key-file /usr/local/etc/redis/key.pem +tls-ca-cert-file /usr/local/etc/redis/ca.pem +tls-auth-clients no diff --git a/drizzle.config.ts b/drizzle.config.ts index fc258df..3baff27 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -14,9 +14,7 @@ export default defineConfig({ ssl: (() => { try { return { - ca: fs.readFileSync(path.resolve('./certs/pgbouncer-ca.crt')), - key: fs.readFileSync(path.resolve('./certs/pgbouncer-client.key')), - cert: fs.readFileSync(path.resolve('./certs/pgbouncer-server.crt')), + ca: fs.readFileSync(path.resolve('./certs/rootCA.pem')), }; } catch (error) { console.warn( diff --git a/generate-certs.sh b/generate-certs.sh index 32ecd19..7f3f28e 100755 --- a/generate-certs.sh +++ b/generate-certs.sh @@ -1,53 +1,37 @@ #!/bin/bash -# Get the Effective User ID -_uid="$(id -u)" +# Get the Group ID _gid="$(id -g)" -# Create the certificates directory -mkdir -p certs +# Remove everything in the certs directory except for rootCA.pem and rootCA-key.pem +if [ -d certs ]; then + find certs -mindepth 1 ! -name 'rootCA.pem' ! -name 'rootCA-key.pem' -exec rm -rf {} + +else + mkdir certs +fi -# Generate PostgreSQL Certificates -openssl req -new -x509 -days 365 -nodes \ - -out certs/psql-server.crt \ - -keyout certs/psql-server.key \ - -subj "/CN=localhost" +# Set CAROOT Environment Variable +CAROOT="$(pwd)/certs" +export CAROOT -# Generate Valkey Certificates -openssl req -new -x509 -days 365 -nodes \ - -out certs/cache-server.crt \ - -keyout certs/cache-server.key \ - -subj "/CN=localhost" +# Generate postgres Certificates +mkcert -key-file certs/psql-key.pem -cert-file certs/psql-cert.pem localhost 127.0.0.1 ::1 -# Generate pgbouncer Certificates -openssl req -new -x509 -days 365 -nodes \ - -out certs/pgbouncer-server.crt \ - -keyout certs/pgbouncer-server.key \ - -subj "/CN=localhost" +# Generate Cache Certificates +mkcert -key-file certs/cache-key.pem -cert-file certs/cache-cert.pem localhost 127.0.0.1 ::1 -# Get CA Certificates -cp certs/psql-server.crt certs/psql-ca.crt -cp certs/cache-server.crt certs/cache-ca.crt -cp certs/pgbouncer-server.crt certs/pgbouncer-ca.crt +# Generate PgBouncer Certificates +mkcert -key-file certs/pgbouncer-key.pem -cert-file certs/pgbouncer-cert.pem localhost 127.0.0.1 ::1 + +# Install the Root CA +mkcert -install # Setup Permissions -chmod 0600 certs/psql-server.key -chmod 0600 certs/cache-server.key -chmod 0600 certs/pgbouncer-server.key +chmod 0600 certs/psql-key.pem +chmod 0640 certs/pgbouncer-key.pem +chmod 0640 certs/cache-key.pem # Assign Ownership -sudo chown 70:70 certs/psql-*.* -sudo chown 999:1000 certs/cache-*.* -sudo chown 1100:1100 certs/pgbouncer-*.* - -# Get Client Keys -sudo cp certs/pgbouncer-server.key certs/pgbouncer-client.key -sudo cp certs/cache-server.key certs/cache-client.key - -# Change Client Key Ownership -sudo chown "${_uid}:${_gid}" certs/pgbouncer-client.key -sudo chown "${_uid}:${_gid}" certs/cache-client.key - -# Change Client Key Permissions -sudo chmod 0600 certs/pgbouncer-client.key -sudo chmod 0600 certs/cache-client.key +sudo chown 70:70 certs/psql-key.pem +sudo chown 1100:"${_gid}" certs/pgbouncer-key.pem +sudo chown 999:"${_gid}" certs/cache-key.pem diff --git a/src/db/db.ts b/src/db/db.ts index d4a0207..498662e 100644 --- a/src/db/db.ts +++ b/src/db/db.ts @@ -103,9 +103,7 @@ export async function initializeDatabaseConnection(): Promise { ssl: (() => { try { return { - ca: fs.readFileSync(path.resolve('./certs/pgbouncer-ca.crt')), - key: fs.readFileSync(path.resolve('./certs/pgbouncer-client.key')), - cert: fs.readFileSync(path.resolve('./certs/pgbouncer-server.crt')), + ca: fs.readFileSync(path.resolve('./certs/rootCA.pem')), }; } catch (error) { console.warn( diff --git a/src/db/redis.ts b/src/db/redis.ts index 8348190..23fab78 100644 --- a/src/db/redis.ts +++ b/src/db/redis.ts @@ -96,9 +96,9 @@ async function initializeRedisConnection() { tls: (() => { try { return { - ca: fs.readFileSync(path.resolve('./certs/cache-ca.crt')), - key: fs.readFileSync(path.resolve('./certs/cache-client.key')), - cert: fs.readFileSync(path.resolve('./certs/cache-server.crt')), + ca: fs.readFileSync(path.resolve('./certs/rootCA.pem')), + key: fs.readFileSync(path.resolve('./certs/cache-key.pem')), + cert: fs.readFileSync(path.resolve('./certs/cache-cert.pem')), }; } catch (error) { console.warn(