Initial Discourse deployment config for cadCAD community forum
Sets up official Discourse Docker behind Traefik reverse proxy on Netcup RS 8000. Temp domain: cadcad-forum.jeffemmett.com (switching to community.cadcad.org later). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
efac8782ac
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Discourse Environment Variables
|
||||||
|
# Copy to .env and fill in values
|
||||||
|
|
||||||
|
# Admin
|
||||||
|
DISCOURSE_DEVELOPER_EMAILS=jeff@jeffemmett.com
|
||||||
|
|
||||||
|
# Domain (temporary - switch to community.cadcad.org later)
|
||||||
|
DISCOURSE_HOSTNAME=cadcad-forum.jeffemmett.com
|
||||||
|
|
||||||
|
# SMTP (configure when email provider is chosen)
|
||||||
|
# DISCOURSE_SMTP_ADDRESS=smtp.example.com
|
||||||
|
# DISCOURSE_SMTP_PORT=587
|
||||||
|
# DISCOURSE_SMTP_USER_NAME=
|
||||||
|
# DISCOURSE_SMTP_PASSWORD=
|
||||||
|
# DISCOURSE_SMTP_ENABLE_START_TLS=true
|
||||||
|
# DISCOURSE_SMTP_DOMAIN=cadcad.org
|
||||||
|
# DISCOURSE_NOTIFICATION_EMAIL=noreply@cadcad.org
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.env
|
||||||
|
*.backup
|
||||||
|
*.tar.gz
|
||||||
|
shared/
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
# cadCAD Community Discourse Forum
|
||||||
|
|
||||||
|
Self-hosted Discourse forum for the cadCAD community.
|
||||||
|
|
||||||
|
- **Temp URL**: https://cadcad-forum.jeffemmett.com
|
||||||
|
- **Final URL**: https://community.cadcad.org (pending DNS coordination)
|
||||||
|
- **Server**: Netcup RS 8000 at `/opt/discourse/`
|
||||||
|
- **Memory**: 2GB container limit + 2GB swap
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh netcup
|
||||||
|
cd /opt/discourse
|
||||||
|
|
||||||
|
./launcher logs app # View logs
|
||||||
|
./launcher restart app # Restart
|
||||||
|
./launcher rebuild app # Rebuild (after config changes)
|
||||||
|
./launcher enter app # Shell into container
|
||||||
|
./launcher stop app # Stop
|
||||||
|
```
|
||||||
|
|
||||||
|
After any rebuild, reconnect to Traefik:
|
||||||
|
```bash
|
||||||
|
bash scripts/post-rebuild.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Initial Setup
|
||||||
|
|
||||||
|
1. Run `scripts/install.sh` on Netcup (or see SPEC.md for manual steps)
|
||||||
|
2. Add `cadcad-forum.jeffemmett.com` to Cloudflare tunnel
|
||||||
|
3. Create admin account: `./launcher enter app` → `rake admin:create`
|
||||||
|
|
||||||
|
## Import Existing Forum Data
|
||||||
|
|
||||||
|
1. Get `.tar.gz` backup from existing community.cadcad.org admin panel (`/admin/backups`)
|
||||||
|
2. Upload to Netcup: `scp backup.tar.gz netcup:/tmp/`
|
||||||
|
3. Run: `bash scripts/restore-backup.sh /tmp/backup.tar.gz`
|
||||||
|
|
||||||
|
## Switch to community.cadcad.org
|
||||||
|
|
||||||
|
1. Edit `containers/app.yml`: update `DISCOURSE_HOSTNAME` and Traefik `Host()` rule
|
||||||
|
2. `./launcher rebuild app && bash scripts/post-rebuild.sh`
|
||||||
|
3. Add `community.cadcad.org` to Cloudflare tunnel
|
||||||
|
4. Coordinate DNS: CNAME `community.cadcad.org` → tunnel UUID `.cfargotunnel.com`
|
||||||
|
|
||||||
|
## Configure Email (SMTP)
|
||||||
|
|
||||||
|
Uncomment and fill in the SMTP section in `containers/app.yml`, then rebuild.
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
# cadCAD Discourse Forum - Deployment Spec
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Deploy a self-hosted Discourse forum on Netcup RS 8000, initially at `cadcad-forum.jeffemmett.com` (temporary domain), to be switched to `community.cadcad.org` once DNS is coordinated. An existing Discourse backup will be imported later.
|
||||||
|
|
||||||
|
## Architecture Decision: Official Discourse Docker
|
||||||
|
|
||||||
|
**Chosen approach: Official Discourse Docker** (`discourse/discourse_docker`)
|
||||||
|
|
||||||
|
### Why official over alternatives?
|
||||||
|
|
||||||
|
| Criteria | Official | nfrastack (alternative) |
|
||||||
|
|----------|----------|------------------------|
|
||||||
|
| Backup import | Best (native) | Untested |
|
||||||
|
| Long-term support | Discourse team | Community |
|
||||||
|
| Plugin management | Easy (app.yml) | Env vars |
|
||||||
|
| Traefik integration | Requires config tweaks | Native |
|
||||||
|
| Docker-compose native | No (custom launcher) | Yes |
|
||||||
|
|
||||||
|
**Backup compatibility is the deciding factor** since we need to import an existing community.cadcad.org backup later. The official approach is the only one guaranteed to handle this reliably.
|
||||||
|
|
||||||
|
### Trade-off accepted
|
||||||
|
|
||||||
|
The official Discourse Docker uses a custom `./launcher` script instead of standard `docker-compose`. This breaks the pattern used by other services on the stack, but is necessary for reliable backup import/restore.
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### Infrastructure
|
||||||
|
- **Server**: Netcup RS 8000 (64GB RAM, 20 cores)
|
||||||
|
- **Container type**: Monolithic (PostgreSQL + Redis + Discourse in one container)
|
||||||
|
- **Memory limit**: 2GB container + 2GB swap (sufficient for <1k users in steady state)
|
||||||
|
- **Temp domain**: `cadcad-forum.jeffemmett.com`
|
||||||
|
- **Final domain**: `community.cadcad.org` (DNS controlled by someone else)
|
||||||
|
|
||||||
|
### Routing
|
||||||
|
```
|
||||||
|
Internet → Cloudflare Tunnel → Traefik (:80) → Discourse container (:80 internal)
|
||||||
|
```
|
||||||
|
|
||||||
|
Traefik integration via Docker labels in `app.yml`:
|
||||||
|
- Disable SSL templates (Cloudflare handles TLS)
|
||||||
|
- Don't expose ports directly (Traefik routes traffic)
|
||||||
|
- Connect to `traefik-public` network via `docker_args`
|
||||||
|
|
||||||
|
### Email
|
||||||
|
- Deferred for initial setup
|
||||||
|
- Will configure SMTP later (Resend or another provider)
|
||||||
|
- Discourse will warn about missing email but will function for admin access
|
||||||
|
|
||||||
|
### Storage
|
||||||
|
- Data stored in `/opt/discourse/shared/standalone/` on Netcup
|
||||||
|
- PostgreSQL data, Redis data, uploads, backups all within the container's shared directory
|
||||||
|
- Repo at `/opt/discourse/` contains config only (not data)
|
||||||
|
|
||||||
|
## Deployment Steps
|
||||||
|
|
||||||
|
1. **Create repo** with config files locally at `/home/jeffe/Github/cadcad-discourse-forum`
|
||||||
|
2. **Clone to Netcup** at `/opt/discourse/`
|
||||||
|
3. **Install official Discourse Docker** (`discourse_docker` launcher)
|
||||||
|
4. **Configure `app.yml`** with Traefik labels, no SSL, 2GB memory limit
|
||||||
|
5. **Add Cloudflare tunnel hostname** for `cadcad-forum.jeffemmett.com`
|
||||||
|
6. **Bootstrap and start** Discourse
|
||||||
|
7. **Verify** forum is accessible at `cadcad-forum.jeffemmett.com`
|
||||||
|
|
||||||
|
## Files in This Repo
|
||||||
|
|
||||||
|
```
|
||||||
|
cadcad-discourse-forum/
|
||||||
|
├── SPEC.md # This file
|
||||||
|
├── README.md # Deployment instructions
|
||||||
|
├── app.yml # Discourse container config (copied to /opt/discourse/containers/)
|
||||||
|
├── .env.example # Environment variable template
|
||||||
|
└── scripts/
|
||||||
|
├── install.sh # Initial setup script (run on Netcup)
|
||||||
|
└── restore-backup.sh # Backup import script (for later)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Plan (Later)
|
||||||
|
|
||||||
|
1. Obtain `.tar.gz` backup from existing community.cadcad.org admin panel
|
||||||
|
2. Upload to `/opt/discourse/shared/standalone/backups/default/`
|
||||||
|
3. Run restore: `./launcher enter app` → `discourse restore <filename>`
|
||||||
|
4. Coordinate DNS change: `community.cadcad.org` CNAME → tunnel
|
||||||
|
5. Update `app.yml` hostname and rebuild
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
- Email configuration (deferred)
|
||||||
|
- SSO/OAuth integration
|
||||||
|
- Custom plugins (can be added later via `app.yml`)
|
||||||
|
- CDN configuration
|
||||||
|
- Automated backups (Discourse has built-in scheduled backups)
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
- Which email provider to use when ready (Resend, Mailgun, etc.)
|
||||||
|
- Who to coordinate with for cadcad.org DNS
|
||||||
|
- Whether any specific Discourse plugins are needed from the existing instance
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
## Discourse container config for cadCAD community forum
|
||||||
|
## Deployed behind Traefik reverse proxy on Netcup RS 8000
|
||||||
|
##
|
||||||
|
## This file gets copied to /opt/discourse/containers/app.yml on the server.
|
||||||
|
## After editing, rebuild with: cd /opt/discourse && ./launcher rebuild app
|
||||||
|
|
||||||
|
templates:
|
||||||
|
- "templates/postgres.template.yml"
|
||||||
|
- "templates/redis.template.yml"
|
||||||
|
- "templates/web.template.yml"
|
||||||
|
## SSL handled by Cloudflare/Traefik - do NOT enable these:
|
||||||
|
# - "templates/web.ssl.template.yml"
|
||||||
|
# - "templates/web.letsencrypt.ssl.template.yml"
|
||||||
|
- "templates/web.ratelimited.template.yml"
|
||||||
|
|
||||||
|
## No direct port exposure - Traefik routes traffic via Docker network
|
||||||
|
## expose:
|
||||||
|
## - "80:80"
|
||||||
|
|
||||||
|
params:
|
||||||
|
db_default_text_search_config: "pg_catalog.english"
|
||||||
|
## 2GB total container limit, tune DB accordingly
|
||||||
|
db_shared_buffers: "128MB"
|
||||||
|
db_work_mem: "10MB"
|
||||||
|
|
||||||
|
env:
|
||||||
|
LC_ALL: en_US.UTF-8
|
||||||
|
LANG: en_US.UTF-8
|
||||||
|
LANGUAGE: en_US.UTF-8
|
||||||
|
|
||||||
|
DISCOURSE_DEFAULT_LOCALE: en
|
||||||
|
|
||||||
|
## Temporary domain - will switch to community.cadcad.org later
|
||||||
|
DISCOURSE_HOSTNAME: 'cadcad-forum.jeffemmett.com'
|
||||||
|
|
||||||
|
## Admin email for initial setup
|
||||||
|
DISCOURSE_DEVELOPER_EMAILS: 'jeff@jeffemmett.com'
|
||||||
|
|
||||||
|
## SMTP - configure when ready (forum works without it but can't send emails)
|
||||||
|
## Uncomment and fill in when email provider is chosen:
|
||||||
|
# DISCOURSE_SMTP_ADDRESS: smtp.example.com
|
||||||
|
# DISCOURSE_SMTP_PORT: 587
|
||||||
|
# DISCOURSE_SMTP_USER_NAME: user@example.com
|
||||||
|
# DISCOURSE_SMTP_PASSWORD: "password"
|
||||||
|
# DISCOURSE_SMTP_ENABLE_START_TLS: true
|
||||||
|
# DISCOURSE_SMTP_DOMAIN: cadcad.org
|
||||||
|
# DISCOURSE_NOTIFICATION_EMAIL: noreply@cadcad.org
|
||||||
|
|
||||||
|
## Serve behind reverse proxy
|
||||||
|
DISCOURSE_FORCE_HTTPS: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- volume:
|
||||||
|
host: /opt/discourse/shared/standalone
|
||||||
|
guest: /shared
|
||||||
|
- volume:
|
||||||
|
host: /opt/discourse/shared/standalone/log/var-log
|
||||||
|
guest: /var/log
|
||||||
|
|
||||||
|
hooks:
|
||||||
|
after_code:
|
||||||
|
- exec:
|
||||||
|
cd: $home/plugins
|
||||||
|
cmd:
|
||||||
|
## Add plugins here (uncomment as needed):
|
||||||
|
# - git clone https://github.com/discourse/docker_manager.git
|
||||||
|
# - git clone https://github.com/discourse/discourse-solved.git
|
||||||
|
# - git clone https://github.com/discourse/discourse-voting.git
|
||||||
|
- echo "Plugin installation complete"
|
||||||
|
|
||||||
|
## Memory limit: 2GB container + 2GB swap
|
||||||
|
run:
|
||||||
|
- exec: echo "Beginning of custom commands"
|
||||||
|
|
||||||
|
## Traefik integration labels
|
||||||
|
labels:
|
||||||
|
app_name: discourse
|
||||||
|
traefik.enable: "true"
|
||||||
|
traefik.docker.network: traefik-public
|
||||||
|
traefik.http.routers.discourse.rule: "Host(`cadcad-forum.jeffemmett.com`)"
|
||||||
|
traefik.http.services.discourse.loadbalancer.server.port: "80"
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
## Discourse Installation Script for Netcup RS 8000
|
||||||
|
## Run this ON the Netcup server: ssh netcup "bash -s" < scripts/install.sh
|
||||||
|
## Or: ssh netcup, then cd /opt/discourse && bash scripts/install.sh
|
||||||
|
|
||||||
|
DISCOURSE_DIR="/opt/discourse"
|
||||||
|
REPO_URL="https://github.com/discourse/discourse_docker.git"
|
||||||
|
|
||||||
|
echo "=== Discourse Installation for cadCAD Community Forum ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. Check for swap (Discourse needs it for 2GB RAM limit)
|
||||||
|
echo "[1/6] Checking swap space..."
|
||||||
|
SWAP_TOTAL=$(free -m | awk '/^Swap:/ {print $2}')
|
||||||
|
if [ "$SWAP_TOTAL" -lt 2000 ]; then
|
||||||
|
echo " WARNING: Less than 2GB swap detected (${SWAP_TOTAL}MB)."
|
||||||
|
echo " Creating 2GB swap file..."
|
||||||
|
if [ ! -f /swapfile ]; then
|
||||||
|
fallocate -l 2G /swapfile
|
||||||
|
chmod 600 /swapfile
|
||||||
|
mkswap /swapfile
|
||||||
|
swapon /swapfile
|
||||||
|
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||||
|
echo " Swap file created and enabled."
|
||||||
|
else
|
||||||
|
echo " /swapfile already exists. Enabling if not active..."
|
||||||
|
swapon /swapfile 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Swap OK: ${SWAP_TOTAL}MB"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Clone discourse_docker
|
||||||
|
echo ""
|
||||||
|
echo "[2/6] Setting up Discourse Docker..."
|
||||||
|
if [ -d "$DISCOURSE_DIR/.git" ]; then
|
||||||
|
echo " discourse_docker already cloned at $DISCOURSE_DIR"
|
||||||
|
cd "$DISCOURSE_DIR"
|
||||||
|
git pull
|
||||||
|
else
|
||||||
|
echo " Cloning discourse_docker..."
|
||||||
|
git clone "$REPO_URL" "$DISCOURSE_DIR"
|
||||||
|
cd "$DISCOURSE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Copy app.yml config
|
||||||
|
echo ""
|
||||||
|
echo "[3/6] Installing app.yml configuration..."
|
||||||
|
if [ -f "containers/app.yml" ]; then
|
||||||
|
echo " Backing up existing app.yml to containers/app.yml.backup"
|
||||||
|
cp containers/app.yml "containers/app.yml.backup.$(date +%Y%m%d%H%M%S)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The app.yml should already be in the repo root from our config
|
||||||
|
if [ -f "app.yml" ]; then
|
||||||
|
cp app.yml containers/app.yml
|
||||||
|
echo " app.yml copied to containers/"
|
||||||
|
else
|
||||||
|
echo " ERROR: app.yml not found in repo root."
|
||||||
|
echo " Please copy it manually: cp /path/to/app.yml containers/app.yml"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Ensure traefik-public network exists
|
||||||
|
echo ""
|
||||||
|
echo "[4/6] Checking Docker networks..."
|
||||||
|
if docker network inspect traefik-public >/dev/null 2>&1; then
|
||||||
|
echo " traefik-public network exists."
|
||||||
|
else
|
||||||
|
echo " Creating traefik-public network..."
|
||||||
|
docker network create traefik-public
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Bootstrap Discourse (this takes 5-10 minutes)
|
||||||
|
echo ""
|
||||||
|
echo "[5/6] Bootstrapping Discourse container..."
|
||||||
|
echo " This will take 5-10 minutes. Building image and precompiling assets..."
|
||||||
|
echo ""
|
||||||
|
./launcher bootstrap app
|
||||||
|
|
||||||
|
# 6. Start and connect to Traefik network
|
||||||
|
echo ""
|
||||||
|
echo "[6/6] Starting Discourse and connecting to Traefik..."
|
||||||
|
./launcher start app
|
||||||
|
|
||||||
|
# Connect to traefik-public network
|
||||||
|
CONTAINER_ID=$(docker ps -q -f name=app)
|
||||||
|
if [ -n "$CONTAINER_ID" ]; then
|
||||||
|
docker network connect traefik-public "$CONTAINER_ID" 2>/dev/null || echo " Already connected to traefik-public"
|
||||||
|
echo " Container connected to traefik-public network."
|
||||||
|
else
|
||||||
|
echo " WARNING: Could not find running discourse container."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Discourse Installation Complete ==="
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Add cadcad-forum.jeffemmett.com to Cloudflare tunnel"
|
||||||
|
echo " 2. Create admin account:"
|
||||||
|
echo " cd /opt/discourse && ./launcher enter app"
|
||||||
|
echo " rake admin:create"
|
||||||
|
echo " 3. Configure SMTP in containers/app.yml when ready"
|
||||||
|
echo " 4. Visit https://cadcad-forum.jeffemmett.com"
|
||||||
|
echo ""
|
||||||
|
echo "Useful commands:"
|
||||||
|
echo " ./launcher logs app # View logs"
|
||||||
|
echo " ./launcher restart app # Restart"
|
||||||
|
echo " ./launcher rebuild app # Rebuild after config changes"
|
||||||
|
echo " ./launcher enter app # Shell into container"
|
||||||
|
echo " ./launcher stop app # Stop"
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
## Reconnect Discourse container to traefik-public network after rebuild
|
||||||
|
## Run after every: ./launcher rebuild app
|
||||||
|
##
|
||||||
|
## The official launcher creates a NEW container on rebuild, which loses
|
||||||
|
## the external network connection. This script reconnects it.
|
||||||
|
|
||||||
|
CONTAINER_ID=$(docker ps -q -f name=app)
|
||||||
|
|
||||||
|
if [ -z "$CONTAINER_ID" ]; then
|
||||||
|
echo "ERROR: Discourse container not running. Start it first: ./launcher start app"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Connecting Discourse container to traefik-public network..."
|
||||||
|
docker network connect traefik-public "$CONTAINER_ID" 2>/dev/null && \
|
||||||
|
echo "Connected successfully." || \
|
||||||
|
echo "Already connected."
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
## Restore a Discourse backup from an existing instance
|
||||||
|
## Usage: bash scripts/restore-backup.sh <path-to-backup.tar.gz>
|
||||||
|
|
||||||
|
DISCOURSE_DIR="/opt/discourse"
|
||||||
|
BACKUP_DIR="/opt/discourse/shared/standalone/backups/default"
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: $0 <path-to-backup.tar.gz>"
|
||||||
|
echo ""
|
||||||
|
echo "Steps to get a backup from the existing community.cadcad.org:"
|
||||||
|
echo " 1. Log into the existing Discourse as admin"
|
||||||
|
echo " 2. Go to /admin/backups"
|
||||||
|
echo " 3. Click 'Backup' to create a new backup"
|
||||||
|
echo " 4. Download the .tar.gz file"
|
||||||
|
echo " 5. Upload to Netcup: scp backup.tar.gz netcup:/tmp/"
|
||||||
|
echo " 6. Run: bash $0 /tmp/backup.tar.gz"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BACKUP_FILE="$1"
|
||||||
|
|
||||||
|
if [ ! -f "$BACKUP_FILE" ]; then
|
||||||
|
echo "ERROR: Backup file not found: $BACKUP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Discourse Backup Restore ==="
|
||||||
|
echo "Backup file: $BACKUP_FILE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Copy backup to Discourse backup directory
|
||||||
|
echo "[1/4] Copying backup to Discourse backup directory..."
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
cp "$BACKUP_FILE" "$BACKUP_DIR/"
|
||||||
|
BACKUP_FILENAME=$(basename "$BACKUP_FILE")
|
||||||
|
echo " Copied to $BACKUP_DIR/$BACKUP_FILENAME"
|
||||||
|
|
||||||
|
# Enable restore mode
|
||||||
|
echo ""
|
||||||
|
echo "[2/4] Enabling restore mode..."
|
||||||
|
cd "$DISCOURSE_DIR"
|
||||||
|
./launcher enter app <<EOF
|
||||||
|
discourse enable_restore
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Restore the backup
|
||||||
|
echo ""
|
||||||
|
echo "[3/4] Restoring backup (this may take several minutes)..."
|
||||||
|
./launcher enter app <<EOF
|
||||||
|
discourse restore $BACKUP_FILENAME
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Rebuild to ensure everything is clean
|
||||||
|
echo ""
|
||||||
|
echo "[4/4] Rebuilding container to finalize restore..."
|
||||||
|
./launcher rebuild app
|
||||||
|
|
||||||
|
# Reconnect to traefik network after rebuild
|
||||||
|
CONTAINER_ID=$(docker ps -q -f name=app)
|
||||||
|
if [ -n "$CONTAINER_ID" ]; then
|
||||||
|
docker network connect traefik-public "$CONTAINER_ID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Restore Complete ==="
|
||||||
|
echo ""
|
||||||
|
echo "The forum should now contain all data from the backup."
|
||||||
|
echo "Visit https://cadcad-forum.jeffemmett.com to verify."
|
||||||
|
echo ""
|
||||||
|
echo "If switching to community.cadcad.org:"
|
||||||
|
echo " 1. Update DISCOURSE_HOSTNAME in containers/app.yml"
|
||||||
|
echo " 2. Update Traefik router rule in containers/app.yml"
|
||||||
|
echo " 3. ./launcher rebuild app"
|
||||||
|
echo " 4. Update Cloudflare tunnel + DNS"
|
||||||
Loading…
Reference in New Issue