Applications Azure

SkillTree 4.6.0 on Ubuntu 24.04 on Azure User Guide

| Product: SkillTree 4.6.0 on Ubuntu 24.04 LTS on Azure

Overview

SkillTree is a free and open source training gamification platform. You model a curriculum as projects, subjects, skills and badges, your applications report user activity to SkillTree over its REST API, and SkillTree awards points, levels and badges back and renders progress, rankings and metrics for trainees. It is designed to bolt gamified training onto an application you already have, rather than to replace it.

The cloudimg image installs SkillTree 4.6.0 from the official release artifact, pinned by SHA 256, and runs it as a Spring Boot service behind nginx with a local PostgreSQL. The Vue dashboard ships inside the same application artifact, so there is no separate frontend to deploy or keep in step.

What is included:

  • SkillTree 4.6.0 from the official release, verified by SHA 256 and installed at /opt/skilltree
  • The Vue dashboard bundled inside the same artifact and served on port 80
  • OpenJDK 21 from the Ubuntu 24.04 archive, so the runtime keeps receiving security updates
  • PostgreSQL from the Ubuntu 24.04 archive, on loopback only, tuned for a 4 GB VM
  • nginx as the only public listener, with an unauthenticated /healthz probe
  • A JVM heap pinned to -Xmx1536m so the whole stack fits Standard_B2s with no swap
  • skilltree-firstboot.service generating the administrator password, the database password and the JWT signing keystore uniquely per VM
  • A start time guard that refuses to start the service if any published example secret is in effect
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key, and a VNet with a subnet. Standard_B2s (2 vCPU, 4 GB RAM) is the tested size and runs the whole stack with roughly 2 GB of memory still available. Move to a larger size if you expect many concurrent trainees or heavy video and attachment uploads. Open port 80 on the network security group, plus 22 for SSH from your management address.

Step 1 to 3: Deploy and connect

Deploy the image from the Azure Marketplace, then connect over SSH as azureuser.

ssh azureuser@<vm-ip>

Step 4: Verify the services

SkillTree runs as a Spring Boot service behind nginx, with PostgreSQL alongside it.

sudo systemctl is-active postgresql skilltree nginx
java -version
sudo ss -tlnp | grep -E ':80 |:8080 '

PostgreSQL, SkillTree and nginx all reporting active, with OpenJDK 21 as the runtime and nginx listening on port 80

Step 5: Read the first boot credentials

On the first boot of your VM a one shot service generates the administrator password, the PostgreSQL password and the JWT signing keystore, all unique to that VM, and writes the administrator credentials to a root only file. The image itself ships with no database and no account of any kind, so there is no default login to change.

sudo sed -E 's/(SKILLTREE_ADMIN_PASSWORD=).*/\1**** unique per VM ****/' /root/skilltree-credentials.txt
sudo ls -l /etc/skilltree/application.properties /var/lib/skilltree/jwtkeys.jks

The screenshot below masks the password, which is different on every VM.

The root only credentials file with the password masked, the per VM configuration and signing keystore, and the start time guard reporting OK

Read the real password when you need it:

sudo grep SKILLTREE_ADMIN_PASSWORD /root/skilltree-credentials.txt

Step 6: Check the endpoints

nginx serves an unauthenticated health probe, and SkillTree serves its own public bootstrap configuration used by the dashboard.

curl -s -o /dev/null -w 'healthz %{http_code}\n' http://127.0.0.1/healthz
curl -s -o /dev/null -w 'public config %{http_code}\n' http://127.0.0.1/public/config

Step 7: Sign in to the dashboard

Browse to http://<your-vm-ip>/ and sign in with the administrator address admin@skilltree.local and the password from Step 5.

The SkillTree sign in page served over port 80, showing the email address and password fields

You can prove the same sign in from the command line. This performs a real form login, keeps the session cookie, and then uses that cookie to call an authenticated endpoint.

JAR=$(mktemp)
curl -s -o /dev/null -w 'login %{http_code}\n' -c "$JAR" \
  -X POST http://127.0.0.1/performLogin \
  --data-urlencode 'username=<SKILLTREE_USER>' \
  --data-urlencode 'password=<SKILLTREE_PASSWORD>'
curl -s -b "$JAR" http://127.0.0.1/app/userInfo | cut -c1-120; echo
rm -f "$JAR"

