Virtual Private Servers (VPSs) provide an economical and flexible infrastructure platform for small and medium-sized businesses, engineering organizations, software companies and eCommerce businesses.

A single VPS may host:

  • WordPress

  • Joomla

  • Magento/Open Source

  • Nginx

  • Apache

  • PHP-FPM

  • MariaDB/MySQL

  • Redis

  • Docker

  • Docker Compose

  • APIs

  • development tools

  • monitoring systems

  • business applications

This concentration of services also creates a concentrated security risk.

A vulnerable plugin, stolen administrator credential, exposed Docker port, compromised PHP application or misconfigured firewall can potentially provide an attacker with access to valuable business systems.

This paper presents a defense-in-depth security architecture using multiple independent security controls:

Defense-in-Depth VPS Security

Cloud Firewall, UFW, Docker Hardening, Malware Detection and Rootkit Hunting

A Production Engineering Tutorial for WordPress, Joomla, Magento and Docker-Based Web Applications

Executive Summary

Virtual Private Servers (VPSs) provide an economical and flexible infrastructure platform for small and medium-sized businesses, engineering organizations, software companies and eCommerce businesses.

A single VPS may host:

  • WordPress

  • Joomla

  • Magento/Open Source

  • Nginx

  • Apache

  • PHP-FPM

  • MariaDB/MySQL

  • Redis

  • Docker

  • Docker Compose

  • APIs

  • development tools

  • monitoring systems

  • business applications

This concentration of services also creates a concentrated security risk.

A vulnerable plugin, stolen administrator credential, exposed Docker port, compromised PHP application or misconfigured firewall can potentially provide an attacker with access to valuable business systems.

This paper presents a defense-in-depth security architecture using multiple independent security controls:

Internet | v Cloud Firewall | v Ubuntu VPS | +-- UFW / nftables | +-- SSH Hardening | +-- Fail2ban | +-- Nginx / Apache | +-- WAF | +-- Docker Isolation | +-- WordPress / Joomla / Magento | +-- MariaDB | +-- Redis | +-- ClamAV | +-- Rootkit Hunting | +-- File Integrity | +-- Monitoring | +-- Backup | +-- Incident Response

The reference implementation in this tutorial uses a Contabo VPS running Ubuntu LTS as an example. The same principles can be applied to other VPS providers.

The fundamental engineering principle is:

Do not depend on a single security control. Build multiple layers so that the failure or misconfiguration of one layer does not automatically result in compromise.

1. Introduction

Modern web infrastructure is a software-defined system rather than simply a server.

A typical eCommerce or CMS deployment may contain:

INTERNET | v +----------------+ | DNS / CDN / WAF| +----------------+ | v +----------------+ | Cloud Firewall | +----------------+ | v +----------------+ | Ubuntu VPS | | | | UFW | | SSH | | Docker | +----------------+ | v +----------------+ | Nginx / Apache | +----------------+ | +----------+----------+ | | | v v v WordPress Joomla Magento | | | +----------+----------+ | Private Network | +-------+-------+ | | v v MariaDB Redis

Every component represents an attack surface.

Security therefore has to be designed at multiple levels:

  1. Network

  2. Host

  3. Identity

  4. Container

  5. Web server

  6. Application

  7. Database

  8. File system

  9. Monitoring

  10. Recovery

2. Research Objective

This paper develops a practical security methodology for production VPS environments.

The objectives are to demonstrate:

  • why cloud firewalls and host firewalls should be combined;

  • how to harden an Ubuntu VPS;

  • how to secure SSH;

  • how to handle Docker firewall behavior;

  • how to prevent accidental exposure of databases and internal services;

  • how to secure WordPress, Joomla and Magento;

  • how to use ClamAV;

  • how to perform rootkit hunting;

  • how to establish file-integrity baselines;

  • how to automate security checks;

  • how to investigate a compromised website;

  • how to recover from compromise;

  • how SMEs can operationalize VPS security.

3. Defense-in-Depth Model

The recommended security architecture is:

INTERNET | v +------------------+ | CDN / WAF / DNS | +------------------+ | v +------------------+ | CLOUD FIREWALL | | External Layer | +------------------+ | v +------------------+ | CONTABO VPS | | Ubuntu LTS | +------------------+ | v +------------------+ | UFW / nftables | | Host Layer | +------------------+ | +--------+--------+ | | v v SSH NGINX | v WAF | v Docker | +-----------------+----------------+ | | | v v v WordPress Joomla Magento | | | +-----------------+----------------+ | Private Network | +-----------+-----------+ | | v v MariaDB Redis Security Operations: ClamAV | Rootkit Hunting | AIDE Lynis | Fail2ban | Logging Monitoring | Backup | Incident Response

4. Why Use Both a Cloud Firewall and UFW?

A cloud firewall and UFW operate at different architectural boundaries.

Cloud firewall

The provider firewall operates outside the VPS.

It can reject traffic before it reaches the operating system.

UFW

UFW provides host-level firewall administration.

The two layers therefore provide defense in depth.

Internet | v Cloud Firewall | v VPS Network Interface | v UFW | v Application

If a cloud firewall rule is accidentally changed, UFW remains available as another control.

If an application unexpectedly opens a service, the provider firewall can provide an additional perimeter control.

5. Firewall Design Principle

Use:

DEFAULT DENY

for inbound traffic.

Then explicitly permit required services.

For a typical production web server:

TCP 80 HTTP TCP 443 HTTPS TCP 22 SSH, preferably restricted

Do not expose internal services unless there is a documented requirement.

Examples include:

3306 MariaDB 6379 Redis 9000 PHP-FPM 9200 Elasticsearch 11211 Memcached 8080 Development application 3000 Development application 5000 Development API 8000 Development service

6. Contabo VPS Reference Use Case

The example environment is:

Provider: Contabo Operating System: Ubuntu LTS Application Platform: Docker / Docker Compose Web Server: Nginx Applications: WordPress Joomla Magento Database: MariaDB Cache: Redis Security: Cloud Firewall UFW Fail2ban ClamAV Rootkit Hunter chkrootkit Lynis AIDE

This is a reference architecture rather than a requirement that all components be installed on every server.

7. Initial VPS Discovery

Connect to the VPS:

ssh administrator@YOUR_SERVER_IP>If root access was initially provided:ssh root@YOUR_SERVER_IP>Immediately identify the operating system:hostnamectl uname -a cat /etc/os-release

Check CPU:

nproc lscpu

Memory:

free -h

Storage:

df -h lsblk

Network:

ip addr ip route

8. Create an Administrative Account

 

If operating as root:

adduser administrator

Add sudo capability:

usermod -aG sudo administrator

Verify:

id administrator

Test:

ssh administrator@YOUR_SERVER_IP>Then:sudo whoami

Expected:

root

Do not disable root SSH access until the administrative account has been tested successfully.

 

9. Update Ubuntu

sudo apt update sudo apt upgrade -y

Clean unused packages:

sudo apt autoremove -y sudo apt autoclean

Check for remaining updates:

apt list --upgradable

Reboot when required:

sudo reboot

Reconnect:

ssh administrator@YOUR_SERVER_IP>10. Install Administration Toolssudo apt install -y \ curl \ wget \ git \ vim \ nano \ htop \ iotop \ ncdu \ tree \ unzip \ zip \ rsync \ jq \ net-tools \ dnsutils \ lsof \ ca-certificates \ gnupg

11. SSH Key Authentication

 

On the administrator's workstation:

ssh-keygen -t ed25519

Copy the public key:

ssh-copy-id administrator@YOUR_SERVER_IP>Test:ssh administrator@YOUR_SERVER_IP>The key-based connection must work before disabling password authentication.

12. SSH Hardening

Create:

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf

Example:

PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes PermitEmptyPasswords no MaxAuthTries 3 X11Forwarding no AllowUsers administrator

Validate:

sudo sshd -t

If valid, restart SSH:

sudo systemctl restart ssh

Keep the existing SSH session open.

Open a second terminal and test:

ssh administrator@YOUR_SERVER_IP>Only after successful testing should the original session be closed.

13. Contabo Cloud Firewall

Configure the provider-level firewall to allow only required public services.

A typical policy:

INBOUND TCP 80 ALLOW TCP 443 ALLOW TCP 22 ALLOW from trusted administrative IPs ALL OTHER DENY

Do not expose database or container-development ports simply because applications use them internally.

14. Discover Existing Listening Services

Before enabling UFW:

sudo ss -tulpn

TCP:

sudo ss -lntp

UDP:

sudo ss -lnup

Alternative:

sudo lsof -i -P -n

Save the baseline:

sudo ss -tulpn | tee ~/listening-services.txt

This is an important security-management step.

15. Install UFW

sudo apt install -y ufw

Check:

sudo ufw status verbose

Set defaults:

sudo ufw default deny incoming sudo ufw default allow outgoing

Allow SSH:

sudo ufw allow 22/tcp

Allow HTTP:

sudo ufw allow 80/tcp

Allow HTTPS:

sudo ufw allow 443/tcp

Check:

sudo ufw status numbered

Enable:

sudo ufw enable

Verify:

sudo ufw status verbose

16. Avoiding SSH Lockout

Never enable UFW before permitting the SSH access path.

Correct sequence:

sudo ufw allow 22/tcp sudo ufw enable

For a custom SSH port:

sudo ufw allow 2222/tcp

The port must correspond to the actual SSH configuration.

Always maintain provider console/recovery access.

17. Restrict SSH to an Administration IP

If the administrator has a fixed trusted IP:

sudo ufw delete allow 22/tcp

Then:

sudo ufw allow from YOUR_ADMIN_IP to any port 22 proto tcp

Verify:

sudo ufw status numbered

This can dramatically reduce automated SSH attack traffic.

18. UFW Logging

Enable:

sudo ufw logging medium

Check:

sudo grep UFW /var/log/ufw.log

Or:

sudo journalctl -k | grep UFW

Follow:

sudo tail -f /var/log/ufw.log

19. Inspect nftables and iptables

Because modern Linux systems use netfilter technologies and applications such as Docker may manipulate firewall rules, inspect the underlying rules.

sudo iptables -L -n -v

Inspect Docker-specific chains later:

sudo iptables -L DOCKER -n -v sudo iptables -L DOCKER-USER -n -v

Inspect nftables:

sudo nft list ruleset

The goal is not to manipulate every rule manually.

The goal is to understand which system owns and controls each rule.

20. Install Docker

Remove potentially conflicting packages:

sudo apt remove -y \ docker.io \ docker-doc \ docker-compose \ podman-docker \ containerd \ runc

Install prerequisites:

sudo apt update sudo apt install -y \ ca-certificates \ curl \ gnupg

Create the keyring directory:

sudo install -m 0755 -d /etc/apt/keyrings

Then install Docker Engine and Compose using the current official Docker repository procedure appropriate for the Ubuntu release.

Verify:

sudo docker version

Compose:

sudo docker compose version

21. Add the Administrator to Docker

sudo usermod -aG docker administrator

Log out:

exit

Reconnect:

ssh

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

administrator@YOUR_SERVER_IP>Test:docker ps

 

22. Docker Security

Docker changes the networking model.

List containers:

docker ps -a

Networks:

docker network ls

Inspect:

docker network inspect bridge

Published ports:

docker ps --format "table {{.Names}}\t{{.Ports}}"

Inspect an individual container:

docker inspect CONTAINER_NAME

23. The Docker/UFW Security Problem

Docker manages network filtering and port publishing.

Therefore, administrators must not assume that an ordinary UFW rule automatically controls every published Docker port.

For example:

docker run -p 8080:80 nginx

publishes a container port.

A safer host-only example is:

docker run -p 127.0.0.1:8080:80 nginx

The second configuration binds the service only to localhost.

This principle is useful for:

24. Docker Published-Port Audit

Run:

docker ps --format "table {{.Names}}\t{{.Ports}}"

Investigate anything such as:

0.0.0.0:3306 0.0.0.0:6379 0.0.0.0:8080 0.0.0.0:9200

unless explicitly required.

Also run:

sudo ss -lntup

Compare both results.

25. Secure Docker Compose Design

A production architecture should expose only the reverse proxy.

Example:

services: nginx: image: nginx:stable ports: - "80:80" - "443:443" networks: - frontend - backend application: image: your-application-image expose: - "9000" networks: - backend mariadb: image: mariadb expose: - "3306" networks: - backend redis: image: redis expose: - "6379" networks: - backend networks: frontend: backend: internal: true

This is a conceptual example and must be adapted to the application.

26. Ports vs. Expose

Avoid unnecessary:

ports: - "3306:3306"

Prefer an internal service:

expose: - "3306"

Similarly:

expose: - "6379"

for Redis.

The reverse proxy can expose:

ports: - "80:80" - "443:443"

27. Docker Firewall Inspection

Inspect:

sudo iptables -L DOCKER -n -v

Inspect:

sudo iptables -L DOCKER-USER -n -v

Forwarding:

sudo iptables -L FORWARD -n -v

nftables:

sudo nft list ruleset

Docker's networking should be treated as part of the security architecture rather than as an independent convenience layer.

28. Install Fail2ban

sudo apt install -y fail2ban

Enable:

sudo systemctl enable --now fail2ban

Check:

sudo systemctl status fail2ban

Jails:

sudo fail2ban-client status

SSH:

sudo fail2ban-client status sshd

29. Fail2ban Configuration

Create:

sudo nano /etc/fail2ban/jail.local

Example:

[DEFAULT] bantime = 1h findtime = 10m maxretry = 5 [sshd] enabled = true

Restart:

sudo systemctl restart fail2ban

Verify:

sudo fail2ban-client status sshd

30. ClamAV Installation

Install:

sudo apt update sudo apt install -y clamav clamav-daemon

Update signatures:

sudo freshclam

Check:

sudo systemctl status clamav-freshclam

31. Scan a Web Server

For a conventional web root:

sudo clamscan -r /var/www/

Infected files only:

sudo clamscan -r --infected /var/www/

Save a report:

sudo clamscan \ -r \ --infected \ --log=/var/log/clamav/web-scan.log \ /var/www/

32. Scan Docker Application Data

First identify volumes:

docker volume ls

Inspect:

docker inspect CONTAINER_NAME

Identify the host path used for persistent application data.

Then scan the appropriate mounted directory:

sudo clamscan -r --infected /PATH/TO/DATA

Do not blindly scan Docker's entire internal filesystem structure without understanding the consequences.

33. Automated ClamAV Scan

Create:

sudo nano /usr/local/sbin/web-malware-scan.sh

Script:

#!/bin/bash set -u LOG="/var/log/web-malware-scan.log" TARGET="/var/www" echo "========================================" >> "$LOG" echo "Web malware scan started" >> "$LOG" echo "Date: $(date)" >> "$LOG" echo "Target: $TARGET" >> "$LOG" clamscan \ -r \ --infected \ --log="$LOG" \ "$TARGET" RESULT=$? echo "Scan finished: $(date)" >> "$LOG" echo "Exit code: $RESULT" >> "$LOG" echo "========================================" >> "$LOG" exit "$RESULT"

Make executable:

sudo chmod 750 /usr/local/sbin/web-malware-scan.sh

Test:

sudo /usr/local/sbin/web-malware-scan.sh

34. Daily Malware Scan

Create:

sudo nano /etc/cron.d/web-malware-scan

Example:

0 2 * * * root /usr/local/sbin/web-malware-scan.sh

Review:

cat /etc/cron.d/web-malware-scan

For high-value production environments, systemd timers can also be used for more structured scheduling and logging.

35. Rootkit Hunting

Install Rootkit Hunter:

sudo apt install -y rkhunter

Update:

sudo rkhunter --update

After establishing a known-good baseline:

sudo rkhunter --propupd

Run:

sudo rkhunter --check

Review:

sudo less /var/log/rkhunter.log

Rootkit Hunter warnings require investigation.

A warning is not automatically proof of a rootkit.

36. Chkrootkit

Install:

sudo apt install -y chkrootkit

Run:

sudo chkrootkit

Save:

sudo chkrootkit | tee ~/chkrootkit-report.txt

Use multiple sources of evidence:

Rootkit Hunter + chkrootkit + ClamAV + process analysis + network analysis + log analysis + file-integrity analysis

37. Lynis Security Audit

Install:

sudo apt install -y lynis

Run:

sudo lynis audit system

Quick audit:

sudo lynis audit system --quick

Lynis recommendations should be reviewed by an administrator rather than applied blindly.

38. File Integrity Monitoring

Install AIDE:

sudo apt install -y aide

Initialize:

sudo aideinit

Check:

sudo aide --check

The baseline should be created when the system is known to be clean.

Monitor important files:

/etc/ /var/www/ /etc/ssh/ /etc/systemd/ /etc/cron* Docker Compose configuration CMS configuration Web-server configuration

39. Process Hunting

Display processes:

ps auxf

Interactive:

htop

Top CPU consumers:

ps aux --sort=-%cpu | head -20

Top memory consumers:

ps aux --sort=-%mem | head -20

Investigate unknown processes.

40. Network Hunting

Listening services:

sudo ss -lntup

Active connections:

sudo ss -tunap

Established connections:

sudo ss -tnp state established

Network processes:

sudo lsof -i -P -n

Unexpected outbound connections should be investigated.

41. User and Privilege Hunting

List users:

cut -d: -f1 /etc/passwd

Users with interactive shells:

awk -F: '$7 !~ /(nologin|false)$/ {print $1,$7}' /etc/passwd

Sudo group:

getent group sudo

Last logins:

last

Failed logins:

sudo lastb

42. SSH Log Analysis

View SSH events:

sudo journalctl -u ssh

Last 24 hours:

sudo journalctl -u ssh --since "24 hours ago"

Failed attempts:

sudo journalctl -u ssh | grep -Ei "failed|invalid"

Successful authentication:

sudo journalctl -u ssh | grep -Ei "accepted"

43. Cron Persistence Hunting

Root cron:

sudo crontab -l

System cron:

sudo cat /etc/crontab

Cron directories:

sudo find /etc/cron* -type f -ls

Check all users:

for user in $(cut -d: -f1 /etc/passwd); do echo "===== $user =====" sudo crontab -u "$user" -l 2>/dev/null done

Unknown cron entries should be investigated.

44. Systemd Persistence Hunting

Enabled services:

systemctl list-unit-files --state=enabled

Running services:

systemctl --type=service --state=running

Timers:

systemctl list-timers --all

Inspect a suspicious service:

systemctl status SERVICE_NAME

Configuration:

systemctl cat SERVICE_NAME

45. Web-Shell Hunting

Find recently modified PHP files:

sudo find /var/www \ -type f \ -name "*.php" \ -mtime -7 \ -ls

Search uploads:

sudo find /var/www \ -type f \ -path "*/uploads/*" \ -name "*.php" \ -print

Search suspicious functions:

sudo grep -RniE \ 'eval\(|base64_decode\(|shell_exec\(|passthru\(|system\(' \ /var/www

These searches generate investigation leads.

They do not prove that a file is malicious.

46. Recently Modified Website Files

Last 24 hours:

sudo find /var/www \ -type f \ -mtime -1 \ -ls

Last 7 days:

sudo find /var/www \ -type f \ -mtime -7 \ -ls

Last 14 days:

sudo find /var/www \ -type f \ -mtime -14 \ -ls

This is particularly useful after a reported website compromise.

47. World-Writable Files

Find world-writable files:

sudo find /var/www \ -type f \ -perm -0002 \ -ls

Directories:

sudo find /var/www \ -type d \ -perm -0002 \ -ls

Review every result.

48. Executable Files in Web Roots

sudo find /var/www \ -type f \ -perm /111 \ -ls

Unexpected executable files should be investigated.

49. Hidden Files

sudo find /var/www \ -type f \ -name ".*" \ -ls

Remember that legitimate files such as:

.htaccess .user.ini

may exist.

50. Nginx Investigation

List logs:

sudo ls -lah /var/log/nginx/

Follow access log:

sudo tail -f /var/log/nginx/access.log

Follow error log:

sudo tail -f /var/log/nginx/error.log

Search common attack indicators:

sudo grep -Ei \ "wp-admin|xmlrpc|\.env|phpmyadmin|/shell|cmd=" \ /var/log/nginx/access.log

The search patterns should be adapted to the actual application.

51. WordPress Security Use Case

WordPress should be treated as both an application and an infrastructure workload.

Review:

wp-admin/ wp-includes/ wp-content/

Particular attention:

wp-content/uploads/ wp-content/plugins/ wp-content/themes/

Search:

sudo find /var/www \ -type f \ -name "*.php" \ -mtime -14 \ -ls

Search uploads:

sudo find /var/www \ -path "*/uploads/*" \ -name "*.php" \ -print

Review:

52. Joomla Security Use Case

Review:

configuration.php administrator/ components/ plugins/ modules/ templates/ media/ images/ cache/ tmp/

Find recent changes:

sudo find /var/www \ -type f \ -mtime -14 \ -ls

PHP:

sudo find /var/www \ -type f \ -name "*.php" \ -mtime -14 \ -ls

Investigate:

53. Magento Security Use Case

Magento combines many components:

PHP Composer MariaDB Redis Nginx Cron Admin APIs Extensions Themes Media Cache

Review:

app/ pub/ vendor/ generated/ var/ bin/

Particularly:

pub/media/ app/code/ app/design/

Find recent PHP changes:

sudo find /path/to/magento \ -type f \ -name "*.php" \ -mtime -14 \ -ls

Check Magento version:

php bin/magento --version

Check cron:

php bin/magento cron:status

Check Composer:

composer show

54. Database Isolation

Check MariaDB:

sudo ss -lntp | grep 3306

Check Redis:

sudo ss -lntp | grep 6379

Production architecture should normally be:

Internet | v Nginx | v Application | v Private Docker Network | +---- MariaDB | +---- Redis

Not:

Internet | +---- 3306 ---> MariaDB | +---- 6379 ---> Redis

55. Database Security

Review MariaDB:

sudo systemctl status mariadb

If installed directly on Ubuntu:

sudo mysql_secure_installation

Review database users:

SELECT User, Host FROM mysql.user;

Review databases:

SHOW DATABASES;

The exact hardening procedure depends on the MariaDB version and deployment architecture.

56. Redis Security

Check service:

sudo systemctl status redis-server

Check listener:

sudo ss -lntp | grep 6379

Redis should generally be restricted to:

Never assume that a Redis instance is safe simply because it does not contain a traditional relational database.

57. Backup Architecture

A production backup system should not depend exclusively on the same VPS.

Recommended:

PRODUCTION VPS | +------------+------------+ | | v v Local Backup Remote Backup | v Off-site Copy

Back up:

Website files Database Docker Compose Dockerfiles Nginx configuration TLS configuration Application configuration Deployment scripts

Protect secrets appropriately.

58. Database Backup

Example MariaDB backup:

mysqldump \ -u root \ -p \ --single-transaction \ --all-databases \ > /backup/all-databases.sql

Compress:

gzip /backup/all-databases.sql

For production, database credentials should be supplied securely rather than embedded directly into scripts.

59. Website Backup Script

Create:

sudo nano /usr/local/sbin/backup-web.sh

Example:

#!/bin/bash set -euo pipefail BACKUP_ROOT="/backup" DATE=$(date +"%Y-%m-%d_%H-%M-%S") DEST="$BACKUP_ROOT/$DATE" mkdir -p "$DEST" echo "Backup started: $(date)" rsync -a \ /var/www/ \ "$DEST/www/" echo "Backup completed: $(date)"

Make executable:

sudo chmod 750 /usr/local/sbin/backup-web.sh

Run:

sudo /usr/local/sbin/backup-web.sh

60. VPS Security Audit Script

Create:

sudo nano /usr/local/sbin/vps-security-audit.sh

Use:

#!/bin/bash REPORT="/var/log/vps-security-audit.log" { echo "======================================" echo "VPS SECURITY AUDIT" echo "Date: $(date)" echo "Hostname: $(hostname)" echo "======================================" echo echo "=== OS ===" cat /etc/os-release echo echo "=== Kernel ===" uname -a echo echo "=== Listening Ports ===" ss -tulpn echo echo "=== UFW ===" ufw status verbose echo echo "=== Docker Containers ===" docker ps -a 2>/dev/null || true echo echo "=== Docker Published Ports ===" docker ps --format "table {{.Names}}\t{{.Ports}}" 2>/dev/null || true echo echo "=== SSH Activity ===" journalctl -u ssh --since "24 hours ago" | grep -Ei "failed|invalid|accepted" || true echo echo "=== Enabled Services ===" systemctl list-unit-files --state=enabled echo echo "=== Timers ===" systemctl list-timers --all echo echo "=== Disk ===" df -h echo echo "=== Memory ===" free -h echo echo "=== Top CPU Processes ===" ps aux --sort=-%cpu | head -15 echo echo "=== Top Memory Processes ===" ps aux --sort=-%mem | head -15 echo echo "=== AUDIT COMPLETE ===" } | tee "$REPORT"

Make executable:

sudo chmod 750 /usr/local/sbin/vps-security-audit.sh

Run:

sudo /usr/local/sbin/vps-security-audit.sh

61. Schedule the Security Audit

Create:

sudo nano /etc/cron.d/vps-security-audit

Example:

30 1 * * * root /usr/local/sbin/vps-security-audit.sh

Review:

cat /etc/cron.d/vps-security-audit

62. Security Baseline

Create:

sudo mkdir -p /root/security-baseline

Save ports:

sudo ss -tulpn \ > /root/security-baseline/ports.txt

Firewall:

sudo ufw status verbose \ > /root/security-baseline/ufw.txt

Services:

systemctl list-unit-files --state=enabled \ > /root/security-baseline/services.txt

Timers:

systemctl list-timers --all \ > /root/security-baseline/timers.txt

Docker:

docker ps -a \ > /root/security-baseline/docker.txt

This creates a reference against which future changes can be compared.

63. HTProtect and CMS Security

Infrastructure hardening should be combined with application-specific security.

For Joomla environments, HTProtect can form part of a broader Joomla security and hardening strategy.

The operational model should be:

Joomla Core + Extensions + Template + Web Server + HTProtect + Firewall + Malware Scanning + Rootkit Hunting + Backups

HTProtect should not be treated as a replacement for:

Instead, it should form another layer in the application-security stack.

64. Joomla Compromise Investigation

When SEO spam, redirects or suspicious content appear:

First preserve evidence.

Record:

date hostname who w

Network:

sudo ss -tunap

Processes:

ps auxf

Recent files:

sudo find /var/www \ -type f \ -mtime -14 \ -ls

Malware:

sudo clamscan -r --infected /var/www/

Rootkits:

sudo rkhunter --check sudo chkrootkit

Persistence:

systemctl list-timers --all systemctl list-unit-files --state=enabled sudo crontab -l

Then investigate the initial entry point.

65. Incident Response Procedure

If compromise is suspected:

SECURITY ALERT | v Preserve Evidence | v Identify Scope | v Isolate | v Investigate | +---------+---------+ | | v v Malware Hunt Persistence Hunt | | +---------+---------+ | v Find Entry Point | v Remediate | v Patch Vulnerability | v Rotate Credentials | v Restore Trusted Data | v Monitor

66. Preserve Evidence

Do not immediately delete suspicious files.

Capture:

date hostname who w last

Network:

sudo ss -tunap \ > /root/incident-network.txt

Processes:

ps auxf \ > /root/incident-processes.txt

Services:

systemctl list-unit-files --state=enabled \ > /root/incident-services.txt

Timers:

systemctl list-timers --all \ > /root/incident-timers.txt

67. When to Rebuild the VPS

If there is evidence of deep operating-system compromise, attempting to clean every malicious modification may not provide sufficient confidence.

Consider:

Known-good VPS image | v Patch OS | v Configure firewall | v Harden SSH | v Install required software | v Restore trusted application | v Restore clean database/data | v Rotate credentials | v Security test | v Production

The decision to rebuild should depend on the nature and scope of the compromise.

68. External Security Testing

