Deployment guide

SkillTree

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 and renders progress, rankings and metrics for trainees. It adds gamified training to an application you already have, rather than replacing it.

This SecureAnyCloud 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 you get:

  • 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, which generates 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 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key, and a VNet with a subnet.

Standard_B2s (2 vCPU, 4 GB RAM) is the tested size. It runs the whole stack with roughly 2 GB of memory still available. Choose a larger size if you expect many concurrent trainees or heavy video and attachment uploads.

Open port 80 on the network security group, plus port 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>
4

Verify the services

SkillTree runs as a Spring Boot service behind nginx, with PostgreSQL alongside it. Confirm that all three services are active and check the listeners:

sudo systemctl is-active postgresql skilltree nginx java -version sudo ss -tlnp | grep -E ':80 |:8080 '
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. It 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. Run the following to read the credentials file with the password masked:

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 password is different on every VM. To read the real password, run:

sudo grep SKILLTREE_ADMIN_PASSWORD /root/skilltree-credentials.txt
6

Check the endpoints

nginx serves an unauthenticated health probe, and SkillTree serves the public bootstrap configuration that the dashboard uses. Call both:

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

You can also verify the sign-in from the command line. The following 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"
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 shown 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"

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

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.

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

10

Report a skill event from your application

Your application tells SkillTree that a user did something, and points, levels and badges follow automatically. Reporting uses a project token, which you create on the project's Access page. To check what the project holds, query the database:

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"

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 one. Check the heap setting and confirm that no swap is active:

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

After a configuration change, restart SkillTree with sudo systemctl restart skilltree. Follow its log with sudo journalctl -u skilltree -f.

The service refuses to start if its configuration is missing a generated secret or points at a published example value. That guard runs on every start, so a misconfigured VM fails loudly instead of coming up with a weak secret.

Security recommendations

  • Change the administrator password after your first sign-in, from Settings then Security.
  • Add TLS and restrict SSH. Put your own TLS terminator in front of port 80 before you expose 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.
  • Leave the management port as it is. The Spring Boot management port 8808 is bound to loopback and is authenticated.
  • Back up regularly. If you rely on the training records, back up the skilltree database with pg_dump.

Next steps

Point your application at the REST API to report skill events as your users complete work. Use the dashboard's Metrics pages to see progress across projects, subjects and user tags.

The upstream documentation and API reference live with the SkillTree project at github.com/NationalSecurityAgency/skills-service, which is the source of the software in this image.

Support

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

Deploy on Azure

Launch SkillTree 4.6.0 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure