Skip to main content

Deployment

This guide covers building and deploying LAMISPlus 3.0 to a production server.

Build

The monorepo uses Maven to build both backend and all frontend plugin bundles in a single command:

cd Lamisplus3.0
mvn clean package -DskipTests

This produces:

  • api/lamisplus-core/target/lamisplus-core-*.jar, the runnable Spring Boot JAR
  • Frontend plugin assets embedded inside each plugin JAR under src/main/resources/static/

Environment Variables

Set these before starting the application:

VariableRequiredDescription
DB_USERNAMEYesPostgreSQL username
DB_PASSWORDYesPostgreSQL password
JWT_SECRETYes256-bit base64-encoded secret for JWT signing
SERVER_PORTNoHTTP port (default: 8789)
PLUGIN_STORAGE_PATHYesPath where plugin JARs are persisted
CORS_ALLOWED_ORIGINSYesAllowed frontend origins (e.g. https://app.hospital.org)

PLUGIN_STORAGE_PATH is critical. Plugin JARs must be stored outside the Maven build output directory. If you point this to target/, mvn clean will delete all installed plugins and they must be re-uploaded. Use a stable path such as /opt/lamisplus/plugins.

Running the Backend

Direct JAR

java \
-Dspring.profiles.active=prod \
-Dplugins.storage.path=/opt/lamisplus/plugins \
-Xmx2g \
-jar api/lamisplus-core/target/lamisplus-core-*.jar

systemd Service

Create /etc/systemd/system/lamisplus.service:

[Unit]
Description=LAMISPlus 3.0
After=network.target postgresql.service

[Service]
User=lamisplus
WorkingDirectory=/opt/lamisplus
EnvironmentFile=/opt/lamisplus/.env
ExecStart=/usr/bin/java \
-Dspring.profiles.active=prod \
-Dplugins.storage.path=/opt/lamisplus/plugins \
-Xmx2g \
-jar /opt/lamisplus/lamisplus-core.jar
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
sudo systemctl enable lamisplus
sudo systemctl start lamisplus
sudo journalctl -u lamisplus -f # follow logs

nginx Reverse Proxy

Route all API and plugin asset requests through nginx:

server {
listen 443 ssl;
server_name app.hospital.org;

# Frontend SPA
root /opt/lamisplus/frontend;
index index.html;

# All API and plugin routes go to Spring Boot
location /api/ {
proxy_pass http://localhost:8789;
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;
}

# Plugin remoteEntry.js and assets served by Spring Boot
location /plugins/ {
proxy_pass http://localhost:8789;
proxy_set_header Host $host;
}

# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
}

Frontend Build

The frontend is built as part of mvn clean package (the Maven frontend plugin runs pnpm build). The Core SPA output is embedded in the JAR and served at the root.

If you need to build the frontend independently:

cd ui
pnpm build # builds all apps

Copy core/dist/ to your static file server root. Plugin assets are served by the Spring Boot backend from /plugins/{pluginId}/.

Plugin Management

Installing a Plugin

curl -X POST https://app.hospital.org/api/v1/core/plugin/admin/install \
-H "Authorization: Bearer YOUR_SUPER_ADMIN_TOKEN" \
-H "X-Tenant-Id: _system_" \
-F "file=@/path/to/plugin.jar"

Enabling a Plugin for a Tenant

curl -X POST https://app.hospital.org/api/v1/core/plugin/{pluginId}/enable \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-H "X-Tenant-Id: YOUR_TENANT_ID"

Plugin Storage Location

Installed JARs are stored in PLUGIN_STORAGE_PATH. On restart, the application automatically reloads all JARs from this directory. Ensure this directory is:

  • Readable and writable by the lamisplus service user
  • Backed up separately from the application JAR
  • Not inside the Maven target/ directory

Database

First-Time Setup

Liquibase runs migrations automatically on startup. No manual schema creation is needed beyond creating the database:

CREATE DATABASE lamisplus_db;
CREATE USER lamisplus_user WITH ENCRYPTED PASSWORD 'strong_password';
GRANT ALL PRIVILEGES ON DATABASE lamisplus_db TO lamisplus_user;

Backup

pg_dump -U lamisplus_user -d lamisplus_db -Fc -f /backups/lamisplus_$(date +%Y%m%d).dump

Health Check

# Application health
curl https://app.hospital.org/actuator/health

# Plugin status
curl https://app.hospital.org/api/v1/core/health/plugins \
-H "Authorization: Bearer TOKEN" \
-H "X-Tenant-Id: _system_"

Checklist Before Going Live

  • JWT_SECRET is a randomly generated 256-bit key, not a default or guessable value
  • DB_PASSWORD is strong and not a default value
  • PLUGIN_STORAGE_PATH points outside of target/
  • spring.profiles.active=prod is set, disables dev security config
  • Actuator endpoints heapdump, env, beans are disabled or IP-restricted in application-prod.yml
  • CORS_ALLOWED_ORIGINS is set to the specific frontend domain, not *
  • TLS/HTTPS configured on nginx
  • Database backups scheduled
  • Log rotation configured