Files
honey-be/VPS_SETUP_FROM_SCRATCH.md
Tihon 15498c8337
All checks were successful
Deploy to VPS / deploy (push) Successful in 52s
Initial setup, cleanup, VPS setup
2026-03-07 23:11:31 +02:00

15 KiB
Raw Permalink Blame History

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

sudo apt update && sudo apt upgrade -y
# 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):

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

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:

sudo mkdir -p /run/secrets
sudo cp /opt/app/backend/honey-be/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:

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; its 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.

IMPORTANT

  • Change Java memory in docker-compose.prod.yml when you know the PROD VPS characteristics.
  • Change the rolling-update.sh script to match sites-enabled nginx file name for PROD when you know the domain

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:

mkdir -p /opt/app/backend/config
mkdir -p /opt/app/logs

Either copy from the JAR or from source:

# 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):

cd /opt/app/backend/honey-be
./scripts/setup-logging.sh

Edit log level at any time:

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):

# 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

Note: on Staged VPS it has 4G RAM, so don't forget to change it for PROD accordingly.

2.6 First start (backend + DB only)

cd /opt/app/backend/honey-be
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

Note: for Staged use a separate docker compose.

Check:

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)

  • Take 2 files from already working VPS: nginx.conf and sites-enabled/<domain.com> and put to new VPS.
  • Remove or comment lines reg certificates and change 2 listen lines:
    # SSL Certificates
    ssl_certificate /etc/letsencrypt/live/testforapp.website/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/testforapp.website/privkey.pem;
    Change 'listen 443 ssl http2;' to 'listen 443;`
    Change `listen [::]:443 ssl http2;` to `listen [::]:443;`

Enable and test:

sudo ln -s /etc/nginx/sites-available/testforapp.website /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

3.3 SSL (Lets Encrypt)

sudo certbot --nginx -d testforapp.website

Certbot will adjust the server block for certificates. Reload Nginx if needed. And remove redundant ssl/listen lines from server block to not override certbot's configs.


4. phpMyAdmin

4.1 Start phpMyAdmin container

docker-compose.prod.yml already defines a phpmyadmin service (port 8081, same network as db). Start it:

cd /opt/app/backend/honey-be
source scripts/load-db-password.sh
docker compose -f docker-compose.prod.yml up -d phpmyadmin

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):

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:

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):

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:

rsync -avz dist/ root@YOUR_VPS_IP:/opt/app/frontend/dist/

Ensure the apps 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:

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:

cd /opt/app/admin/honey-admin
npm run build:with-secret
cp -r dist/* /opt/app/admin-panel/

If you build locally:

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-backendhoney-backend
  • lottery-backend-newhoney-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):

cd /opt/app/backend/honey-be
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:

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:

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:

ssh -i ~/.ssh/backup_key user@BACKUP_VPS_IP "echo OK"

9.3 Cron (daily at 2 AM)

sudo crontab -e

Add:

0 2 * * * /opt/app/backend/honey-be/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 (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/honey-be && 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.