Deployment guide

XXL-JOB

Overview

XXL-JOB is a lightweight, widely adopted distributed task-scheduling platform. It gives your teams one central place to define, schedule, dispatch and monitor scheduled jobs across a fleet of worker (executor) nodes, so batch work, data pipelines and periodic tasks run reliably without a bespoke cron setup on every server. The admin console supports cron and fixed-rate scheduling, several executor routing strategies, block and failover handling, run logs, alerting and a live dashboard of scheduling activity.

The SecureAnyCloud image runs the official XXL-JOB admin console as a Docker Compose stack, pinned to release 3.4.2. The stack has two parts: a MySQL datastore that holds the scheduler's jobs, executors and run history, and the xxl-job-admin Spring Boot application (built on Temurin OpenJDK 17) that presents the management web console. MySQL is bound to the private Docker network only, so just SSH and the admin console's HTTP port are exposed on the virtual machine.

Every secret is generated uniquely on the first boot of every VM. The administrator password, the MySQL database password and the executor access token are each rotated per instance, replacing the shipped defaults, so no shared or default credential is ever live. This matters for a scheduler that can dispatch commands to your executors, where a known default admin would be remote code execution across the fleet. The image is backed by 24/7 SecureAnyCloud support.

What you get:

  • The official XXL-JOB 3.4.2 admin console running under Docker (xxl-job-admin pinned by image digest, xxl-job-mysql on mysql:8.4), so it never silently upgrades
  • The admin console on port 8080, backed by a MySQL scheduler datastore seeded with the pinned release's schema
  • A per-VM admin account generated on first boot, with its SHA-256 password stored in the database and recorded in a root-only file, so every VM is secured independently
  • The xxl.job.accessToken executor access token and the MySQL password regenerated per VM on first boot, replacing the shipped defaults
  • MySQL bound to the private Docker network only, so just 22/tcp (SSH) and 8080/tcp (XXL-JOB) are exposed
  • The stack managed as one xxl-job.service systemd unit, plus docker.service, both enabled
  • 24/7 SecureAnyCloud support

Prerequisites

  • An active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region
  • Standard_B2s (2 vCPU, 4 GiB RAM) as a comfortable starting size for the admin console and its database
  • Network security group inbound rules that allow 22/tcp from your management network and 8080/tcp from the operators and executor nodes that will use XXL-JOB
  • Your own domain and TLS for production, because the appliance serves plain HTTP

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for XXL-JOB by SecureAnyCloud, and select Create.

On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22), and add 8080 after deployment.

Select Review + create, then Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:xxl-job:default:latest
az vm create \
  --resource-group <your-rg> \
  --name xxl-job \
  --image sac1647283583153:xxl-job:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name xxl-job --port 8080 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the stack is running

XXL-JOB runs as a Docker Compose stack managed by a single systemd unit. On first boot the stack rotates every secret, re-seeds a fresh scheduler database, seeds the per-VM admin account and points its console URL at your VM's address. The stack can take a minute or two to become fully healthy after the VM is first created.

systemctl is-active xxl-job.service docker.service docker compose -f /var/lib/xxl-job/docker-compose.yml ps --format '{{.Name}}\t{{.Status}}'

Both containers should report Up.

Step 5 - Retrieve your per-VM admin credentials

The first boot writes a unique administrator password and executor access token to a root-only file. Read the file over SSH:

sudo cat /root/xxl-job-credentials.txt

The file records the console URL, the admin username, the generated password and the per-VM xxl.job.accessToken. It has mode 0600 and is owned by root.

Step 6 - Verify the login and that no default credential survives

The first boot rotates the built-in admin password away from XXL-JOB's shipped default (admin / 123456). It also rotates the executor access token away from the shipped default_token, so no known credential is ever live.

You can prove this from the shell. The per-VM password authenticates and the login returns code 200, while the shipped default is rejected with code 500.