From an authorized external system:

nmap -Pn YOUR_SERVER_IP

The expected public exposure should match the documented architecture.

Typical:

22/tcp 80/tcp 443/tcp

Internal services should normally appear:

closed

or:

filtered

Do not scan systems without authorization.

69. Internal Port Validation

On the VPS:

sudo ss -lntup

Create a documented port inventory:

22 SSH 80 HTTP 443 HTTPS

Every additional listener must have a business or technical reason.

70. Security Monitoring

Monitor:

SSH UFW Nginx Apache Docker PHP MariaDB Redis CMS Cron systemd Filesystem CPU Memory Disk Network

Useful commands:

journalctl -xe

Recent system logs:

sudo journalctl --since "24 hours ago"

Kernel:

sudo journalctl -k

71. Disk Monitoring

df -h

Directory usage:

sudo du -xhd1 / | sort -h

Web:

sudo du -xhd1 /var/www | sort -h

Docker:

docker system df

Unexpected disk growth may indicate:

72. Container Monitoring

List:

docker ps -a

Resource usage:

docker stats

Logs:

docker logs CONTAINER

Last 100 lines:

docker logs --tail 100 CONTAINER

Follow:

docker logs -f CONTAINER

Images:

docker images --digests

Volumes:

docker volume ls

73. Docker Image Hygiene

Inspect:

docker images

Disk:

docker system df

Remove unused objects only after confirming they are not required.

Avoid blindly executing:

docker system prune -a

on production servers.

74. Application Security Testing

Security testing should include:

Authentication Authorization Session management Input validation File uploads API endpoints Admin interfaces Plugins Extensions Dependencies Configuration

The infrastructure firewall cannot protect against every application-layer vulnerability.

75. Security Layers by Attack Type

Attack

Primary Controls

Port scanning

Cloud firewall + UFW

SSH brute force

SSH keys + source restriction + Fail2ban

Web attack

WAF + web server + application security

Malicious upload

Application controls + ClamAV

Web shell

File integrity + malware scanning + rootkit hunting

Docker exposure

Cloud firewall + Docker network controls

Database exposure

Private network + firewall

Credential theft

SSH keys + credential management

Persistence

rkhunter + chkrootkit + AIDE + system inspection

Data loss

Backups

Deep compromise

Incident response + rebuild

76. Production Deployment Lifecycle

A secure deployment should follow:

1. DISCOVER | 2. INVENTORY | 3. DESIGN | 4. HARDEN | 5. FIREWALL | 6. DEPLOY | 7. TEST | 8. MONITOR | 9. SCAN | 10. REVIEW | 11. BACKUP | 12. IMPROVE

Security is therefore an ongoing engineering activity.

77. Contabo Production Checklist

Provider Layer

Ubuntu Layer

Docker Layer

Application Layer

Detection Layer

Recovery Layer

78. Security Maturity Model

Level 1 — Basic

Cloud Firewall UFW SSH Keys TLS Updates Backups

Level 2 — Hardened

Fail2ban Docker isolation ClamAV Rootkit hunting Lynis File permissions

Level 3 — Managed

WAF Centralized logging AIDE Vulnerability management Automated backups Incident response

Level 4 — Engineering Security

CI/CD security Container scanning Infrastructure as Code Automated compliance Threat modeling Continuous security testing AI-assisted security operations

79. Security for SMEs

Small and medium-sized businesses frequently have limited IT staff.

The security architecture should therefore prioritize:

Simple Automated Documented Repeatable Recoverable Measurable

A practical SME baseline is:

Cloud Firewall + UFW + SSH Hardening + Fail2ban + Docker Isolation + TLS + CMS Hardening + ClamAV + Rootkit Hunting + Monitoring + Backup

This provides a substantial security foundation without requiring a large enterprise security team.

80. Strategic Role of KeenComputer

KeenComputer can serve as the infrastructure and digital-transformation partner.

Potential services include:

The objective should be to transform VPS administration from an ad-hoc activity into a documented operational process.

81. Strategic Role of IAS-Research

IAS-Research can provide the engineering and research layer.

Potential activities include:

The role is especially relevant where the VPS is part of a larger engineering or industrial system.

82. Strategic Role of KeenDirect

KeenDirect can focus on the eCommerce platform layer.

Potential services include:

The architecture becomes:

BUSINESS | +-----------+-----------+ | | | v v v KeenComputer IAS-Research KeenDirect Infrastructure Engineering eCommerce | | | +-----------+-----------+ | v Secure Platform

83. Business Value

VPS security is not simply an IT expense.

It protects:

A compromised website can cause:

Security Incident | +--> Downtime +--> Revenue Loss +--> SEO Damage +--> Customer Trust Loss +--> Recovery Cost +--> Data Exposure +--> Reputation Damage

