SafeLine WAF on Ubuntu 24.04 on Azure User Guide
Overview
SafeLine is a self hosted Web Application Firewall and reverse proxy that protects web applications from attacks and exploits. Rather than matching requests against long lists of regular expression signatures, it uses a semantic detection engine that parses each request the way the target application would, so it recognises the intent behind SQL injection, cross site scripting, command injection, path traversal and other common web attacks while letting legitimate traffic through. You place a protected site in front of your upstream server, choose the port it listens on, and every request is inspected before it reaches your application, with attacks answered by a branded interception page. The cloudimg image installs SafeLine 9.3.10 as the official Chaitin SafeLine Docker Compose stack and runs it as a systemd service, so a working management console and WAF are online within minutes of launch.
What is included:
- SafeLine 9.3.10 (GPL-3.0) deployed from the official
chaitin/SafeLineDocker Compose stack, pinned to the v9.3.10 images so the image never silently upgrades - Docker Engine (Docker CE) and the Docker Compose plugin, installed from the official Docker package repository
- The SafeLine Compose stack (seven containers):
safeline-mgt(the management API and web console, published on host port 9443 over HTTPS),safeline-tengine(the tengine reverse proxy that filters traffic to your protected sites),safeline-detector(the semantic detection engine),safeline-pg(PostgreSQL, the management database, reachable only on the internal container network), and thesafeline-luigi,safeline-fvmandsafeline-chaossupporting services - A per-VM
adminaccount with a generated password, minted on first boot — SafeLine ships with no default password - Two systemd units:
safeline.service(a oneshot wrapper arounddocker compose up -d) andsafeline-firstboot.service - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key, and a VNet and subnet. Standard_B2s (2 vCPU / 4 GB RAM) is the recommended size. NSG inbound rules: allow 22/tcp from your management CIDR for SSH, 9443/tcp from the CIDR that needs the SafeLine management console, and 80/tcp and 443/tcp from the internet for the web traffic you want the WAF to protect (SafeLine's tengine proxy binds the listen ports of the sites you add).
Step 1: Connect over SSH
Replace <vm-ip> with the public IP of your VM. The default login user is azureuser.
ssh azureuser@<vm-ip>
Step 2: Confirm the services are active
sudo systemctl is-active docker safeline
docker --version
docker compose version
You should see active printed twice, the Docker Engine version, and the Docker Compose v2 plugin version.

Step 3: Confirm the SafeLine containers are running
cd /data/safeline && sudo docker compose -f compose.yaml --env-file .env ps
You should see the SafeLine containers — safeline-mgt, safeline-tengine, safeline-detector, safeline-pg, safeline-luigi, safeline-fvm and safeline-chaos — in the Up / running state.
Step 4: Confirm the management console is healthy
The management console is served over HTTPS on port 9443 and exposes an unauthenticated health endpoint that returns HTTP 200 when SafeLine is ready. The console uses a self signed certificate on first launch, so curl is called with -k.
curl -ks -o /dev/null -w "%{http_code}\n" https://localhost:9443/api/open/health
A 200 confirms the console is up.
Step 5: Read the per-VM admin credentials
SafeLine has no default password. A unique admin credential is minted for your instance on its first boot and written to a root only file.
sudo cat /root/safeline-credentials.txt
This file lists safeline.url (where to sign in), safeline.admin.user (admin) and safeline.admin.pass. Store the password somewhere safe.

Step 6: Sign in to the SafeLine console
Browse to https://<vm-ip>:9443/ in your browser. Because the console uses a self signed certificate on first launch, your browser warns once — accept it to continue. On the very first visit SafeLine shows a one time software licence agreement; read it and choose Agree, start using. You then reach the sign in page, where you log in with the username admin and the safeline.admin.pass from Step 5.

After signing in you land on the Statistics dashboard, which summarises request volume, blocked attacks, the geographic origin of traffic and the current security posture. SafeLine recommends binding an authenticator app for two factor authentication on first sign in; you can do this from Auth at any time.

Step 7: Protect your first web application
To put SafeLine in front of a web application, open Applications in the console and choose Add Application. Give it the domain (or Match All Host), the port SafeLine should listen on (for example 80 or 443), and the upstream address of your origin server (for example http://127.0.0.1:8080 or http://10.0.0.4:3000). SafeLine's tengine proxy then binds that port and every request to it is inspected by the detection engine before it reaches your origin.

Step 8: How SafeLine blocks attacks
Once a site is protected, SafeLine passes clean traffic straight through to your origin and intercepts attacks. A benign request returns your application's normal response; an obvious SQL injection or cross site scripting probe is answered with an HTTP 403 interception page instead of ever reaching your origin.

The visitor who sends the malicious request sees SafeLine's branded interception page, with a unique event id that also appears in the console under Attacks.

Secure by default
The management console requires authentication, the PostgreSQL database is bound to the internal container network only (it is never published on a host port), and a wrong password is rejected. You can confirm which ports are exposed on the host and that the console is healthy at any time.
sudo ss -tlnp | grep -E ':9443|:5432' || true
You will see the console listening on 9443; PostgreSQL on 5432 is deliberately absent from the host because it lives only on the container network.

Step 9: Manage the stack
The whole stack is managed by the safeline.service systemd unit, which wraps docker compose under /data/safeline.
sudo systemctl restart safeline.service
sudo systemctl status safeline.service --no-pager
To inspect the logs for a specific service:
cd /data/safeline && sudo docker compose -f compose.yaml --env-file .env logs --tail 50 mgt
If you ever need to mint a fresh admin credential, run sudo docker exec safeline-mgt resetadmin and it prints a new username and password.
Enabling HTTPS on your own domain
The management console already serves HTTPS on port 9443 with a self signed certificate. For the sites you protect, add your own TLS certificate under Certificates in the console and bind it to the site so SafeLine terminates HTTPS for your application on port 443. Add 443/tcp to your NSG inbound rules.
First-boot security model
On the first boot of each VM, safeline-firstboot.service runs once and:
- Regenerates the PostgreSQL password and initialises the database clean, so no build time database or secret ships in the image
- Mints a fresh, strong
admincredential withresetadminand writes it to/root/safeline-credentials.txt(root only, mode 0600) - Records a sentinel so the stack only starts once the credential has been rotated
No shared or default login and no preexisting protected site ship in the image. The management console is protected by this per-VM credential the moment it comes up.
Support
24/7 technical support is included. Contact cloudimg at support@cloudimg.co.uk for help with deployment, protecting your applications, the detection engine and custom rules, rate limiting, bot and authentication defence, TLS certificates and custom domains, and the SafeLine Open API.
SafeLine is a trademark of Beijing Chaitin Technology Co., Ltd. PostgreSQL is a trademark of the PostgreSQL Community Association of Canada. Docker is a trademark of Docker, Inc. All other product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.