B=http://127.0.0.1:8080 curl -s -X POST "$B/auth/doLogin" --data-urlencode "userName=admin" --data-urlencode "password=<XXLJOB_ADMIN_PASSWORD>" echo curl -s -X POST "$B/auth/doLogin" --data-urlencode "userName=admin" --data-urlencode "password=123456"

The first call returns {"code":200,...,"success":true}, which means the per-VM admin authenticated. The second returns {"code":500,...} with a "Username or password error" message, which means the shipped default is rejected.

Step 7 - Confirm the pinned image and exposed ports

The admin console image is pinned to 3.4.2, and only SSH and the console HTTP port are exposed on the VM. MySQL listens on the private Docker network only, never on the host.

docker compose -f /var/lib/xxl-job/docker-compose.yml images --format '{{.Repository}}:{{.Tag}}' | sort -u sudo ss -tln '( sport = :8080 or sport = :22 or sport = :3306 )' | awk '{print $1" "$4}'

You should see xuxueli/xxl-job-admin:3.4.2 and mysql:8.4, with listeners on :22 and :8080 only. :3306 (MySQL) is not bound on the host.

Step 8 - Sign in to the admin console

Browse to http://<vm-public-ip>:8080/ and sign in as admin with the password from Step 5.

After you sign in, you land on the Run report dashboard. It summarises your scheduler with the number of jobs and executors, recent trigger counts, and the success, fail and running distribution of recent runs.

Step 9 - Review the scheduler and its jobs

Open Job Manage to see the scheduled jobs. The image ships with XXL-JOB's sample jobs, so the console is populated out of the box. Each row shows the job description, its schedule type (for example a CRON expression), the run mode and handler, its status and its author.

From here you create your own jobs, set their schedule, choose a routing strategy, and start or stop them. You can also trigger a job immediately with Run Once.

Step 10 - Register an executor and run a job

Jobs are dispatched to executors, which are your own worker applications that run the job logic. Open Executor Manage to see the registered executor groups. The image ships XXL-JOB's sample groups.

To connect your own executor, add the XXL-JOB executor dependency to your application. Point it at this console and give it the per-VM access token from Step 5:

# In your-executor application's configuration: xxl.job.admin.addresses=http://<vm-public-ip>:8080 xxl.job.accessToken=<XXLJOB_ACCESS_TOKEN> xxl.job.executor.appname=my-executor

Once your executor registers, it appears here with OnLine machine addresses. You can then route jobs to it and trigger them from Job Manage.

Step 11 - Production hardening

  • TLS. The appliance serves plain HTTP on port 8080. In production, place it behind your own domain and a TLS-terminating load balancer or reverse proxy.
  • Access token. The per-VM xxl.job.accessToken (Step 5) authorises executors to register and receive dispatched commands. Keep it secret and give it only to your own executor nodes. To rotate it, edit XXLJOB_ACCESS_TOKEN in /var/lib/xxl-job/.env and run sudo systemctl restart xxl-job.service.
  • Admin password. After your first sign-in, change the admin password from the console (top-right user menu). Alternatively, add your own users under User Manage and disable the default.
  • Network. Expose port 8080 only to your operators and executor nodes, not the public internet.
  • Backups. The scheduler database lives in the xxl-job_mysql_data Docker volume. Include it in your backup routine, together with /var/lib/xxl-job/.env, which holds your per-VM secrets.

Managing the service

Restart, stop, start and follow the logs of the stack:

# Restart the whole stack
sudo systemctl restart xxl-job.service
# Stop / start
sudo systemctl stop xxl-job.service
sudo systemctl start xxl-job.service
# Follow the admin console logs docker compose -f /var/lib/xxl-job/docker-compose.yml logs -f xxl-job-admin

Support

Every SecureAnyCloud image is backed by 24/7 support. For questions about this XXL-JOB image, email sales@secureanycloud.com.

Deploy on Azure

Launch XXL-JOB 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