commit 4e5a2e315a3f720781888fae9231d41ea7db7b9a Author: Rainer Hauser Date: Fri Aug 22 16:09:48 2025 +0200 initial diff --git a/.env b/.env new file mode 100644 index 0000000..56ac261 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +POSTGRES_USER=app +POSTGRES_PASSWORD=appsecret +POSTGRES_DB=messdb + +NODE_ENV=development +PORT=8080 +DATABASE_URL=postgres://app:appsecret@db:5432/messdb + +APACHE_HTTP_PORT=8088 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..040823d --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Node +node_modules/ +npm-debug.log + +# Docker +db-data/ +*.pid + +# System +.DS_Store +*.swp diff --git a/apache/Dockerfile b/apache/Dockerfile new file mode 100644 index 0000000..4bd1036 --- /dev/null +++ b/apache/Dockerfile @@ -0,0 +1,9 @@ +FROM httpd:2.4 +# Module aktivieren und vHost einbinden +RUN sed -i \ + -e 's/#LoadModule proxy_module/LoadModule proxy_module/' \ + -e 's/#LoadModule proxy_http_module/LoadModule proxy_http_module/' \ + -e 's/#LoadModule headers_module/LoadModule headers_module/' \ + conf/httpd.conf +COPY vhost.conf /usr/local/apache2/conf/extra/vhost.conf +RUN echo 'Include conf/extra/vhost.conf' >> /usr/local/apache2/conf/httpd.conf diff --git a/apache/vhost.conf b/apache/vhost.conf new file mode 100644 index 0000000..99a74be --- /dev/null +++ b/apache/vhost.conf @@ -0,0 +1,30 @@ +# Reverse-Proxy auf Node-API (Service-Name "api", Port 8080) + + ServerName localhost + + # Optionale statische Dateien + DocumentRoot "/usr/local/apache2/htdocs" + + Require all granted + Options -Indexes + + + # Proxy Einstellungen + ProxyPreserveHost On + ProxyPass /api/ http://api:8080/api/ + ProxyPassReverse /api/ http://api:8080/api/ + + # Health passthrough + ProxyPass /health http://api:8080/health + ProxyPassReverse /health http://api:8080/health + + # CORS/Headers bei Bedarf + Header always set X-Frame-Options "SAMEORIGIN" + Header always set X-Content-Type-Options "nosniff" + Header always set Referrer-Policy "strict-origin-when-cross-origin" + Header always set X-Forwarded-Proto "http" + RequestHeader set X-Forwarded-Proto "http" + + ErrorLog /proc/self/fd/2 + CustomLog /proc/self/fd/1 combined + diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 0000000..4386753 --- /dev/null +++ b/api/Dockerfile @@ -0,0 +1,15 @@ +FROM node:20-alpine +WORKDIR /app + +# Nur package.json kopieren +COPY package.json ./ + +# Statt npm ci: install ohne dev +RUN npm install --omit=dev + +# App-Code +COPY server.js ./ + +ENV PORT=8080 +EXPOSE 8080 +CMD ["node", "server.js"] diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000..71cf95d --- /dev/null +++ b/api/package.json @@ -0,0 +1,11 @@ +{ + "name": "messgeraet-api", + "version": "1.0.0", + "main": "server.js", + "type": "module", + "scripts": { "start": "node server.js" }, + "dependencies": { + "express": "^4.19.2", + "pg": "^8.11.5" + } +} diff --git a/api/server.js b/api/server.js new file mode 100644 index 0000000..c84e7a7 --- /dev/null +++ b/api/server.js @@ -0,0 +1,18 @@ +import express from "express"; +import pkg from "pg"; +const { Pool } = pkg; + +const app = express(); +app.use(express.json()); + +const pool = new Pool({ connectionString: process.env.DATABASE_URL }); + +app.get("/health", async (_req, res) => { + try { await pool.query("select 1"); res.json({ ok: true }); } + catch (e) { res.status(500).json({ ok: false, error: String(e) }); } +}); + +app.get("/api/hello", (_req, res) => res.json({ msg: "Hello from Node behind Apache" })); + +const port = process.env.PORT || 8080; +app.listen(port, () => console.log(`API on :${port}`)); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6500b5c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,65 @@ +# version: "3.9" + +services: + db: + image: postgres:16 + container_name: pg-db + restart: unless-stopped + env_file: .env + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - db-data:/var/lib/postgresql/data + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 5s + timeout: 3s + retries: 10 + + api: + build: + context: ./api + dockerfile: Dockerfile + container_name: node-api + restart: unless-stopped + env_file: .env + environment: + PORT: ${PORT} + DATABASE_URL: ${DATABASE_URL} + NODE_ENV: ${NODE_ENV} + expose: + - "8080" # nur im Compose-Netz + depends_on: + db: + condition: service_healthy + + web: + build: + context: ./apache + dockerfile: Dockerfile + container_name: apache-web + restart: unless-stopped + env_file: .env + ports: + - "${APACHE_HTTP_PORT}:80" # Host:8088 -> Apache:80 + depends_on: + - api + + pgadmin: + image: dpage/pgadmin4:8 + container_name: pg-admin + restart: unless-stopped + environment: + PGADMIN_DEFAULT_EMAIL: admin@example.com + PGADMIN_DEFAULT_PASSWORD: admin123 + ports: + - "5050:80" + depends_on: + - db + +volumes: + db-data: