qOntology Service Deployment
Before continuing, complete middleware deployment and data initialization, and prepare the JAR and frontend files from application build. Run these commands on the Ubuntu 22.04 x86_64 runtime server.
1. Prepare directories and the service user
The staging directory should look like this. Frontend files belong directly under web/, without another dist/ level:
~/qontology-release/
├── qontology-server.jar
└── web/
├── index.html
└── …For a first deployment, run:
# Check that the backend JAR and frontend entry file exist and are nonempty
test -s "$HOME/qontology-release/qontology-server.jar"
test -s "$HOME/qontology-release/web/index.html"
# Create a service user and matching group, with interactive login disabled
sudo useradd --system --user-group --home-dir /var/lib/qontology --shell /usr/sbin/nologin qontology
# Create deployment directories; root manages config, and the service user can write data/logs
sudo install -d -m 755 /opt/qontology /opt/qontology/server /opt/qontology/web
sudo install -d -o root -g qontology -m 750 /opt/qontology/config
sudo install -d -o qontology -g qontology -m 750 /var/lib/qontology /var/lib/qontology/upload /var/log/qontology
# Copy backend/frontend artifacts and set readable frontend directory/file permissions
sudo install -m 644 "$HOME/qontology-release/qontology-server.jar" /opt/qontology/server/
sudo cp -R "$HOME/qontology-release/web/." /opt/qontology/web/
sudo find /opt/qontology/web -type d -exec chmod 755 {} +
sudo find /opt/qontology/web -type f -exec chmod 644 {} +
# Link the application's logs directory to the shared log location
sudo ln -s /var/log/qontology /opt/qontology/server/logsThe source Logback configuration writes to logs/ under the working directory, so it is linked to /var/log/qontology/. If a logs file or directory already exists, inspect it instead of forcing the link. The service user needs write access only to data and logs; deployment administrators maintain the JAR, frontend, and configuration.
2. Configure the backend
2.1. External configuration loading
The bundled application.yml imports production and module configurations for AI, file storage, system services, graph databases, and others. Start with:
--spring.profiles.active=prod
--spring.config.additional-location=file:/opt/qontology/config/deploy.ymlKeep the bundled configuration as the baseline and override local deployment values in deploy.yml. Do not replace spring.config.location with a small file containing only connection details, or assume that an external YAML file with the same module name replaces a bundled classpath: import. Spring Boot external configuration
2.2. Write deployment overrides
Run sudoedit /opt/qontology/config/deploy.yml and write the following. Use the passwords set in earlier steps. Inside YAML single-quoted strings, escape a single quote by doubling it. Generate <RANDOM_SIGNING_SECRET> with openssl rand -hex 32 and insert the result; do not leave placeholders.
server:
address: 127.0.0.1
port: 8097
forward-headers-strategy: framework
qontology:
profile: /var/lib/qontology/upload/
ai:
enabled: true
vector-store: memory
datasource:
type: mysql
spring:
data:
redis:
host: 127.0.0.1
port: 6379
database: 3
password: '<REDIS_PASSWORD>'
datasource:
druid:
stat-view-servlet:
enabled: false
dynamic:
primary: master
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: 'jdbc:mysql://127.0.0.1:3306/qontology?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai'
username: qontology
password: '<MYSQL_APP_PASSWORD>'
graphis:
type: neo4j
neo4j:
uri: bolt://127.0.0.1:7687
user: neo4j
password: '<NEO4J_PASSWORD>'
dromara:
x-file-storage:
default-platform: local
local-plus:
- platform: local
enable-storage: true
enable-access: false
domain: ''
path-patterns: /**
base-path: /
storage-path: /var/lib/qontology/upload/
aliyun-oss:
- platform: unused-oss
enable-storage: false
access-key: ''
secret-key: ''
end-point: ''
bucket-name: ''
domain: ''
token:
secret: '<RANDOM_SIGNING_SECRET>'
user:
password:
universalPassword: ''
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
knife4j:
enable: falseThis directly overrides spring.datasource.dynamic.datasource.master so the bundled example database address is not reused. Neo4j uses the project's top-level neo4j.uri/user/password, not a separate spring.neo4j configuration.
File storage keeps relative addresses. qontology.profile and storage-path point to the same upload directory. The file service generates URLs under /profile/, so that route is also proxied below. server.forward-headers-strategy works with Nginx forwarding headers to retain the external host and port 8897 in generated file URLs.
The example disables unconfigured OSS, the built-in universal login password, and API documentation pages. AI stays enabled with memory vector storage so basic deployment does not depend on external Weaviate. In-memory vectors are lost on restart, and model calls still require valid models and keys. For persistence, configure qontology.ai.weaviate; do not copy bundled example addresses unchanged.
After saving, restrict configuration permissions:
# Set ownership and permissions: root can edit; the service group can read
sudo chown root:qontology /opt/qontology/config/deploy.yml
sudo chmod 640 /opt/qontology/config/deploy.yml
# Check configuration readability and upload-directory writability as the service user
sudo -u qontology test -r /opt/qontology/config/deploy.yml
sudo -u qontology test -w /var/lib/qontology/upload3. Start qOntology API
3.1. Configure systemd
Run sudoedit /etc/systemd/system/qontology.service:
[Unit]
Description=qOntology API
Wants=network-online.target
After=network-online.target mysql57.service redis-server.service neo4j.service
[Service]
Type=simple
User=qontology
Group=qontology
WorkingDirectory=/opt/qontology/server
Environment=JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -Xms512m -Xmx2g -Dfile.encoding=UTF-8 -jar /opt/qontology/server/qontology-server.jar --spring.profiles.active=prod --spring.config.additional-location=file:/opt/qontology/config/deploy.yml
Restart=on-failure
RestartSec=10
TimeoutStopSec=120
UMask=0027
[Install]
WantedBy=multi-user.targetAfter defines startup order only; it does not guarantee that databases are ready for connections. Complete middleware checks before the first startup. The Java heap limit is not the API process's total memory requirement.
3.2. Start and check
# Reload service definitions, start the API, and enable startup at boot
sudo systemctl daemon-reload
sudo systemctl enable --now qontology
# Inspect service status and recent startup logs
sudo systemctl status qontology --no-pager
sudo journalctl -u qontology -n 100 --no-pager
# Check the API listening port and CAPTCHA endpoint response
sudo ss -lntp | grep ':8097'
curl -sS http://127.0.0.1:8097/captchaImageConfirm prod is active, the port is 8097, and there are no database, Redis, Neo4j authentication, or configuration-loading errors. The CAPTCHA endpoint should return application JSON; interpret it according to the current version. An open port alone is not sufficient proof of startup. Logs default to /var/log/qontology/; startup exceptions also appear in journal.
4. Deploy Nginx and the frontend
4.1. Install and configure the site
# Install Nginx and check its version
sudo apt install -y nginx
nginx -v
# Edit this site's configuration using the example below
sudoedit /etc/nginx/sites-available/qontologyWrite this site configuration. Ubuntu's default sites-enabled loads it inside the http context; do not replace the entire /etc/nginx/nginx.conf:
server {
listen 8897;
server_name _;
root /opt/qontology/web;
index index.html;
client_max_body_size 100m;
location / {
try_files $uri $uri/ /index.html;
}
location /prod-api/ {
proxy_pass http://127.0.0.1:8097/;
proxy_set_header Host $http_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_read_timeout 600s;
}
location /websocket/ {
proxy_pass http://127.0.0.1:8097;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
location /profile/ {
proxy_pass http://127.0.0.1:8097;
proxy_set_header Host $http_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;
}
location /kkfileview/ {
proxy_pass http://127.0.0.1:8012;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
}The trailing / in proxy_pass for /prod-api/ removes that prefix; the other three routes preserve their paths. /profile/ forwards to existing file-resource handling rather than exposing the whole application or configuration directory as static files. Align upload limits across Nginx, the API, and previews; the entry limit here is 100 MB.
4.2. Enable and verify
# Enable the site and validate Nginx configuration syntax
sudo ln -s /etc/nginx/sites-available/qontology /etc/nginx/sites-enabled/qontology
sudo nginx -t
# After validation, start Nginx, enable startup at boot, and load the site configuration
sudo systemctl enable --now nginx
sudo systemctl reload nginx
# Check the home page and business API through the shared entry point
curl -I http://127.0.0.1:8897/
curl -sS http://127.0.0.1:8897/prod-api/captchaImageIf the link already exists, check its target rather than creating it again. Fix any nginx -t failure before reloading. Allow TCP 8897 only for intended clients in the firewall or cloud security group; keep internal database and middleware ports private.
5. Access and functional checks
Open http://<SERVER_IP>:8897 in the browser. Obtain login credentials and the initial password from the matching release notes or delivery records; change the initial password after first login.
| Check | Action and expected result |
|---|---|
| Page resources | Login page renders, JS/CSS have no 404s, and business pages still work after refresh |
| Business API | /prod-api/ returns application responses, not Nginx 502 or frontend HTML |
| Login and permissions | A valid account can log in; menus and authorized pages load correctly |
| Graph database | Authorized graph queries connect and authenticate successfully; no demo nodes is normal for an empty graph |
| WebSocket | Inspect actual /websocket/ requests; the handshake succeeds and the connection persists |
| File access | Upload a test file; its URL uses the actual site's /profile/ and respects application access rules |
| File preview | Test PDF and Office files; preview pages and converted resources load under /kkfileview/ |
The preview service must fetch the file URL returned by the upload API from the server side. Run curl -I 'ACTUAL_FILE_URL' on the runtime server to check routing and reachability. URLs must not retain container service names, development addresses, or wrong ports. If a file requires authentication, pass authorization according to this version's preview mechanism or provide controlled file access. A browser login does not imply kkFileView can download the file.
AI extraction, question answering, and vector retrieval also need model configuration and credentials. Basic page access does not prove those capabilities work. This example installs neither a local model nor Weaviate, and requires no local GPU.
6. Routine operations and troubleshooting
At startup, check MySQL, Redis, and Neo4j first, then start the API, previews, and entry point:
# Start the relational database, cache, and graph database first
sudo systemctl start mysql57 redis-server neo4j
# Continue after completing the connection checks on the preceding pages
sudo systemctl start qontology kkfileview nginxFor maintenance, stop the application entry point and services before the data services. This command assumes Nginx is dedicated to this deployment. If it hosts other sites, maintain only this site:
# Stop the entry point, API, and preview service first
sudo systemctl stop nginx qontology kkfileview
# After the application stops, stop graph, cache, and relational services
sudo systemctl stop neo4j redis-server mysql57| Symptom | First checks |
|---|---|
| API fails to start | First journal exception, Java 17, prod profile, external-file permissions, YAML indentation |
| MySQL connection fails | Port 3306, account grants, database name, password, initialization completion |
| Redis authentication fails | Matching Redis/API passwords and logical database 3 |
| Graph connection fails | Java 17, Neo4j logs, Bolt 7687, top-level neo4j.* settings |
| Nginx 502 | API/preview startup, upstream ports, /var/log/nginx/error.log |
| Page refresh returns 404 | Frontend directory layout, assets, try_files fallback |
| WebSocket fails | Path preservation, HTTP 1.1, Upgrade/Connection headers |
| Uploaded-file URL is wrong | Forwarding headers, external port, /profile/ proxy, matching upload directories |
| Preview resource 404 | base.url, /kkfileview context, path-preserving proxy |
| Office conversion fails | LibreOffice path, fonts, service-user HOME/directory permissions, available memory |
After changing API overrides, run sudo systemctl restart qontology. Restart kkfileview after its configuration changes. Run sudo systemctl daemon-reload first after editing systemd units. Rebuild the frontend after changing its environment variables, then replace static resources.
This completes the native single-server deployment workflow. Before production operation, check backups, disk growth, and resource allocation against actual data and load. See server resource specifications. Return to the manual deployment index.
