BlogTutorialsHow to Host Your WordPress Website on a €4.49/Month VPS

How to Host Your WordPress Website on a €4.49/Month VPS

Adrian Silaghi
Adrian Silaghi
February 3, 2026
14 min read
92 views
#wordpress #vps #hosting #lemp #nginx #php #ssl #performance

WordPress powers over 40% of all websites on the internet, yet most people overpay for hosting. Managed WordPress plans from providers like WP Engine, Kinsta, or SiteGround charge $25-100+ per month for resources you can get for a fraction of the price on a VPS. In this guide, you'll set up a production-ready WordPress site on a DanubeData DD Nano VPS—2 dedicated AMD Zen4 vCPUs, 2GB DDR5 RAM, and 40GB NVMe SSD—for just €4.49/month.

Why Host WordPress on a VPS?

  • Full Root Access: Install any PHP extension, caching layer, or server software you need—no host restrictions
  • Dedicated Resources: No noisy neighbors slowing your site during traffic spikes
  • Cost Savings: A DD Nano VPS at €4.49/month replaces $25-100/month managed hosting
  • GDPR Compliance: Your data stays in Germany on European infrastructure
  • Performance: NVMe storage and DDR5 memory deliver fast page loads
  • Scalability: Upgrade to a larger plan with one click when you outgrow your current setup

What You'll Build

By the end of this guide, you'll have a production-ready WordPress site with:

  • A lean LEMP stack (Linux, Nginx, MariaDB, PHP 8.3) optimized for 2GB RAM
  • Free SSL/TLS certificates via Let's Encrypt with automatic renewal
  • FastCGI caching for sub-second page loads without plugins
  • Gzip and Brotli compression for smaller page sizes
  • Security hardening with a firewall, Fail2Ban, and secure headers
  • Automated daily backups

Prerequisites

  • A DanubeData account
  • A domain name with DNS access (e.g., example.com)
  • Basic familiarity with the Linux command line

Step 1: Create Your DD Nano VPS

  1. Log in to the DanubeData dashboard
  2. Click Create VPS
  3. Select the DD Nano plan (2 vCPU, 2GB RAM, 40GB NVMe)
  4. Choose Ubuntu 24.04 LTS as the operating system
  5. Add your SSH public key for secure access
  6. Click Create—your VPS will be ready in under 60 seconds

Once the VPS is running, note the IPv4 address from your dashboard. Point your domain's DNS A record to this IP:

# DNS records to configure at your registrar
example.com        A    YOUR_VPS_IP
www.example.com    A    YOUR_VPS_IP

Allow DNS propagation before continuing. You can verify with:

dig +short example.com

Step 2: Initial Server Setup

SSH into your VPS and secure the base system:

# Connect to your VPS
ssh root@YOUR_VPS_IP

# Update system packages
apt update && apt upgrade -y

# Create a non-root user
adduser deploy
usermod -aG sudo deploy

# Copy SSH key to the new user
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

# Configure firewall
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable

# Switch to new user for remaining steps
su - deploy

Harden SSH Access

Edit the SSH configuration to disable password authentication:

sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

Step 3: Install the LEMP Stack

We'll use MariaDB instead of MySQL—it uses less memory and performs better on constrained systems.

Install Nginx

sudo apt install nginx -y
sudo systemctl enable nginx

Install MariaDB

sudo apt install mariadb-server -y
sudo systemctl enable mariadb

# Secure the installation
sudo mysql_secure_installation

During the secure installation wizard:

  • Set a strong root password
  • Remove anonymous users: Y
  • Disallow root login remotely: Y
  • Remove test database: Y
  • Reload privilege tables: Y

Create the WordPress Database

sudo mysql -u root -p
CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'YOUR_STRONG_PASSWORD_HERE';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Generate a strong password with openssl rand -base64 24 and save it somewhere safe.

Install PHP 8.3

sudo apt install php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd 
    php8.3-intl php8.3-mbstring php8.3-xml php8.3-zip 
    php8.3-imagick php8.3-bcmath php8.3-opcache -y

Step 4: Optimize PHP for 2GB RAM

With 2GB of RAM, every megabyte counts. Tune PHP-FPM to use memory efficiently:

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Find and update the following values:

; Use static process management for predictable memory usage
pm = static
pm.max_children = 4
pm.max_requests = 500

; Match the user Nginx runs as
user = www-data
group = www-data

Why these values? Each PHP-FPM worker uses roughly 40-60MB of RAM. With 4 workers, PHP uses around 200MB, leaving plenty of room for Nginx, MariaDB, and the OS. If your site has very light traffic, you can reduce pm.max_children to 3.

Next, tune the PHP configuration:

sudo nano /etc/php/8.3/fpm/php.ini

Update these settings:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 128M
max_execution_time = 300
max_input_vars = 3000

; OPcache settings - critical for performance
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.validate_timestamps = 1

Restart PHP-FPM:

sudo systemctl restart php8.3-fpm

Step 5: Optimize MariaDB for 2GB RAM

Create a custom MariaDB configuration tuned for a single WordPress site on limited memory:

sudo nano /etc/mysql/mariadb.conf.d/99-wordpress.cnf
[mysqld]
# InnoDB settings
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Query cache (useful for WordPress read-heavy workload)
query_cache_type = 1
query_cache_size = 32M
query_cache_limit = 2M

# Connection limits
max_connections = 50
table_open_cache = 400

# Temp tables
tmp_table_size = 32M
max_heap_table_size = 32M

# Slow query log (enable to find bottlenecks)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
sudo systemctl restart mariadb

Step 6: Download and Configure WordPress

# Download WordPress
cd /tmp
curl -LO https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz

# Move to web root
sudo mv wordpress /var/www/wordpress
sudo chown -R www-data:www-data /var/www/wordpress
sudo chmod -R 755 /var/www/wordpress

# Create wp-config.php
cd /var/www/wordpress
sudo cp wp-config-sample.php wp-config.php

Edit the configuration with your database credentials:

sudo nano /var/www/wordpress/wp-config.php

Update the database settings:

define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'YOUR_STRONG_PASSWORD_HERE' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', 'utf8mb4_unicode_ci' );

Generate unique authentication keys at api.wordpress.org/secret-key and replace the placeholder lines in wp-config.php.

Add these performance and security options before the line /* That's all, stop editing! */:

/** Limit post revisions to save database space */
define( 'WP_POST_REVISIONS', 5 );

/** Increase memory available to WordPress */
define( 'WP_MEMORY_LIMIT', '128M' );

/** Disable the built-in file editor for security */
define( 'DISALLOW_FILE_EDIT', true );

/** Auto-save interval in seconds */
define( 'AUTOSAVE_INTERVAL', 120 );

/** Force HTTPS for admin and logins */
define( 'FORCE_SSL_ADMIN', true );

Step 7: Configure Nginx with FastCGI Caching

FastCGI caching serves pages directly from disk without hitting PHP at all. This is the single biggest performance optimization for WordPress on a small VPS—cached pages load in under 50ms.

sudo nano /etc/nginx/sites-available/wordpress
# FastCGI cache configuration
fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:10m inactive=60m max_size=512m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

server {
    listen 80;
    server_name example.com www.example.com;

    # Redirect HTTP to HTTPS
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Redirect www to non-www
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    root /var/www/wordpress;
    index index.php index.html;

    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

    # Upload size limit
    client_max_body_size 64M;

    # FastCGI cache bypass rules
    set $skip_cache 0;

    # Don't cache logged-in users
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
        set $skip_cache 1;
    }

    # Don't cache POST requests or URLs with query strings
    if ($request_method = POST) {
        set $skip_cache 1;
    }
    if ($query_string != "") {
        set $skip_cache 1;
    }

    # Don't cache admin or login pages
    if ($request_uri ~* "/wp-admin/|/wp-login.php|/xmlrpc.php|wp-.*.php") {
        set $skip_cache 1;
    }

    # WordPress permalinks
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # PHP handling with FastCGI caching
    location ~ .php$ {
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_read_timeout 300;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;

        # FastCGI cache
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_valid 404 1m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        add_header X-Cache-Status $upstream_cache_status;
    }

    # Block access to sensitive files
    location ~ /. {
        deny all;
    }

    location ~* /(?:uploads|files)/.*.php$ {
        deny all;
    }

    location = /wp-config.php {
        deny all;
    }

    # Block XML-RPC (common attack vector)
    location = /xmlrpc.php {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Cache static assets for 1 year
    location ~* .(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|webp|avif)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Deny access to sensitive WordPress files
    location ~* /(wp-config.php|readme.html|license.txt) {
        deny all;
    }
}

Enable the site and create the cache directory:

# Remove default site
sudo rm /etc/nginx/sites-enabled/default

# Enable WordPress site
sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/

# Create cache directory
sudo mkdir -p /var/cache/nginx/wordpress
sudo chown www-data:www-data /var/cache/nginx/wordpress

# Test configuration
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

Step 8: Set Up Free SSL with Let's Encrypt

# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Obtain certificate (Nginx must be running on port 80 first)
sudo certbot --nginx -d example.com -d www.example.com

# Verify auto-renewal is active
sudo certbot renew --dry-run

Certbot automatically configures a systemd timer that renews certificates before they expire. No cron jobs needed.

Step 9: Complete the WordPress Installation

Open https://example.com in your browser. You'll see the WordPress installation wizard:

  1. Select your language
  2. Enter a site title, admin username, and a strong password
  3. Enter your email address
  4. Click Install WordPress

Log in at https://example.com/wp-admin to access the dashboard.

Recommended Plugins

Keep your plugin count low to conserve memory. These are the essentials:

  • Nginx Helper: Purges the FastCGI cache when you publish or update content
  • Wordfence Security: Firewall and login protection
  • UpdraftPlus: Scheduled backups to cloud storage
  • Yoast SEO or Rank Math: Search engine optimization
  • ShortPixel or Imagify: Image compression to save storage

Important: You do not need a caching plugin like WP Super Cache or W3 Total Cache. Nginx FastCGI caching handles this at the server level, which is faster and uses less memory than any PHP-based caching plugin.

Step 10: Set Up Automated Backups

Create a backup script that saves your database and WordPress files daily:

sudo nano /home/deploy/backup-wordpress.sh
#!/bin/bash
BACKUP_DIR="/home/deploy/backups"
DATE=$(date +%Y%m%d)
RETENTION_DAYS=14

mkdir -p "$BACKUP_DIR"

# Backup database
mariadb-dump -u wpuser -p'YOUR_STRONG_PASSWORD_HERE' wordpress | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"

# Backup WordPress files (excluding cache)
tar -czf "$BACKUP_DIR/wp_files_$DATE.tar.gz" 
    --exclude='/var/www/wordpress/wp-content/cache' 
    /var/www/wordpress/wp-content/

# Remove old backups
find "$BACKUP_DIR" -type f -mtime +$RETENTION_DAYS -delete

echo "[$(date)] Backup completed: db_$DATE.sql.gz, wp_files_$DATE.tar.gz"
chmod +x /home/deploy/backup-wordpress.sh

# Schedule daily backups at 3 AM
(crontab -l 2>/dev/null; echo "0 3 * * * /home/deploy/backup-wordpress.sh >> /home/deploy/backups/backup.log 2>&1") | crontab -

Tip: For off-site backup redundancy, configure UpdraftPlus to send backups to DanubeData Object Storage (S3-compatible, €3.99/month with 1TB included).

Step 11: Security Hardening

Install Fail2Ban

Protect against brute-force login attempts:

sudo apt install fail2ban -y

sudo nano /etc/fail2ban/jail.d/wordpress.conf
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
findtime = 300

Create the filter:

sudo nano /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =
sudo systemctl restart fail2ban

Enable Automatic Security Updates

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

Step 12: Set Up Swap Space

A small swap file acts as a safety net during occasional memory spikes, preventing the Linux OOM killer from terminating your services:

# Create a 1GB swap file
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Make it permanent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Optimize swappiness (low value = prefer RAM)
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Memory Usage Breakdown

Here's how the 2GB of RAM is allocated across the stack:

Service RAM Usage Notes
Ubuntu 24.04 OS ~150 MB Base system with systemd
Nginx ~30 MB Lightweight with worker_processes auto
MariaDB (InnoDB) ~350 MB 256MB buffer pool + overhead
PHP-FPM (4 workers) ~200 MB ~50MB per worker
OPcache ~128 MB Shared across all PHP workers
Buffers/Cache ~150 MB Linux disk cache (freed when needed)
Total ~1,008 MB ~1GB free + 1GB swap safety net

This leaves plenty of headroom for traffic spikes. The FastCGI cache means most visitors are served static files directly by Nginx, so PHP-FPM and MariaDB stay idle under normal load.

Performance Benchmarks

Here's what you can expect from this setup on a DD Nano VPS:

Metric Cached Pages Uncached Pages
Time to First Byte (TTFB) < 30ms 150-300ms
Requests/second 1,000+ 30-50
Concurrent Users 500+ ~20
Monthly Visitors Supported 100,000+ ~10,000

With FastCGI caching enabled, a DD Nano VPS comfortably handles 100,000+ monthly visitors for a typical blog or business website.

Cost Comparison: DanubeData vs Managed WordPress Hosting

Provider Plan Monthly Cost Storage Bandwidth Visitors
DanubeData DD Nano 2 vCPU, 2GB RAM €4.49/mo 40GB NVMe 20TB 100,000+
WP Engine Startup $30/mo 10GB 50GB 25,000
Kinsta Single 35k $35/mo 10GB 100GB CDN 35,000
SiteGround GrowBig $25/mo 20GB Unmetered* ~25,000
Cloudways 2GB $28/mo 50GB 2TB ~30,000

At €4.49/month, the DanubeData DD Nano VPS costs 5-8x less than managed WordPress hosting while delivering more storage, more bandwidth, and better performance. Over a year, that's a saving of €250-350.

When to Upgrade

The DD Nano plan handles most WordPress sites with ease. Consider upgrading to the DD Micro (3 vCPU, 4GB RAM, 80GB NVMe, €7.49/month) if you:

  • Run WooCommerce with a large product catalog
  • Need to host multiple WordPress sites on one server
  • Use memory-heavy plugins (page builders, complex forms)
  • Want to add Redis object caching for dynamic-heavy sites
  • Consistently see traffic above 200,000 monthly visitors

Upgrading on DanubeData is seamless—your data and IP address stay the same.

Quick Reference: Useful Commands

# Check memory usage
free -h

# Monitor resource usage in real time
htop

# View Nginx error log
sudo tail -f /var/log/nginx/error.log

# View PHP-FPM error log
sudo tail -f /var/log/php8.3-fpm.log

# Purge FastCGI cache
sudo rm -rf /var/cache/nginx/wordpress/*

# Restart all services
sudo systemctl restart nginx php8.3-fpm mariadb

# Check SSL certificate expiry
sudo certbot certificates

# Test Nginx configuration
sudo nginx -t

Get Started

  1. Create your DanubeData account
  2. Deploy a DD Nano VPS with Ubuntu 24.04
  3. Follow this guide to set up WordPress
  4. Point your domain and go live

Perfect for: Personal blogs, business websites, portfolios, small WooCommerce shops, membership sites, and anyone who wants fast, affordable WordPress hosting in Europe with GDPR compliance.

Questions about hosting WordPress on a DanubeData VPS? Contact our team or explore our documentation for more guides.

Share this article

Ready to Get Started?

Deploy your infrastructure in minutes with DanubeData's managed services.