Installatiescript met opslagkeuze, standaard /srv/server-up (v0.2.04 beta)
Nieuw: scripts/install.sh — installeert de stack in zeven zichtbare stappen
met drie vragen, standaard in /srv/server-up (aan te passen met
ROOSTERWIJS_DIR). Het script:
- controleert git, docker, de compose-plugin en of de daemon bereikbaar is;
- maakt de doelmap aan, of legt uit welk commando daarvoor nodig is als de
rechten ontbreken (roept zelf geen sudo aan);
- kloont of werkt de checkout bij;
- laat kiezen waar de gegevens komen (zie hieronder);
- genereert .env met een willekeurige DJANGO_SECRET_KEY en een sterk
databasewachtwoord, en zet hostnaam, CSRF-origin en DJANGO_SECURE op basis
van twee vragen; een bestaande .env wordt nooit zomaar overschreven;
- bouwt en start de containers;
- meldt of er een account is en biedt aan er een aan te maken.
Opslagkeuze bij de installatie:
- docker-compose.yml gebruikt nu ${DATA_DB}, ${DATA_MEDIA} en ${DATA_STATIC}.
Een naam = Docker-volume, een pad = gewone map naast de code.
- De standaardwaarden zijn de bestaande named volumes, dus installaties die
al draaien veranderen niet en er gaan geen gegevens verloren.
- Kies je voor mappen, dan komt alles onder /srv/server-up/data/.
Verder:
- .gitignore: /data/ uitgesloten. Zonder dat zou de gegevensmap als lokale
wijziging gelden en zou deploy.sh weigeren te draaien.
- deploy.sh maakt de gegevensmappen aan als de opslagkeuze paden gebruikt,
zodat Docker ze niet als root aanmaakt.
- DEPLOY.md en README: installatie via het script, de opslagkeuze in een
tabel, en de dump/restore-stappen die nodig zijn bij het omzetten van
volumes naar mappen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAQ4Np13v8fwbTtKHKnwDz
This commit is contained in:
parent
500cf6c558
commit
f795e85333
10 changed files with 374 additions and 34 deletions
10
.env.example
10
.env.example
|
|
@ -27,6 +27,16 @@ DJANGO_CSRF_TRUSTED_ORIGINS=https://rooster.example.nl
|
||||||
# in dit project geeft die header door.
|
# in dit project geeft die header door.
|
||||||
DJANGO_SECURE=1
|
DJANGO_SECURE=1
|
||||||
|
|
||||||
|
# --- Opslag ---------------------------------------------------------------
|
||||||
|
# Waar de gegevens staan. Een NAAM = Docker beheert het volume; een PAD =
|
||||||
|
# gewone map naast de code (direct benaderbaar, makkelijk te back-uppen).
|
||||||
|
# scripts/install.sh vult dit in op basis van je keuze.
|
||||||
|
# Docker-volumes: DATA_DB=pgdata DATA_MEDIA=media_volume DATA_STATIC=static_volume
|
||||||
|
# Gewone mappen: DATA_DB=./data/postgres DATA_MEDIA=./data/media DATA_STATIC=./data/static
|
||||||
|
DATA_DB=pgdata
|
||||||
|
DATA_MEDIA=media_volume
|
||||||
|
DATA_STATIC=static_volume
|
||||||
|
|
||||||
# --- PostgreSQL -----------------------------------------------------------
|
# --- PostgreSQL -----------------------------------------------------------
|
||||||
POSTGRES_DB=rooster
|
POSTGRES_DB=rooster
|
||||||
POSTGRES_USER=rooster
|
POSTGRES_USER=rooster
|
||||||
|
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -68,3 +68,9 @@ logs/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
desktop.ini
|
desktop.ini
|
||||||
|
|
||||||
|
# Gegevens bij de 'gewone mappen'-opslagkeuze (database, media, statics).
|
||||||
|
# Deze map hoort nooit in git en moet buiten 'git status' blijven, anders
|
||||||
|
# weigert scripts/deploy.sh te draaien wegens 'lokale wijzigingen'.
|
||||||
|
/data/
|
||||||
|
.env.backup-*
|
||||||
|
|
|
||||||
83
DEPLOY.md
83
DEPLOY.md
|
|
@ -78,30 +78,67 @@ Je hoeft op de server **niets** te installeren behalve Docker zelf (met de
|
||||||
|
|
||||||
## Eenmalig: server klaarzetten
|
## Eenmalig: server klaarzetten
|
||||||
|
|
||||||
1. Zorg dat Docker + Compose op de test-server staan:
|
Het installatiescript doet alles hieronder in zeven stappen en stelt drie
|
||||||
```bash
|
vragen. Standaard komt alles in **`/srv/server-up`**.
|
||||||
docker --version
|
|
||||||
docker compose version
|
|
||||||
```
|
|
||||||
2. Haal de code op:
|
|
||||||
```bash
|
|
||||||
git clone <jouw-forgejo-url>/roosterwijs.git
|
|
||||||
cd roosterwijs
|
|
||||||
```
|
|
||||||
3. Maak het `.env`-bestand aan vanuit het voorbeeld en vul echte waarden in:
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
Belangrijk om aan te passen:
|
|
||||||
- `DJANGO_SECRET_KEY` — genereer met
|
|
||||||
`python3 -c "import secrets; print(secrets.token_urlsafe(50))"`
|
|
||||||
- `DJANGO_ALLOWED_HOSTS` — de hostnaam/IP van de test-server
|
|
||||||
- `DJANGO_CSRF_TRUSTED_ORIGINS` — exact de origin die de browser gebruikt,
|
|
||||||
dus `https://<host>` achter TLS (of `http://<host>:8080` zonder TLS)
|
|
||||||
- `POSTGRES_PASSWORD` — een sterk wachtwoord
|
|
||||||
|
|
||||||
`.env` staat in `.gitignore` en komt dus **niet** in git — dat hoort zo.
|
```bash
|
||||||
|
git clone <jouw-forgejo-url>/roosterwijs.git /tmp/roosterwijs-install
|
||||||
|
/tmp/roosterwijs-install/scripts/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Heb je nog geen schrijfrechten op `/srv`, dan zegt het script welk commando je
|
||||||
|
eenmalig als beheerder moet draaien. Een andere map kan met:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ROOSTERWIJS_DIR=/pad/naar/map ./scripts/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Het script controleert Docker, haalt de code op, vraagt waar de gegevens moeten
|
||||||
|
staan, genereert `.env` met een willekeurige `DJANGO_SECRET_KEY` en een sterk
|
||||||
|
databasewachtwoord, bouwt de containers en biedt aan een beheerder aan te maken.
|
||||||
|
|
||||||
|
### De opslagkeuze
|
||||||
|
|
||||||
|
Bij stap 4 kies je waar database, media en statics terechtkomen:
|
||||||
|
|
||||||
|
| Keuze | Waar | Wanneer |
|
||||||
|
|-------|------|---------|
|
||||||
|
| **1. Docker-volumes** | door Docker beheerd (`docker volume ls`) | standaard; afgeschermd, maar alleen bereikbaar via docker-commando's |
|
||||||
|
| **2. Gewone mappen** | `/srv/server-up/data/` | alles zichtbaar naast de code, makkelijk te back-uppen en in te zien |
|
||||||
|
|
||||||
|
De keuze staat als `DATA_DB`, `DATA_MEDIA` en `DATA_STATIC` in `.env` en is
|
||||||
|
later te wijzigen. **Let op:** omzetten verplaatst geen gegevens. Wissel je van
|
||||||
|
volumes naar mappen, maak dan eerst een dump en zet die daarna terug:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec db pg_dump -U rooster rooster > ~/rooster.sql # vóór het omzetten
|
||||||
|
# ... DATA_* aanpassen in .env, dan:
|
||||||
|
docker compose down && docker compose up -d db
|
||||||
|
cat ~/rooster.sql | docker compose exec -T db psql -U rooster rooster
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Zonder die stap start de app met een **lege** database — de oude gegevens staan
|
||||||
|
dan nog wel in het oude volume, maar worden niet meer gebruikt.
|
||||||
|
|
||||||
|
### Handmatig, zonder script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <jouw-forgejo-url>/roosterwijs.git /srv/server-up
|
||||||
|
cd /srv/server-up
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Belangrijk om aan te passen:
|
||||||
|
- `DJANGO_SECRET_KEY` — genereer met `openssl rand -base64 48`
|
||||||
|
- `DJANGO_ALLOWED_HOSTS` — de hostnaam/IP van de server
|
||||||
|
- `DJANGO_CSRF_TRUSTED_ORIGINS` — exact de origin die de browser gebruikt,
|
||||||
|
dus `https://<host>` achter TLS (of `http://<host>:8080` zonder TLS)
|
||||||
|
- `POSTGRES_PASSWORD` — een sterk wachtwoord
|
||||||
|
- `DATA_DB` / `DATA_MEDIA` / `DATA_STATIC` — zie de tabel hierboven
|
||||||
|
|
||||||
|
`.env` staat in `.gitignore` en komt dus **niet** in git — dat hoort zo.
|
||||||
|
|
||||||
## Starten
|
## Starten
|
||||||
|
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -79,6 +79,23 @@ geboortedatum vast.
|
||||||
Een nieuwe module toevoegen = nieuwe app maken, één regel in
|
Een nieuwe module toevoegen = nieuwe app maken, één regel in
|
||||||
`MODULE_APPS` (in `backend/config/settings.py`), klaar.
|
`MODULE_APPS` (in `backend/config/settings.py`), klaar.
|
||||||
|
|
||||||
|
## Installeren op een server
|
||||||
|
|
||||||
|
Eén commando, zeven stappen, drie vragen. Alles komt standaard in
|
||||||
|
`/srv/server-up`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <jouw-forgejo-url>/roosterwijs.git /tmp/roosterwijs-install
|
||||||
|
/tmp/roosterwijs-install/scripts/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Het script controleert Docker, haalt de code op, laat je kiezen of de gegevens
|
||||||
|
in **Docker-volumes** of in **gewone mappen** (`/srv/server-up/data/`) komen,
|
||||||
|
genereert `.env` met willekeurige geheimen, bouwt de containers en maakt een
|
||||||
|
beheerder aan. Bijwerken doe je daarna met `./scripts/deploy.sh`.
|
||||||
|
|
||||||
|
Details, de opslagkeuze en het draaien achter TLS staan in `DEPLOY.md`.
|
||||||
|
|
||||||
## Starten (lokaal ontwikkelen)
|
## Starten (lokaal ontwikkelen)
|
||||||
|
|
||||||
> Voor een test- of productieserver gelden **andere** stappen: zie `DEPLOY.md`.
|
> Voor een test- of productieserver gelden **andere** stappen: zie `DEPLOY.md`.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
# Stack voor de test-server (en later productie):
|
# Stack voor de test-server (en later productie).
|
||||||
|
#
|
||||||
|
# Waar de gegevens staan, bepaal je in .env (scripts/install.sh vraagt ernaar):
|
||||||
|
# DATA_DB / DATA_MEDIA / DATA_STATIC
|
||||||
|
# - een naam (bv. pgdata) -> Docker beheert het volume
|
||||||
|
# - een pad (bv. ./data/postgres) -> gewone map, direct benaderbaar
|
||||||
|
# Laat je ze leeg, dan gelden de named volumes hieronder — precies zoals
|
||||||
|
# bestaande installaties nu al draaien.
|
||||||
|
#
|
||||||
# db - PostgreSQL
|
# db - PostgreSQL
|
||||||
# backend - Django via gunicorn
|
# backend - Django via gunicorn
|
||||||
# nginx - serveert de frontend en proxyt /api + /admin naar de backend
|
# nginx - serveert de frontend en proxyt /api + /admin naar de backend
|
||||||
|
|
@ -13,7 +21,7 @@ services:
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- ${DATA_DB:-pgdata}:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|
@ -47,9 +55,9 @@ services:
|
||||||
FRONTEND_BASE_URL: ${FRONTEND_BASE_URL:-}
|
FRONTEND_BASE_URL: ${FRONTEND_BASE_URL:-}
|
||||||
volumes:
|
volumes:
|
||||||
# Verzamelde statics delen met nginx.
|
# Verzamelde statics delen met nginx.
|
||||||
- static_volume:/app/staticfiles
|
- ${DATA_STATIC:-static_volume}:/app/staticfiles
|
||||||
# Geüploade media (pictogrammen) delen met nginx.
|
# Geüploade media (pictogrammen, logo) delen met nginx.
|
||||||
- media_volume:/app/media
|
- ${DATA_MEDIA:-media_volume}:/app/media
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
build: ./frontend
|
build: ./frontend
|
||||||
|
|
@ -61,8 +69,8 @@ services:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
volumes:
|
volumes:
|
||||||
# Lees de door Django verzamelde statics (alleen-lezen).
|
# Lees de door Django verzamelde statics (alleen-lezen).
|
||||||
- static_volume:/static:ro
|
- ${DATA_STATIC:-static_volume}:/static:ro
|
||||||
- media_volume:/media:ro
|
- ${DATA_MEDIA:-media_volume}:/media:ro
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
|
|
||||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"version": "0.2.3-beta",
|
"version": "0.2.4-beta",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"version": "0.2.3-beta",
|
"version": "0.2.4-beta",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.3-beta",
|
"version": "0.2.4-beta",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ button,a,input,select{transition:border-color .15s,background-color .15s,color .
|
||||||
.cog-btn{width:100%;min-height:38px;justify-content:flex-start;font-size:15px;padding:0}
|
.cog-btn{width:100%;min-height:38px;justify-content:flex-start;font-size:15px;padding:0}
|
||||||
.cog-btn::after{content:"Beheer en instellingen";margin-left:8px;font-size:13px}
|
.cog-btn::after{content:"Beheer en instellingen";margin-left:8px;font-size:13px}
|
||||||
.cog-dropdown{position:static;min-width:0;margin:4px 0 0;box-shadow:none}
|
.cog-dropdown{position:static;min-width:0;margin:4px 0 0;box-shadow:none}
|
||||||
.topbar::after{content:"v0.2.03 beta";order:4;margin:10px 8px 0;color:#98a2b3;font-size:10px}
|
.topbar::after{content:"v0.2.04 beta";order:4;margin:10px 8px 0;color:#98a2b3;font-size:10px}
|
||||||
.content{margin-left:var(--sidebar);width:calc(100% - var(--sidebar));max-width:1680px;padding:32px 38px 48px}
|
.content{margin-left:var(--sidebar);width:calc(100% - var(--sidebar));max-width:1680px;padding:32px 38px 48px}
|
||||||
.content-wide{padding:24px 28px 42px}
|
.content-wide{padding:24px 28px 42px}
|
||||||
h1{font-size:clamp(24px,2.4vw,30px);line-height:1.2;letter-spacing:-.025em;font-weight:750}
|
h1{font-size:clamp(24px,2.4vw,30px);line-height:1.2;letter-spacing:-.025em;font-weight:750}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,16 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Bouwen en starten ----------------------------------------------------
|
# --- Bouwen en starten ----------------------------------------------------
|
||||||
|
# Bij de 'gewone mappen'-opslagkeuze moeten die mappen bestaan; Docker zou ze
|
||||||
|
# anders als root aanmaken.
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
set -a; . ./.env; set +a
|
||||||
|
for pad in "${DATA_DB:-}" "${DATA_MEDIA:-}" "${DATA_STATIC:-}"; do
|
||||||
|
case "$pad" in
|
||||||
|
./*|/*) mkdir -p "$pad" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
|
|
||||||
# --- Controleren ----------------------------------------------------------
|
# --- Controleren ----------------------------------------------------------
|
||||||
|
|
|
||||||
252
scripts/install.sh
Executable file
252
scripts/install.sh
Executable file
|
|
@ -0,0 +1,252 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Roosterwijs installeren op een server.
|
||||||
|
#
|
||||||
|
# Gebruik: ./scripts/install.sh
|
||||||
|
# ROOSTERWIJS_DIR=/pad/naar/map ./scripts/install.sh
|
||||||
|
#
|
||||||
|
# Het script doorloopt zeven stappen, stelt onderweg drie vragen en raakt
|
||||||
|
# nooit iets aan zonder dat te melden. Afbreken kan altijd met Ctrl-C.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DOELMAP="${ROOSTERWIJS_DIR:-/srv/server-up}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- vormgeving
|
||||||
|
# Kleuren alleen als we naar een terminal schrijven (en NO_COLOR niet gezet is),
|
||||||
|
# zodat de uitvoer in een logbestand leesbaar blijft.
|
||||||
|
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
||||||
|
VET=$'\033[1m'; DOF=$'\033[2m'; STOP=$'\033[0m'
|
||||||
|
GROEN=$'\033[32m'; GEEL=$'\033[33m'; ROOD=$'\033[31m'; BLAUW=$'\033[36m'
|
||||||
|
else
|
||||||
|
VET=''; DOF=''; STOP=''; GROEN=''; GEEL=''; ROOD=''; BLAUW=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIJN=$(printf '─%.0s' $(seq 1 62))
|
||||||
|
STAP_NR=0
|
||||||
|
STAP_TOTAAL=7
|
||||||
|
|
||||||
|
kop() {
|
||||||
|
printf '\n%s%s%s\n' "$BLAUW" "$LIJN" "$STOP"
|
||||||
|
printf ' %sROOSTERWIJS%s %s· installatie%s\n' "$VET" "$STOP" "$DOF" "$STOP"
|
||||||
|
printf '%s%s%s\n' "$BLAUW" "$LIJN" "$STOP"
|
||||||
|
}
|
||||||
|
stap() { STAP_NR=$((STAP_NR + 1)); printf '\n %s[%d/%d]%s %s%s%s\n' "$BLAUW" "$STAP_NR" "$STAP_TOTAAL" "$STOP" "$VET" "$1" "$STOP"; }
|
||||||
|
ok() { printf ' %s✓%s %s\n' "$GROEN" "$STOP" "$1"; }
|
||||||
|
info() { printf ' %s·%s %s\n' "$DOF" "$STOP" "$1"; }
|
||||||
|
let_op(){ printf ' %s!%s %s\n' "$GEEL" "$STOP" "$1"; }
|
||||||
|
fout() { printf '\n %s✗ %s%s\n\n' "$ROOD" "$1" "$STOP" >&2; exit 1; }
|
||||||
|
|
||||||
|
# vraag "Tekst" "standaardwaarde" -> antwoord in $ANTWOORD
|
||||||
|
vraag() {
|
||||||
|
local tekst="$1" standaard="${2:-}" invoer
|
||||||
|
if [ -n "$standaard" ]; then
|
||||||
|
printf ' %s%s%s %s[%s]%s: ' "$VET" "$tekst" "$STOP" "$DOF" "$standaard" "$STOP"
|
||||||
|
else
|
||||||
|
printf ' %s%s%s: ' "$VET" "$tekst" "$STOP"
|
||||||
|
fi
|
||||||
|
read -r invoer </dev/tty 2>/dev/null || invoer=""
|
||||||
|
ANTWOORD="${invoer:-$standaard}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# jaNee "Vraag" "j|n" -> 0 = ja, 1 = nee
|
||||||
|
jaNee() {
|
||||||
|
local tekst="$1" standaard="${2:-j}" invoer
|
||||||
|
local hint="j/N"; [ "$standaard" = "j" ] && hint="J/n"
|
||||||
|
printf ' %s%s%s %s(%s)%s: ' "$VET" "$tekst" "$STOP" "$DOF" "$hint" "$STOP"
|
||||||
|
read -r invoer </dev/tty 2>/dev/null || invoer=""
|
||||||
|
invoer="${invoer:-$standaard}"
|
||||||
|
case "$invoer" in [jJyY]*) return 0 ;; *) return 1 ;; esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wachtwoord/sleutel genereren zonder Python op de server te vereisen.
|
||||||
|
genereer_geheim() {
|
||||||
|
if command -v openssl >/dev/null 2>&1; then
|
||||||
|
openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | cut -c1-50
|
||||||
|
else
|
||||||
|
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 50
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
kop
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- 1. vereisten
|
||||||
|
stap "Vereisten controleren"
|
||||||
|
command -v git >/dev/null 2>&1 || fout "git ontbreekt. Installeer git en probeer opnieuw."
|
||||||
|
ok "git $(git --version | awk '{print $3}')"
|
||||||
|
command -v docker >/dev/null 2>&1 || fout "docker ontbreekt. Zie https://docs.docker.com/engine/install/"
|
||||||
|
ok "docker $(docker --version | awk '{print $3}' | tr -d ,)"
|
||||||
|
docker compose version >/dev/null 2>&1 || fout "'docker compose' werkt niet. Installeer de compose-plugin."
|
||||||
|
ok "docker compose $(docker compose version --short 2>/dev/null || echo aanwezig)"
|
||||||
|
docker info >/dev/null 2>&1 || fout "Kan niet met de Docker-daemon praten. Draait Docker, en zit je in de groep 'docker'?"
|
||||||
|
ok "Docker-daemon bereikbaar"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------- 2. doelmap
|
||||||
|
stap "Doelmap $DOELMAP"
|
||||||
|
if [ ! -d "$DOELMAP" ]; then
|
||||||
|
if mkdir -p "$DOELMAP" 2>/dev/null; then
|
||||||
|
ok "aangemaakt"
|
||||||
|
else
|
||||||
|
printf '\n'
|
||||||
|
let_op "Geen rechten om $DOELMAP aan te maken."
|
||||||
|
info "Draai eenmalig, als beheerder:"
|
||||||
|
printf '\n %ssudo mkdir -p %s && sudo chown "$USER":"$USER" %s%s\n\n' "$VET" "$DOELMAP" "$DOELMAP" "$STOP"
|
||||||
|
fout "Start daarna dit script opnieuw."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
[ -w "$DOELMAP" ] || fout "$DOELMAP bestaat, maar je hebt er geen schrijfrechten."
|
||||||
|
ok "bestaat en is beschrijfbaar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ 3. code
|
||||||
|
stap "Code ophalen"
|
||||||
|
if [ -d "$DOELMAP/.git" ]; then
|
||||||
|
ok "checkout gevonden"
|
||||||
|
if jaNee "Bijwerken naar de laatste versie?" j; then
|
||||||
|
git -C "$DOELMAP" fetch origin --quiet
|
||||||
|
tak="$(git -C "$DOELMAP" rev-parse --abbrev-ref HEAD)"
|
||||||
|
git -C "$DOELMAP" reset --hard "origin/$tak" --quiet
|
||||||
|
ok "bijgewerkt naar $(git -C "$DOELMAP" rev-parse --short HEAD) op $tak"
|
||||||
|
else
|
||||||
|
info "overgeslagen; huidige versie blijft staan"
|
||||||
|
fi
|
||||||
|
elif [ -n "$(ls -A "$DOELMAP" 2>/dev/null)" ]; then
|
||||||
|
fout "$DOELMAP is niet leeg en bevat geen git-checkout. Maak de map leeg of kies een andere met ROOSTERWIJS_DIR=..."
|
||||||
|
else
|
||||||
|
herkomst=""
|
||||||
|
if git -C "$(dirname "$0")/.." rev-parse --git-dir >/dev/null 2>&1; then
|
||||||
|
herkomst="$(git -C "$(dirname "$0")/.." remote get-url origin 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
vraag "Git-URL van de repository" "$herkomst"
|
||||||
|
[ -n "$ANTWOORD" ] || fout "Zonder URL kan de code niet worden opgehaald."
|
||||||
|
git clone "$ANTWOORD" "$DOELMAP" --quiet || fout "Klonen mislukt. Klopt de URL en heb je toegang (SSH-sleutel)?"
|
||||||
|
ok "gekloond naar $DOELMAP"
|
||||||
|
fi
|
||||||
|
cd "$DOELMAP"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------- 4. opslag
|
||||||
|
stap "Waar komen de gegevens te staan?"
|
||||||
|
printf '\n'
|
||||||
|
printf ' %s1)%s %sDocker-volumes%s %s(standaard)%s\n' "$VET" "$STOP" "$VET" "$STOP" "$DOF" "$STOP"
|
||||||
|
printf ' Docker beheert de opslag. Netjes afgeschermd, maar je\n'
|
||||||
|
printf ' komt er alleen bij via docker-commandos.\n\n'
|
||||||
|
printf ' %s2)%s %sGewone mappen%s onder %s/data\n' "$VET" "$STOP" "$VET" "$STOP" "$DOELMAP"
|
||||||
|
printf ' Database, media en statics staan als zichtbare mappen\n'
|
||||||
|
printf ' naast de code. Makkelijk back-uppen en inzien.\n\n'
|
||||||
|
vraag "Keuze (1 of 2)" "1"
|
||||||
|
case "$ANTWOORD" in
|
||||||
|
2)
|
||||||
|
OPSLAG="mappen"
|
||||||
|
DATA_DB="./data/postgres"; DATA_MEDIA="./data/media"; DATA_STATIC="./data/static"
|
||||||
|
mkdir -p data/postgres data/media data/static
|
||||||
|
ok "mappen aangemaakt onder $DOELMAP/data"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
OPSLAG="volumes"
|
||||||
|
DATA_DB="pgdata"; DATA_MEDIA="media_volume"; DATA_STATIC="static_volume"
|
||||||
|
ok "Docker beheert de opslag (volumes pgdata, media_volume, static_volume)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ 5. .env
|
||||||
|
stap "Instellingen (.env)"
|
||||||
|
if [ -f .env ]; then
|
||||||
|
ok ".env bestaat al"
|
||||||
|
if jaNee "Laten staan en ongewijzigd gebruiken?" j; then
|
||||||
|
info "bestaande instellingen blijven gelden"
|
||||||
|
if ! grep -q '^DATA_DB=' .env; then
|
||||||
|
{ echo ""; echo "# Opslagkeuze (toegevoegd door install.sh)"
|
||||||
|
echo "DATA_DB=$DATA_DB"; echo "DATA_MEDIA=$DATA_MEDIA"; echo "DATA_STATIC=$DATA_STATIC"; } >> .env
|
||||||
|
ok "opslagkeuze toegevoegd aan .env"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp .env ".env.backup-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
ok "oude .env bewaard als .env.backup-*"
|
||||||
|
rm -f .env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
vraag "Hostnaam waarop de app bereikbaar is" "rooster.example.nl"
|
||||||
|
HOSTNAAM="$ANTWOORD"
|
||||||
|
if jaNee "Draait er TLS (https) voor deze server?" j; then
|
||||||
|
SCHEMA="https"; SECURE=1
|
||||||
|
else
|
||||||
|
SCHEMA="http"; SECURE=0
|
||||||
|
fi
|
||||||
|
BASIS_URL="$SCHEMA://$HOSTNAAM"
|
||||||
|
[ "$SCHEMA" = "http" ] && BASIS_URL="$BASIS_URL:8080"
|
||||||
|
|
||||||
|
cat > .env <<ENVEOF
|
||||||
|
# Aangemaakt door scripts/install.sh op $(date '+%Y-%m-%d %H:%M').
|
||||||
|
# Dit bestand bevat geheimen en staat in .gitignore.
|
||||||
|
|
||||||
|
# --- Django ---------------------------------------------------------------
|
||||||
|
DJANGO_SECRET_KEY=$(genereer_geheim)
|
||||||
|
DJANGO_DEBUG=0
|
||||||
|
DJANGO_ALLOWED_HOSTS=$HOSTNAAM,localhost,127.0.0.1
|
||||||
|
DJANGO_CSRF_TRUSTED_ORIGINS=$BASIS_URL
|
||||||
|
|
||||||
|
# 1 = veilige cookies, HSTS en https-redirect. Vereist dat de proxy
|
||||||
|
# X-Forwarded-Proto: https meestuurt (zie DEPLOY.md).
|
||||||
|
DJANGO_SECURE=$SECURE
|
||||||
|
|
||||||
|
# --- Opslag ---------------------------------------------------------------
|
||||||
|
# Een naam = Docker-volume, een pad = gewone map naast de code.
|
||||||
|
DATA_DB=$DATA_DB
|
||||||
|
DATA_MEDIA=$DATA_MEDIA
|
||||||
|
DATA_STATIC=$DATA_STATIC
|
||||||
|
|
||||||
|
# --- PostgreSQL -----------------------------------------------------------
|
||||||
|
POSTGRES_DB=rooster
|
||||||
|
POSTGRES_USER=rooster
|
||||||
|
POSTGRES_PASSWORD=$(genereer_geheim)
|
||||||
|
|
||||||
|
# --- E-mail (wachtwoordreset) --------------------------------------------
|
||||||
|
# Leeg = e-mail gaat naar de log van de backend-container.
|
||||||
|
EMAIL_HOST=
|
||||||
|
EMAIL_PORT=587
|
||||||
|
EMAIL_HOST_USER=
|
||||||
|
EMAIL_HOST_PASSWORD=
|
||||||
|
EMAIL_USE_TLS=1
|
||||||
|
DEFAULT_FROM_EMAIL=Roosterwijs <noreply@$HOSTNAAM>
|
||||||
|
FRONTEND_BASE_URL=$BASIS_URL
|
||||||
|
ENVEOF
|
||||||
|
chmod 600 .env
|
||||||
|
ok "aangemaakt met willekeurige sleutel en databasewachtwoord"
|
||||||
|
info "hostnaam: $HOSTNAAM · $( [ "$SECURE" = 1 ] && echo 'TLS aan' || echo 'TLS uit' )"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------ 6. bouwen
|
||||||
|
stap "Containers bouwen en starten"
|
||||||
|
info "dit duurt de eerste keer enkele minuten"
|
||||||
|
docker compose up -d --build || fout "Bouwen mislukt. Bekijk de uitvoer hierboven."
|
||||||
|
ok "db, backend en nginx draaien"
|
||||||
|
|
||||||
|
# --------------------------------------------------------- 7. beheerder
|
||||||
|
stap "Beheerder"
|
||||||
|
aantal="$(docker compose exec -T backend python manage.py shell -c \
|
||||||
|
'from django.contrib.auth import get_user_model; print(get_user_model().objects.count())' 2>/dev/null | tr -dc '0-9')"
|
||||||
|
aantal="${aantal:-0}"
|
||||||
|
if [ "$aantal" -gt 0 ]; then
|
||||||
|
ok "er zijn al $aantal account(s); geen nieuwe nodig"
|
||||||
|
else
|
||||||
|
let_op "Er is nog geen account. Zonder account kun je nergens inloggen."
|
||||||
|
if jaNee "Nu een beheerder aanmaken?" j; then
|
||||||
|
docker compose exec backend python manage.py createsuperuser </dev/tty 2>/dev/null || \
|
||||||
|
let_op "Aanmaken afgebroken; doe het later met het commando hieronder."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ klaar
|
||||||
|
printf '\n%s%s%s\n' "$GROEN" "$LIJN" "$STOP"
|
||||||
|
printf ' %s✓ Installatie afgerond%s\n' "$GROEN$VET" "$STOP"
|
||||||
|
printf '%s%s%s\n\n' "$GROEN" "$LIJN" "$STOP"
|
||||||
|
printf ' %sMap%s %s\n' "$DOF" "$STOP" "$DOELMAP"
|
||||||
|
if [ "$OPSLAG" = "mappen" ]; then
|
||||||
|
printf ' %sGegevens%s %s/data (database, media, statics)\n' "$DOF" "$STOP" "$DOELMAP"
|
||||||
|
else
|
||||||
|
printf ' %sGegevens%s Docker-volumes (docker volume ls)\n' "$DOF" "$STOP"
|
||||||
|
fi
|
||||||
|
printf ' %sBijwerken%s ./scripts/deploy.sh\n' "$DOF" "$STOP"
|
||||||
|
printf ' %sLogs%s docker compose logs -f\n' "$DOF" "$STOP"
|
||||||
|
printf ' %sBeheerder%s docker compose exec backend python manage.py createsuperuser\n\n' "$DOF" "$STOP"
|
||||||
Loading…
Reference in a new issue