first commit

This commit is contained in:
Tour
2025-12-09 11:12:08 +01:00
commit c2dadf6148
7 changed files with 382 additions and 0 deletions

2
.env Normal file
View File

@@ -0,0 +1,2 @@
POSTGRES_PASSWORD=heel-goed-wachtwoord
PGADMIN_PASSWORD=heel-goed-wachtwoord

188
README.md Normal file
View File

@@ -0,0 +1,188 @@
# PostgreSQL Infrastructure Setup
This folder contains the Docker-based PostgreSQL infrastructure running on the internal server (`192.168.1.159`).
It provides a production-ready PostgreSQL instance, optional pgAdmin UI, and a simple automated backup mechanism.
The setup is designed to be:
- persistent (volume-backed database storage)
- LAN-accessible (port `5432`)
- isolated from Traefik (database does not use reverse proxy)
- easy to operate (`docker compose up -d`)
- safe (controlled permissions and separate admin password)
---
## Directory Structure
```
infra/postgres/
docker-compose.yml → main PostgreSQL service
.env → database credentials (not committed)
data/ → PostgreSQL data directory (automatically created)
backup/ → SQL dumps created by backup containers
pgadmin/ → optional pgAdmin admin UI exposed via Traefik
backup/ → backup runner files (optional)
```
`data/` and `backup/` are *not* included in version control.
They are created on the server when the stack is deployed.
---
## Prerequisites
Run on the target server (`Tour`, 192.168.1.159):
- Docker
- Docker Compose v2
- Access to the `traefik-net` Docker network (only if pgAdmin is used)
---
## Environment File
Create `.env` inside this directory:
```
POSTGRES_PASSWORD=<strong_password_here>
PGADMIN_PASSWORD=<admin_ui_password_if_pgadmin_enabled>
```
Recommended permissions:
```bash
chmod 600 .env
```
---
## Initial Setup
Run these commands on the server:
```bash
cd ~/infra/postgres
mkdir -p data backup
```
Ensure correct directory ownership:
```bash
sudo chown -R $USER:$USER data backup
```
---
## Starting the Stack
Start PostgreSQL:
```bash
docker compose up -d
```
Check status:
```bash
docker ps
```
Expected:
```
postgres-db Up (healthy) 0.0.0.0:5432->5432/tcp
```
---
## Connecting to PostgreSQL
Connection string:
```
postgresql://auction:<password>@192.168.1.159:5432/auctiondb
```
Test:
```bash
psql "postgresql://auction:<password>@192.168.1.159:5432/auctiondb"
```
---
## pgAdmin (Optional)
If pgAdmin is deployed via Traefik, access it at:
```
https://pgadmin.appmodel.nl/
```
Use `postgres-db` as the hostname inside pgAdmin.
---
## Backup Strategy
SQL dumps are stored in:
```
infra/postgres/backup/
```
Daily backups produce files like:
```
backup_YYYY-MM-DD_HH-MM.sql
```
Restore example:
```bash
psql -U auction -d auctiondb < backup_file.sql
```
---
## Stopping or Updating
Stop:
```bash
docker compose down
```
Update:
```bash
docker compose pull
docker compose up -d
```
---
## Disaster Recovery
To rebuild the database:
```bash
docker compose down
mv data data_old_$(date +%s)
docker compose up -d
psql -U auction -d auctiondb < backup/latest.sql
```
---
## Next Steps
Possible extensions:
- Flyway migration container
- Auto schema sync for Python + Quarkus
- Monitoring exporters
- Retention policy for backups
- Migration from SQLite to PostgreSQL

14
backup/backup.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
DATE=$(date +"%Y-%m-%d_%H-%M")
FILENAME="backup_$DATE.sql"
echo "Dumping database to $FILENAME"
/usr/bin/pg_dump \
-h postgres-db \
-U auction \
auctiondb \
> /backup/$FILENAME
# optional: keep only 14 days
find /backup -type f -mtime +14 -delete

19
backup/docker-compose.yml Normal file
View File

@@ -0,0 +1,19 @@
version: "3.9"
services:
pgbackup:
image: postgres:16
container_name: postgres-backup
restart: unless-stopped
environment:
PGPASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ../postgres/backup:/backup
- ./backup.sh:/backup.sh
entrypoint: [ "bash", "-c", "echo 'Starting backup scheduler'; while true; do /backup.sh; sleep 86400; done" ]
networks:
- default

25
docker-compose.yml Normal file
View File

@@ -0,0 +1,25 @@
version: "3.9"
services:
postgres:
image: postgres:16
container_name: postgres-db
restart: unless-stopped
environment:
POSTGRES_DB: auctiondb
POSTGRES_USER: auction
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432" # LAN only, safe inside 192.168.1.x
volumes:
- ./data:/var/lib/postgresql/data
- ./backup:/backup
healthcheck:
test: ["CMD-SHELL", "pg_isready -U auction -d auctiondb"]
interval: 5s
timeout: 2s
retries: 10

105
install_postgres.sh Normal file
View File

@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -e
echo "=== PostgreSQL Infra Installer ==="
# Detect working directory (should be infra/postgres)
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
echo "Using infra directory: $SCRIPT_DIR"
# -----------------------------------------------------------
# 1. Ensure directories exist
# -----------------------------------------------------------
echo "→ Creating required directories..."
mkdir -p data
mkdir -p backup
# -----------------------------------------------------------
# 2. Permissions
# -----------------------------------------------------------
echo "→ Setting directory permissions..."
sudo chown -R "$USER:$USER" data backup
# -----------------------------------------------------------
# 3. Create .env if missing
# -----------------------------------------------------------
if [ ! -f ".env" ]; then
echo "→ Creating .env file..."
cat <<EOF > .env
POSTGRES_PASSWORD=$(openssl rand -hex 16)
PGADMIN_PASSWORD=$(openssl rand -hex 16)
EOF
echo "Generated random passwords in .env"
else
echo "→ .env file already exists; skipping creation."
fi
echo "Current .env:"
cat .env
echo ""
# -----------------------------------------------------------
# 4. Verify Docker & Docker Compose
# -----------------------------------------------------------
echo "→ Checking Docker installation..."
if ! command -v docker &> /dev/null; then
echo "ERROR: Docker is not installed."
exit 1
fi
echo "→ Checking Docker Compose..."
if ! docker compose version &> /dev/null; then
echo "ERROR: Docker Compose V2 is not installed."
exit 1
fi
# -----------------------------------------------------------
# 5. Start PostgreSQL stack
# -----------------------------------------------------------
echo "→ Starting PostgreSQL Docker stack..."
docker compose up -d
echo "→ Waiting for PostgreSQL to report healthy status..."
sleep 3
docker ps --filter "name=postgres-db"
# -----------------------------------------------------------
# 6. Setup backup container
# -----------------------------------------------------------
echo "→ Checking backup service..."
if [ -d "backup" ] && [ -f "backup/docker-compose.yml" ]; then
echo "→ Starting backup runner..."
cd backup
docker compose up -d
cd "$SCRIPT_DIR"
else
echo "⚠ Backup runner folder missing. Expected: ./backup/docker-compose.yml"
echo "Skipping backup setup."
fi
# -----------------------------------------------------------
# 7. Summary
# -----------------------------------------------------------
echo ""
echo "===================================================="
echo " PostgreSQL Infra Installed Successfully"
echo "===================================================="
echo "Host machine: $(hostname)"
echo "Database port: 5432 (LAN accessible)"
echo "Data dir: $SCRIPT_DIR/data"
echo "Backups: $SCRIPT_DIR/backup/"
echo ""
echo "Connection string:"
echo " postgresql://auction:<POSTGRES_PASSWORD>@192.168.1.159:5432/auctiondb"
echo ""
echo "Start/Stop commands:"
echo " docker compose up -d"
echo " docker compose down"
echo ""
echo "If pgAdmin is enabled, visit:"
echo " https://pgadmin.appmodel.nl/"
echo ""
echo "Done."

View File

@@ -0,0 +1,29 @@
version: "3.9"
services:
pgadmin:
image: dpage/pgadmin4:8
container_name: pgadmin
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@appmodel.nl
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
PGADMIN_CONFIG_SERVER_MODE: "True"
volumes:
- ./data:/var/lib/pgadmin
networks:
- traefik-net
- default
labels:
- "traefik.enable=true"
- "traefik.http.routers.pgadmin.rule=Host(`pgadmin.appmodel.nl`)"
- "traefik.http.routers.pgadmin.entrypoints=websecure"
- "traefik.http.routers.pgadmin.tls.certresolver=letsencrypt"
networks:
traefik-net:
external: true