The health probe, a form login returning HTTP 200 with a session cookie, the authenticated user endpoint, memory headroom and an empty swap table

Step 8: Create your first project

A project is one gamified training profile. Create one from the dashboard with the Project button, or over the REST API as below.

JAR=$(mktemp)
curl -s -o /dev/null -c "$JAR" -X POST http://127.0.0.1/performLogin \
  --data-urlencode 'username=<SKILLTREE_USER>' \
  --data-urlencode 'password=<SKILLTREE_PASSWORD>'
XSRF=$(awk '$6=="XSRF-TOKEN"{print $7}' "$JAR")
curl -s -o /dev/null -w 'create project %{http_code}\n' -b "$JAR" \
  -H "X-XSRF-TOKEN: $XSRF" -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1/app/projects/onboarding \
  --data '{"projectId":"onboarding","name":"New Starter Onboarding"}'
curl -s -o /dev/null -w 'pin project %{http_code}\n' -b "$JAR" \
  -H "X-XSRF-TOKEN: $XSRF" -X POST http://127.0.0.1/root/pin/onboarding
rm -f "$JAR"

The pin step matters. Your administrator is a SkillTree root user, and a root user's Projects page lists only the projects they have pinned, so a newly created project will not appear until it is pinned. You can also pin an existing project from the dashboard with the Pin button.

The administrator Projects page listing a training project with its subject, skill, point and badge totals

Step 9: Add subjects and skills

Subjects group skills inside a project, and skills are what your application reports against. Each skill defines how many points it awards and how many times it must be performed.

A project page showing the subject with its skill count and the total points the project is worth

Open a subject to manage its skills. SkillTree keeps the running point total for the subject and the project as you add them.

The subject page listing four skills with their display order and creation dates

Step 10: Report a skill event from your application

Your application tells SkillTree that a user did something. Points, levels and badges follow automatically. Reporting uses a project token, which you create under the project's Access page.

sudo -u postgres psql -d skilltree -tAc \
  "select project_id, name, total_points from project_definition order by project_id"
sudo -u postgres psql -d skilltree -tAc "select count(*) from skill_definition"

The bundled PostgreSQL schema with a real project and its skill count

Memory and swap

The JVM heap is deliberately capped so the whole stack fits the Standard_B2s envelope. Azure certification does not permit a swap file baked into the image, so this image ships with none and does not need any.

grep SKILLTREE_JVM_OPTS /etc/default/skilltree
free -m | head -2
swapon --show

If you move to a larger VM size and want a bigger heap, edit -Xmx in /etc/default/skilltree and restart the service. Keep the heap well under half of the VM's memory so PostgreSQL and the page cache still have room.

Managing the service

sudo systemctl status skilltree --no-pager | head -8
sudo systemctl is-enabled skilltree nginx postgresql

Restart SkillTree after a configuration change with sudo systemctl restart skilltree, and follow its log with sudo journalctl -u skilltree -f.

The service will refuse to start if its configuration is missing a generated secret or is pointing at a published example value. That guard runs on every start, so a misconfigured VM fails loudly rather than coming up with a weak secret.

Security recommendations

  • Change the administrator password after your first sign in, from Settings then Security.
  • Put your own TLS terminator in front of port 80 before exposing this VM to the internet, and restrict port 22 to your management address. SkillTree's session cookie is deliberately not marked secure so that sign in works over the appliance's plain HTTP front door; once you terminate TLS in front of it, set server.servlet.session.cookie.secure=true in /etc/skilltree/application.properties and restart the service.
  • Keep PostgreSQL on loopback. The image does not expose it, and there is no reason to.
  • The Spring Boot management port 8808 is bound to loopback and is authenticated. Leave it that way.
  • Take regular backups of the skilltree database with pg_dump if you rely on the training records.

Next steps

Point your application at the REST API to report skill events as your users complete work, and use the dashboard's Metrics pages to see progress across projects, subjects and user tags. Upstream project documentation and the API reference live with the SkillTree project at github.com/NationalSecurityAgency/skills-service, which is the source of the software in this image.

Support

cloudimg provides 24/7 support for this image. Contact support through the cloudimg website with your VM's region, size and the output of sudo systemctl status skilltree --no-pager.