Security controls therefore contribute directly to business resilience.

84. Recommended Operating Model

A mature VPS security program should operate continuously.

DISCOVER | v HARDEN | v MONITOR | v DETECT | v INVESTIGATE | v REMEDIATE | v RECOVER | v TEST | v IMPROVE | +-------> DISCOVER

85. Final Engineering Conclusions

The Contabo VPS example demonstrates that modern VPS security cannot be reduced to installing UFW.

A production security architecture should combine:

Cloud Firewall + UFW / nftables + SSH Hardening + Fail2ban + Docker Isolation + Nginx / Apache + WAF + CMS Hardening + Database Isolation + ClamAV + Rootkit Hunting + File Integrity + Logging + Monitoring + Backup + Incident Response

The most important engineering principle is:

Security should be layered, continuously monitored, tested and recoverable.

The cloud firewall protects the perimeter.

UFW protects the host.

Docker isolation protects internal application boundaries.

The web server and WAF protect the HTTP layer.

WordPress, Joomla and Magento hardening protects the application.

ClamAV provides malware scanning.

Rootkit Hunter and chkrootkit provide additional persistence/rootkit investigation capabilities.

AIDE provides file-integrity monitoring.

Fail2ban provides automated response to repeated authentication abuse.

Backups provide recovery.

Incident response provides the process for handling failure.

Together these controls transform a VPS from a simple Internet-connected server into a managed production security platform.

86. Master Command Reference

System

hostnamectl uname -a cat /etc/os-release nproc free -h df -h lsblk ip addr ip route

Updates

sudo apt update sudo apt upgrade -y sudo apt autoremove -y sudo apt autoclean

Network

sudo ss -tulpn sudo ss -lntup sudo ss -tunap sudo lsof -i -P -n

Firewall

sudo ufw status verbose sudo ufw status numbered sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable sudo ufw logging medium

Firewall inspection

sudo iptables -L -n -v sudo iptables -L DOCKER -n -v sudo iptables -L DOCKER-USER -n -v sudo nft list ruleset

Docker

docker ps docker ps -a docker images docker network ls docker network inspect bridge docker volume ls docker stats docker system df docker ps --format "table {{.Names}}\t{{.Ports}}" docker logs CONTAINER docker inspect CONTAINER

SSH

sudo sshd -t sudo systemctl restart ssh sudo journalctl -u ssh sudo journalctl -u ssh --since "24 hours ago"

Fail2ban

sudo systemctl status fail2ban sudo fail2ban-client status sudo fail2ban-client status sshd

ClamAV

sudo freshclam sudo clamscan -r --infected /var/www/

Rootkit Hunter

sudo rkhunter --update sudo rkhunter --propupd sudo rkhunter --check

Chkrootkit

sudo chkrootkit

Lynis

sudo lynis audit system sudo lynis audit system --quick

AIDE

sudo aideinit sudo aide --check

Processes

ps auxf ps aux --sort=-%cpu | head -20 ps aux --sort=-%mem | head -20 htop

Users

cut -d: -f1 /etc/passwd getent group sudo last sudo lastb

Cron

sudo crontab -l sudo cat /etc/crontab sudo find /etc/cron* -type f -ls

Systemd

systemctl list-unit-files --state=enabled systemctl --type=service --state=running systemctl list-timers --all

PHP investigation

sudo find /var/www -type f -name "*.php" -mtime -7 -ls sudo grep -RniE \ 'eval\(|base64_decode\(|shell_exec\(|passthru\(|system\(' \ /var/www

Web logs

sudo tail -f /var/log/nginx/access.log sudo tail -f /var/log/nginx/error.log

Disk

df -h sudo du -xhd1 / | sort -h sudo du -xhd1 /var/www | sort -h

87. Final Security Standard

For a production Contabo VPS hosting WordPress, Joomla, Magento or Docker applications, the recommended minimum standard is:

PRODUCTION VPS | +---------------+---------------+ | | v v CLOUD FIREWALL BACKUP | | v | UFW / HOST FIREWALL | | | v | SSH HARDENING | | | v | FAIL2BAN | | | v | NGINX / APACHE | | | v | WAF | | | v | DOCKER | | | +---+---+ | | | | | v v v | WP JML MAG | | | | | +---+---+ | | | v | PRIVATE SERVICES | | | +---+---+ | | | | v v | MariaDB Redis | | +-------------------------------+ | v SECURITY OPERATIONS | +------+------+------+------+ | | | | ClamAV rkhunter AIDE Lynis | v MONITORING | v INCIDENT RESPONSE

The operating principle is simple:

Prevent → Harden → Isolate → Monitor → Detect → Investigate → Recover → Improve.

That principle provides a practical security foundation for SMEs operating production websites, eCommerce platforms and Docker-based applications on Contabo and other VPS providers.

References and Standards