vps setup
This commit is contained in:
526
VPS_SETUP_FROM_SCRATCH.md
Normal file
526
VPS_SETUP_FROM_SCRATCH.md
Normal file
@@ -0,0 +1,526 @@
|
|||||||
|
# Honey VPS Setup from Scratch (Inferno)
|
||||||
|
|
||||||
|
This guide walks through setting up a new VPS for the **Honey** app with the same layout as your existing lottery VPS: backend + MySQL + phpMyAdmin in Docker, frontend and admin panel served by Nginx, logging under `/opt/app/logs`, secrets in `/run/secrets`, and MySQL backups to a backup VPS.
|
||||||
|
|
||||||
|
**Target layout (mirrors your lottery setup):**
|
||||||
|
|
||||||
|
- **Containers:** backend (honey-be), MySQL (honey_db), phpMyAdmin
|
||||||
|
- **Served by Nginx:** frontend (honey-fe), admin panel (honey-admin)
|
||||||
|
- **Paths:** `/opt/app` for app files, `/run/secrets` for config, `/opt/app/logs` for logs
|
||||||
|
- **Nginx:** main config + site config (e.g. `nginx.conf` + `sites-enabled/your-domain`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. VPS basics
|
||||||
|
|
||||||
|
### 1.1 System update and installs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Docker
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sudo sh get-docker.sh
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
|
||||||
|
# Docker Compose (plugin)
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y docker-compose-plugin
|
||||||
|
|
||||||
|
# Nginx + Certbot
|
||||||
|
sudo apt install -y nginx certbot python3-certbot-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Log out and back in so `docker` group applies.
|
||||||
|
|
||||||
|
### 1.2 Directory structure under `/opt/app`
|
||||||
|
|
||||||
|
Create the same layout as lottery (backend, frontend, admin, nginx, data, logs, backups, mysql):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /opt/app/backend
|
||||||
|
sudo mkdir -p /opt/app/frontend
|
||||||
|
sudo mkdir -p /opt/app/admin
|
||||||
|
sudo mkdir -p /opt/app/admin-panel
|
||||||
|
sudo mkdir -p /opt/app/nginx
|
||||||
|
sudo mkdir -p /opt/app/data/avatars
|
||||||
|
sudo mkdir -p /opt/app/logs
|
||||||
|
sudo mkdir -p /opt/app/backups
|
||||||
|
sudo mkdir -p /opt/app/mysql/data
|
||||||
|
sudo mkdir -p /opt/app/mysql/conf
|
||||||
|
|
||||||
|
sudo chown -R $USER:$USER /opt/app
|
||||||
|
sudo chmod -R 755 /opt/app
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 Git
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install git -y
|
||||||
|
git config --global alias.st status
|
||||||
|
ssh-keygen -t ed25519 -C "your_email@example.com" (replace email)
|
||||||
|
cat ~/.ssh/id_ed25519.pub (copy the key and add to origin)
|
||||||
|
|
||||||
|
curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
|
sudo tailscale up (and login in local browser to tailscale)
|
||||||
|
```
|
||||||
|
|
||||||
|
Clone all repositories to respective folders.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Backend (honey-be) on VPS
|
||||||
|
|
||||||
|
### 2.1 Secret file (honey-config.properties)
|
||||||
|
|
||||||
|
Backend reads **`/run/secrets/honey-config.properties`** (see `ConfigLoader` and `docker-compose.prod.yml`). Create it from the template; **do not commit real values**.
|
||||||
|
|
||||||
|
On the VPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /run/secrets
|
||||||
|
sudo cp /opt/app/backend/honey-config.properties.template /run/secrets/honey-config.properties
|
||||||
|
sudo chmod 640 /run/secrets/honey-config.properties
|
||||||
|
sudo chown root:docker /run/secrets/honey-config.properties # if your user is in docker group, or root:$USER
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit and set real values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /run/secrets/honey-config.properties
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- `SPRING_DATASOURCE_URL` - set to new DB URL
|
||||||
|
- `SPRING_DATASOURCE_PASSWORD` - just generate new secret
|
||||||
|
- `TELEGRAM_BOT_TOKEN` - token for Telegram bot
|
||||||
|
- `FRONTEND_URL` - put new domain here
|
||||||
|
- `APP_ADMIN_JWT_SECRET` - generate new secret using `openssl rand -base64 48` on VPS and put here
|
||||||
|
- `APP_TELEGRAM_WEBHOOK_TOKEN` - generate a new secret and set it using `POST https://api.telegram.org/bot<token>/setWebhook?url=https://<domain>/api/telegram/webhook/<secret>&max_connections=100`
|
||||||
|
- `PMA_ABSOLUTE_URI` - generate a new secret and set it. Don't forget to set the same to nginx
|
||||||
|
|
||||||
|
Create 2 files `admin_api_url` and `admin_base_path` with URL and secret path in `/run/secrets` folder.
|
||||||
|
|
||||||
|
### 2.3 Load DB password for Docker Compose
|
||||||
|
|
||||||
|
`docker-compose.prod.yml` expects `DB_ROOT_PASSWORD` (and MySQL healthcheck uses it). The repo has `scripts/load-db-password.sh` which reads the secret file; it’s currently wired to **lottery** path. For Honey, either:
|
||||||
|
|
||||||
|
- Edit `scripts/load-db-password.sh` and set:
|
||||||
|
- `SECRET_FILE="/run/secrets/honey-config.properties"`
|
||||||
|
- Or create a small wrapper that exports the same variables from `honey-config.properties`.
|
||||||
|
|
||||||
|
**When you need to source it:** Only for one-off manual `docker compose` runs (e.g. first-time start in §2.6, or starting phpMyAdmin in §4.1). You do **not** need to source it for deployment: `scripts/rolling-update.sh` loads the password from the secret file automatically when `DB_ROOT_PASSWORD` is not set.
|
||||||
|
|
||||||
|
### 2.4 Logging (logback) and config dir
|
||||||
|
|
||||||
|
Backend uses an external **logback** config so you can change log level without rebuilding. Create the config dir and put `logback-spring.xml` there:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /opt/app/backend/config
|
||||||
|
mkdir -p /opt/app/logs
|
||||||
|
```
|
||||||
|
|
||||||
|
Either copy from the JAR or from source:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From backend dir
|
||||||
|
cp src/main/resources/logback-spring.xml /opt/app/backend/config/
|
||||||
|
# or extract from built JAR:
|
||||||
|
# unzip -p target/honey-be-*.jar BOOT-INF/classes/logback-spring.xml > /opt/app/backend/config/logback-spring.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional: run the existing setup script (it may still reference lottery paths; adjust or run the copy above):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/app/backend
|
||||||
|
./scripts/setup-logging.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit log level at any time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano /opt/app/backend/config/logback-spring.xml
|
||||||
|
# e.g. change <logger name="com.honey" level="INFO"/> to DEBUG
|
||||||
|
# Logback rescans periodically (e.g. 30s); no restart needed if scan is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5 MySQL my.cnf (optional)
|
||||||
|
|
||||||
|
If you use a custom MySQL config in prod (e.g. for buffer pool):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create /opt/app/mysql/conf/my.cnf with your tuning; then in docker-compose.prod.yml
|
||||||
|
# the volume is already: /opt/app/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.6 First start (backend + DB only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/app/backend
|
||||||
|
source scripts/load-db-password.sh
|
||||||
|
docker compose -f docker-compose.prod.yml up -d db
|
||||||
|
# wait for DB healthy
|
||||||
|
docker compose -f docker-compose.prod.yml up -d backend
|
||||||
|
```
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps
|
||||||
|
curl -s http://127.0.0.1:8080/actuator/health/readiness
|
||||||
|
```
|
||||||
|
|
||||||
|
Backend should listen only on `127.0.0.1:8080` (Nginx will proxy to it). Do **not** expose 8080 to the internet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Nginx
|
||||||
|
|
||||||
|
### 3.1 Split config (like your lottery VPS)
|
||||||
|
|
||||||
|
- **Main config:** `/etc/nginx/nginx.conf` (includes sites, worker settings, etc.)
|
||||||
|
- **Site config:** `/etc/nginx/sites-enabled/your-domain` (or `your-domain.conf`) for the Honey server block.
|
||||||
|
|
||||||
|
So you have two files as on lottery: one global, one site.
|
||||||
|
|
||||||
|
### 3.2 Site config (HTTPS, API, frontend, admin, avatars)
|
||||||
|
|
||||||
|
Create a site config (e.g. `honey.yourdomain.com` or same domain as lottery). Example path: `/etc/nginx/sites-available/honey.conf` and symlink in `sites-enabled`.
|
||||||
|
|
||||||
|
- **Frontend:** root `/opt/app/frontend/dist` (SPA; `try_files` to `index.html`).
|
||||||
|
- **Admin panel:** root `/opt/app/admin-panel` (or a location like `/admin` pointing there).
|
||||||
|
- **API:** `location /api/` proxy to `http://127.0.0.1:8080`.
|
||||||
|
- **WebSocket:** `location /ws` proxy to `http://127.0.0.1:8080` with upgrade headers.
|
||||||
|
- **Avatars:** `location /avatars/` alias `/opt/app/data/avatars/`.
|
||||||
|
- **phpMyAdmin:** e.g. `location /pma/` or a secret path proxy to `http://127.0.0.1:8081` (see below).
|
||||||
|
|
||||||
|
Use the repo’s **`nginx.conf.template`** as reference; adapt server_name, SSL paths, and add an admin location. Example skeleton:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# Upstream for backend (same as template)
|
||||||
|
upstream backend {
|
||||||
|
server 127.0.0.1:8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name your-domain.com;
|
||||||
|
location /.well-known/acme-challenge/ { root /var/www/certbot; }
|
||||||
|
location / { return 301 https://$host$request_uri; }
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name your-domain.com;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||||
|
|
||||||
|
root /opt/app/frontend/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://backend;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://backend;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_read_timeout 7d;
|
||||||
|
proxy_send_timeout 7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /avatars/ {
|
||||||
|
alias /opt/app/data/avatars/;
|
||||||
|
expires 1h;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Admin panel (e.g. secret path)
|
||||||
|
location /your-secret-admin-path/ {
|
||||||
|
alias /opt/app/admin-panel/;
|
||||||
|
try_files $uri $uri/ /your-secret-admin-path/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# phpMyAdmin (secret path, optional)
|
||||||
|
location /your-secret-pma-path/ {
|
||||||
|
proxy_pass http://127.0.0.1:8081/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable and test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ln -s /etc/nginx/sites-available/honey.conf /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 SSL (Let’s Encrypt)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx -d your-domain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Certbot will adjust the server block for certificates. Reload Nginx if needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. phpMyAdmin
|
||||||
|
|
||||||
|
### 4.1 Start phpMyAdmin container
|
||||||
|
|
||||||
|
`docker-compose.prod.yml` already defines a **phpmyadmin** service (port 8081, same network as `db`). Start it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/app/backend
|
||||||
|
source scripts/load-db-password.sh
|
||||||
|
docker compose -f docker-compose.prod.yml up -d phpmyadmin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Access via Nginx (recommended)
|
||||||
|
|
||||||
|
Do **not** expose 8081 publicly. Proxy it via Nginx under a secret path (e.g. `/your-secret-pma-path/`), as in the example above. Set `PMA_ABSOLUTE_URI` in the secret file so phpMyAdmin generates correct URLs:
|
||||||
|
|
||||||
|
In `/run/secrets/honey-config.properties` add (or use env when running compose):
|
||||||
|
|
||||||
|
```properties
|
||||||
|
PMA_ABSOLUTE_URI=https://your-domain.com/your-secret-pma-path/
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reload Nginx and open `https://your-domain.com/your-secret-pma-path/`. Login: user `root`, password = `SPRING_DATASOURCE_PASSWORD` from the same secret file.
|
||||||
|
|
||||||
|
### 4.3 Optional: UFW for phpMyAdmin
|
||||||
|
|
||||||
|
If you ever expose 8081 temporarily, restrict it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ufw allow from YOUR_IP to any port 8081
|
||||||
|
sudo ufw reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Prefer keeping 8081 bound to 127.0.0.1 and using only Nginx proxy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Frontend (honey-fe)
|
||||||
|
|
||||||
|
### 5.1 Build locally and upload
|
||||||
|
|
||||||
|
On your machine (e.g. in `honey-test-fe` or your honey-fe repo):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd honey-test-fe # or honey-fe
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
scp -r dist/* root@YOUR_VPS_IP:/opt/app/frontend/dist/
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with rsync:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rsync -avz dist/ root@YOUR_VPS_IP:/opt/app/frontend/dist/
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure the app’s API base URL is correct for production (e.g. relative `""` or `VITE_API_BASE_URL` for your domain).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Admin panel (honey-admin)
|
||||||
|
|
||||||
|
### 6.1 Build with secret (on VPS or locally)
|
||||||
|
|
||||||
|
Admin often has a build that injects a public URL or env. From the repo:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd honey-admin
|
||||||
|
npm install
|
||||||
|
npm run build:with-secret
|
||||||
|
```
|
||||||
|
|
||||||
|
Then copy the built output to the Nginx admin root:
|
||||||
|
|
||||||
|
**If you build on the VPS:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/app/admin/honey-admin
|
||||||
|
npm run build:with-secret
|
||||||
|
cp -r dist/* /opt/app/admin-panel/
|
||||||
|
```
|
||||||
|
|
||||||
|
**If you build locally:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp -r dist/* root@YOUR_VPS_IP:/opt/app/admin-panel/
|
||||||
|
```
|
||||||
|
|
||||||
|
The Nginx location for admin (e.g. `/your-secret-admin-path/`) must serve this directory and support SPA routing (`try_files` to `index.html`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Rolling backend updates
|
||||||
|
|
||||||
|
Use the existing **rolling-update** script so Nginx switches to a new backend container with no downtime.
|
||||||
|
|
||||||
|
### 7.1 Script adaptation for Honey
|
||||||
|
|
||||||
|
The script in the repo may still reference **lottery** container names and Nginx paths. For Honey:
|
||||||
|
|
||||||
|
- **Containers:** `honey-backend` (primary), `honey-backend-new` (standby).
|
||||||
|
- **Nginx:** same idea as lottery: one upstream `backend` with `server 127.0.0.1:8080` and optionally `server 127.0.0.1:8082 backup;`. The script flips which port is primary.
|
||||||
|
|
||||||
|
Edit `scripts/rolling-update.sh` and replace:
|
||||||
|
|
||||||
|
- `lottery-backend` → `honey-backend`
|
||||||
|
- `lottery-backend-new` → `honey-backend-new`
|
||||||
|
|
||||||
|
The script auto-detects Nginx config from paths like `/etc/nginx/sites-enabled/win-spin.live`. For Honey, either:
|
||||||
|
|
||||||
|
- Symlink or name your site config so the script finds it (e.g. add a similar check for `honey.conf` in the script), or
|
||||||
|
- Set the path explicitly before running: `export NGINX_CONF=/etc/nginx/sites-enabled/your-domain && sudo ./scripts/rolling-update.sh`
|
||||||
|
|
||||||
|
### 7.2 Run rolling update
|
||||||
|
|
||||||
|
From the backend directory, run (no need to source `load-db-password.sh` — the script does it):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/app/backend
|
||||||
|
chmod +x scripts/rolling-update.sh
|
||||||
|
sudo ./scripts/rolling-update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script loads `DB_ROOT_PASSWORD` from the secret file if not set, then: builds the new image, starts `backend-new` on 8082, health-checks it, points Nginx to 8082, reloads Nginx, then stops the old backend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Logging
|
||||||
|
|
||||||
|
- **App logs:** `/opt/app/logs/` (mounted into backend container; path can be set via `LOG_DIR` / logback).
|
||||||
|
- **Config:** `/opt/app/backend/config/logback-spring.xml` (edit to change level; no restart if scan is enabled).
|
||||||
|
- **Nginx:** `/var/log/nginx/access.log`, `/var/log/nginx/error.log`.
|
||||||
|
|
||||||
|
View backend logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs -f honey-backend
|
||||||
|
# or
|
||||||
|
tail -f /opt/app/logs/honey-be.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. MySQL backups to backup VPS
|
||||||
|
|
||||||
|
### 9.1 Backup script for Honey
|
||||||
|
|
||||||
|
Copy and adapt the existing **`scripts/backup-database.sh`** (or create a Honey-specific one). Set:
|
||||||
|
|
||||||
|
- `MYSQL_CONTAINER="honey-mysql"`
|
||||||
|
- `MYSQL_DATABASE="honey_db"`
|
||||||
|
- `SECRET_FILE="/run/secrets/honey-config.properties"`
|
||||||
|
- `BACKUP_FILENAME="honey_db_backup_${TIMESTAMP}.sql"` (and `.gz` if compressing)
|
||||||
|
- Remote path and retention (e.g. `BACKUP_VPS_PATH`, keep last 30 days) to match your backup server.
|
||||||
|
|
||||||
|
Ensure the script runs as root (or with sudo) so it can read `/run/secrets/honey-config.properties`, and that it uses the same `DB_PASSWORD` / `SPRING_DATASOURCE_PASSWORD` as in the secret file.
|
||||||
|
|
||||||
|
### 9.2 SSH key to backup VPS
|
||||||
|
|
||||||
|
On the Honey VPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-keygen -t ed25519 -C "backup@honey-vps" -f ~/.ssh/backup_key
|
||||||
|
ssh-copy-id -i ~/.ssh/backup_key.pub user@BACKUP_VPS_IP
|
||||||
|
```
|
||||||
|
|
||||||
|
Test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -i ~/.ssh/backup_key user@BACKUP_VPS_IP "echo OK"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 Cron (daily at 2 AM)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo crontab -e
|
||||||
|
```
|
||||||
|
|
||||||
|
Add:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 2 * * * /opt/app/backend/scripts/backup-database.sh >> /opt/app/logs/backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the Honey-adapted backup script path and ensure `backup-database.sh` uses `honey_db` and `honey-mysql`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Quick reference
|
||||||
|
|
||||||
|
| Item | Honey |
|
||||||
|
|------|--------|
|
||||||
|
| **App root** | `/opt/app` |
|
||||||
|
| **Backend code** | `/opt/app/backend` (honey-be) |
|
||||||
|
| **Frontend static** | `/opt/app/frontend/dist` (honey-fe build) |
|
||||||
|
| **Admin static** | `/opt/app/admin-panel` (honey-admin build) |
|
||||||
|
| **Secret file** | `/run/secrets/honey-config.properties` |
|
||||||
|
| **Logs** | `/opt/app/logs` (+ logback config in `/opt/app/backend/config`) |
|
||||||
|
| **Avatars** | `/opt/app/data/avatars` |
|
||||||
|
| **Nginx** | `/etc/nginx/nginx.conf` + `/etc/nginx/sites-enabled/your-domain` |
|
||||||
|
| **DB container** | `honey-mysql` |
|
||||||
|
| **DB name** | `honey_db` |
|
||||||
|
| **Backend containers** | `honey-backend`, `honey-backend-new` (rolling) |
|
||||||
|
| **phpMyAdmin** | Container `honey-phpmyadmin`, port 8081 → proxy via Nginx secret path |
|
||||||
|
|
||||||
|
### Deploy commands (summary)
|
||||||
|
|
||||||
|
- **Backend (rolling):**
|
||||||
|
`cd /opt/app/backend && chmod +x scripts/rolling-update.sh && sudo ./scripts/rolling-update.sh`
|
||||||
|
(Password is loaded from the secret file inside the script.)
|
||||||
|
|
||||||
|
- **Frontend:**
|
||||||
|
Local: `npm run build` then `scp -r dist/* root@VPS:/opt/app/frontend/dist/`
|
||||||
|
|
||||||
|
- **Admin:**
|
||||||
|
On VPS: `cd /opt/app/admin/honey-admin && npm run build:with-secret && cp -r dist/* /opt/app/admin-panel/`
|
||||||
|
Or build locally and `scp -r dist/* root@VPS:/opt/app/admin-panel/`
|
||||||
|
|
||||||
|
- **Log level:**
|
||||||
|
Edit `/opt/app/backend/config/logback-spring.xml` (no restart if scan enabled).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Checklist after setup
|
||||||
|
|
||||||
|
- [ ] `/opt/app` structure created; ownership and permissions correct.
|
||||||
|
- [ ] `/run/secrets/honey-config.properties` created and filled (no placeholders).
|
||||||
|
- [ ] `load-db-password.sh` (and backup/rolling scripts) use Honey secret path and container/db names.
|
||||||
|
- [ ] Backend + DB + phpMyAdmin start; health check returns 200.
|
||||||
|
- [ ] Nginx site config in place; `nginx -t` OK; HTTPS works.
|
||||||
|
- [ ] Frontend and admin builds deployed to `/opt/app/frontend/dist` and `/opt/app/admin-panel`.
|
||||||
|
- [ ] API and WebSocket work through Nginx; avatars and admin paths load.
|
||||||
|
- [ ] phpMyAdmin reachable only via Nginx secret path; 8081 not public.
|
||||||
|
- [ ] Rolling update script updated for `honey-backend` / `honey-backend-new` and tested.
|
||||||
|
- [ ] Backup script adapted for `honey_db` / `honey-mysql`; cron runs and backups appear on backup VPS.
|
||||||
|
- [ ] Logs under `/opt/app/logs` and logback config under `/opt/app/backend/config`; log level change works.
|
||||||
|
|
||||||
|
This gives you the same layout and workflow as your lottery VPS, but for Honey (honey-be, honey-fe, honey-admin) with Nginx, phpMyAdmin, logging, and backups.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
# This ensures DB_PASSWORD and DB_ROOT_PASSWORD match SPRING_DATASOURCE_PASSWORD
|
# This ensures DB_PASSWORD and DB_ROOT_PASSWORD match SPRING_DATASOURCE_PASSWORD
|
||||||
# Usage: source ./load-db-password.sh
|
# Usage: source ./load-db-password.sh
|
||||||
|
|
||||||
SECRET_FILE="/run/secrets/lottery-config.properties"
|
SECRET_FILE="/run/secrets/honey-config.properties"
|
||||||
|
|
||||||
if [ ! -f "$SECRET_FILE" ]; then
|
if [ ! -f "$SECRET_FILE" ]; then
|
||||||
echo "❌ Error: Secret file not found at $SECRET_FILE"
|
echo "❌ Error: Secret file not found at $SECRET_FILE"
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ if [ -z "$NGINX_CONF" ]; then
|
|||||||
elif [ -f "/etc/nginx/sites-enabled/win-spin.live.conf" ]; then
|
elif [ -f "/etc/nginx/sites-enabled/win-spin.live.conf" ]; then
|
||||||
NGINX_CONF="/etc/nginx/sites-enabled/win-spin.live.conf"
|
NGINX_CONF="/etc/nginx/sites-enabled/win-spin.live.conf"
|
||||||
log "Using Nginx config: $NGINX_CONF (sites-enabled - active config)"
|
log "Using Nginx config: $NGINX_CONF (sites-enabled - active config)"
|
||||||
elif [ -f "/etc/nginx/conf.d/lottery.conf" ]; then
|
elif [ -f "/etc/nginx/conf.d/honey.conf" ]; then
|
||||||
NGINX_CONF="/etc/nginx/conf.d/lottery.conf"
|
NGINX_CONF="/etc/nginx/conf.d/honey.conf"
|
||||||
log "Using Nginx config: $NGINX_CONF (conf.d)"
|
log "Using Nginx config: $NGINX_CONF (conf.d)"
|
||||||
elif [ -f "/opt/app/nginx/win-spin.live.conf" ]; then
|
elif [ -f "/opt/app/nginx/win-spin.live.conf" ]; then
|
||||||
warn "Found config at /opt/app/nginx/win-spin.live.conf"
|
warn "Found config at /opt/app/nginx/win-spin.live.conf"
|
||||||
@@ -74,7 +74,7 @@ if [ -z "$NGINX_CONF" ]; then
|
|||||||
error "Searched:"
|
error "Searched:"
|
||||||
error " - /etc/nginx/sites-enabled/win-spin.live"
|
error " - /etc/nginx/sites-enabled/win-spin.live"
|
||||||
error " - /etc/nginx/sites-enabled/win-spin.live.conf"
|
error " - /etc/nginx/sites-enabled/win-spin.live.conf"
|
||||||
error " - /etc/nginx/conf.d/lottery.conf"
|
error " - /etc/nginx/conf.d/honey.conf"
|
||||||
error " - /opt/app/nginx/win-spin.live.conf"
|
error " - /opt/app/nginx/win-spin.live.conf"
|
||||||
error ""
|
error ""
|
||||||
error "Please set NGINX_CONF environment variable with the correct path."
|
error "Please set NGINX_CONF environment variable with the correct path."
|
||||||
@@ -101,15 +101,15 @@ detect_active_backend() {
|
|||||||
# Port 8082 is active (not backup)
|
# Port 8082 is active (not backup)
|
||||||
ACTIVE_PORT=8082
|
ACTIVE_PORT=8082
|
||||||
STANDBY_PORT=8080
|
STANDBY_PORT=8080
|
||||||
ACTIVE_CONTAINER="lottery-backend-new"
|
ACTIVE_CONTAINER="honey-backend-new"
|
||||||
STANDBY_CONTAINER="lottery-backend"
|
STANDBY_CONTAINER="honey-backend"
|
||||||
log "Detected: Port 8082 is currently active"
|
log "Detected: Port 8082 is currently active"
|
||||||
else
|
else
|
||||||
# Port 8080 is active (default or only one present)
|
# Port 8080 is active (default or only one present)
|
||||||
ACTIVE_PORT=8080
|
ACTIVE_PORT=8080
|
||||||
STANDBY_PORT=8082
|
STANDBY_PORT=8082
|
||||||
ACTIVE_CONTAINER="lottery-backend"
|
ACTIVE_CONTAINER="honey-backend"
|
||||||
STANDBY_CONTAINER="lottery-backend-new"
|
STANDBY_CONTAINER="honey-backend-new"
|
||||||
log "Detected: Port 8080 is currently active"
|
log "Detected: Port 8080 is currently active"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -230,10 +230,10 @@ start_new_container() {
|
|||||||
# Determine which service to start based on standby port
|
# Determine which service to start based on standby port
|
||||||
if [ "$STANDBY_PORT" = "8082" ]; then
|
if [ "$STANDBY_PORT" = "8082" ]; then
|
||||||
SERVICE_NAME="backend-new"
|
SERVICE_NAME="backend-new"
|
||||||
CONTAINER_NAME="lottery-backend-new"
|
CONTAINER_NAME="honey-backend-new"
|
||||||
else
|
else
|
||||||
SERVICE_NAME="backend"
|
SERVICE_NAME="backend"
|
||||||
CONTAINER_NAME="lottery-backend"
|
CONTAINER_NAME="honey-backend"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if standby container exists (running or stopped)
|
# Check if standby container exists (running or stopped)
|
||||||
@@ -288,9 +288,9 @@ health_check_new_container() {
|
|||||||
|
|
||||||
# First, check if container is still running
|
# First, check if container is still running
|
||||||
if [ "$STANDBY_PORT" = "8082" ]; then
|
if [ "$STANDBY_PORT" = "8082" ]; then
|
||||||
local container_name="lottery-backend-new"
|
local container_name="honey-backend-new"
|
||||||
else
|
else
|
||||||
local container_name="lottery-backend"
|
local container_name="honey-backend"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
|
if ! docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
|
||||||
@@ -486,7 +486,7 @@ stop_old_container() {
|
|||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
if [ "$ACTIVE_CONTAINER" = "lottery-backend-new" ]; then
|
if [ "$ACTIVE_CONTAINER" = "honey-backend-new" ]; then
|
||||||
if $DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update stop backend-new; then
|
if $DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update stop backend-new; then
|
||||||
log "✅ Old backend container stopped"
|
log "✅ Old backend container stopped"
|
||||||
else
|
else
|
||||||
@@ -501,7 +501,7 @@ stop_old_container() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Optionally remove the old container (comment out if you want to keep it for rollback)
|
# Optionally remove the old container (comment out if you want to keep it for rollback)
|
||||||
# if [ "$ACTIVE_CONTAINER" = "lottery-backend-new" ]; then
|
# if [ "$ACTIVE_CONTAINER" = "honey-backend-new" ]; then
|
||||||
# docker-compose -f "$COMPOSE_FILE" --profile rolling-update rm -f backend-new
|
# docker-compose -f "$COMPOSE_FILE" --profile rolling-update rm -f backend-new
|
||||||
# else
|
# else
|
||||||
# docker-compose -f "$COMPOSE_FILE" rm -f backend
|
# docker-compose -f "$COMPOSE_FILE" rm -f backend
|
||||||
@@ -535,22 +535,22 @@ rollback() {
|
|||||||
if [ "$STANDBY_PORT" = "8082" ]; then
|
if [ "$STANDBY_PORT" = "8082" ]; then
|
||||||
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update stop backend-new || true
|
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update stop backend-new || true
|
||||||
warn ""
|
warn ""
|
||||||
warn "Container 'lottery-backend-new' is STOPPED but NOT REMOVED"
|
warn "Container 'honey-backend-new' is STOPPED but NOT REMOVED"
|
||||||
warn ""
|
warn ""
|
||||||
warn "To check logs:"
|
warn "To check logs:"
|
||||||
warn " docker logs lottery-backend-new"
|
warn " docker logs honey-backend-new"
|
||||||
warn " docker logs --tail 100 lottery-backend-new"
|
warn " docker logs --tail 100 honey-backend-new"
|
||||||
warn ""
|
warn ""
|
||||||
warn "To remove manually:"
|
warn "To remove manually:"
|
||||||
warn " $DOCKER_COMPOSE_CMD -f $COMPOSE_FILE --profile rolling-update rm -f backend-new"
|
warn " $DOCKER_COMPOSE_CMD -f $COMPOSE_FILE --profile rolling-update rm -f backend-new"
|
||||||
else
|
else
|
||||||
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" stop backend || true
|
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" stop backend || true
|
||||||
warn ""
|
warn ""
|
||||||
warn "Container 'lottery-backend' is STOPPED but NOT REMOVED"
|
warn "Container 'honey-backend' is STOPPED but NOT REMOVED"
|
||||||
warn ""
|
warn ""
|
||||||
warn "To check logs:"
|
warn "To check logs:"
|
||||||
warn " docker logs lottery-backend"
|
warn " docker logs honey-backend"
|
||||||
warn " docker logs --tail 100 lottery-backend"
|
warn " docker logs --tail 100 honey-backend"
|
||||||
warn ""
|
warn ""
|
||||||
warn "To remove manually:"
|
warn "To remove manually:"
|
||||||
warn " $DOCKER_COMPOSE_CMD -f $COMPOSE_FILE rm -f backend"
|
warn " $DOCKER_COMPOSE_CMD -f $COMPOSE_FILE rm -f backend"
|
||||||
@@ -568,7 +568,7 @@ rollback() {
|
|||||||
|
|
||||||
# Start old container if it was stopped
|
# Start old container if it was stopped
|
||||||
if ! docker ps --format '{{.Names}}' | grep -q "^${ACTIVE_CONTAINER}$"; then
|
if ! docker ps --format '{{.Names}}' | grep -q "^${ACTIVE_CONTAINER}$"; then
|
||||||
if [ "$ACTIVE_CONTAINER" = "lottery-backend-new" ]; then
|
if [ "$ACTIVE_CONTAINER" = "honey-backend-new" ]; then
|
||||||
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update start backend-new || \
|
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update start backend-new || \
|
||||||
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update up -d backend-new
|
$DOCKER_COMPOSE_CMD -f "$COMPOSE_FILE" --profile rolling-update up -d backend-new
|
||||||
else
|
else
|
||||||
@@ -614,7 +614,7 @@ main() {
|
|||||||
log "To rollback (if needed):"
|
log "To rollback (if needed):"
|
||||||
log " 1. Restore Nginx config: cp $NGINX_CONF_BACKUP $NGINX_CONF"
|
log " 1. Restore Nginx config: cp $NGINX_CONF_BACKUP $NGINX_CONF"
|
||||||
log " 2. Reload Nginx: systemctl reload nginx"
|
log " 2. Reload Nginx: systemctl reload nginx"
|
||||||
if [ "$ACTIVE_CONTAINER" = "lottery-backend-new" ]; then
|
if [ "$ACTIVE_CONTAINER" = "honey-backend-new" ]; then
|
||||||
log " 3. Start old backend: docker-compose -f $COMPOSE_FILE --profile rolling-update start backend-new"
|
log " 3. Start old backend: docker-compose -f $COMPOSE_FILE --profile rolling-update start backend-new"
|
||||||
log " 4. Stop new backend: docker-compose -f $COMPOSE_FILE stop backend"
|
log " 4. Stop new backend: docker-compose -f $COMPOSE_FILE stop backend"
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user