Setup guides

Installing WordPress on a VDS from scratch

Every step of installing WordPress on a bare server without a panel: the LEMP stack, database, permissions, SSL and hardening afterwards.

10 min read
WordPress emblem being installed on a server beside a web page

A panel-free installation shows you exactly what is happening on the server and leaves the resources a panel would consume to your application. For a single site, this route is lighter and more instructive.

If you plan to host several sites or open accounts for customers, a panel makes more sense; see our Plesk installation guide.

Preparation

We assume an empty Ubuntu 24.04 server. Before starting, update the system and confirm the domain points at it:

bashapt update && apt upgrade -y
dig +short yourdomain.com

The second command should return your server's IP.

1. Nginx, MariaDB and PHP

bashapt install -y nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-imagick

Secure the database server:

bashmysql_secure_installation

The script asks about a root password, removing anonymous users and dropping the test database. Answer yes to all.

2. Create a database and user

bashmysql -u root -p
textCREATE DATABASE wp_database DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'a-strong-password';
GRANT ALL PRIVILEGES ON wp_database.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Do not use the root user for WordPress. Give the application a dedicated user that can reach only its own database; if something is compromised, the damage stays there.

The utf8mb4 character set matters: it is what stores accented characters and emoji correctly.

3. Download WordPress

bashcd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz
mkdir -p /var/www/yourdomain.com
cp -r wordpress/* /var/www/yourdomain.com/

4. File permissions

This is where the balance between security and usability is set:

bashchown -R www-data:www-data /var/www/yourdomain.com
find /var/www/yourdomain.com -type d -exec chmod 755 {} \;
find /var/www/yourdomain.com -type f -exec chmod 644 {} \;

755 for directories, 644 for files. Do not use 777 — that widely repeated advice means any process on the server can modify your files.

5. The Nginx server block

Create /etc/nginx/sites-available/yourdomain.com:

textserver {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com;
    index index.php;

    client_max_body_size 64M;

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

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

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

That last block matters: it stops a PHP file that slips into the uploads directory from executing. It is one of the standard routes into a WordPress install.

client_max_body_size sets the media upload limit; the 1 MB default is too small for most sites.

Enable and test:

bashln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

6. Finish the install

Open your domain in a browser. WordPress takes you to the setup wizard; enter the database details from step 2.

Do not use `admin` as the administrator username. It is the first thing automated attacks try.

7. SSL

bashapt install -y certbot python3-certbot-nginx
certbot --nginx -d yourdomain.com -d www.yourdomain.com

After the certificate is installed, update the site address in WordPress settings to https:// too, otherwise you will get mixed content warnings.

After installation

  • Set up automated backups with a destination outside the server
  • Disable XML-RPC if you do not use it; it is a common brute-force target
  • Turn off the file editor: add define('DISALLOW_FILE_EDIT', true); to wp-config.php
  • For server-side hardening see our server security guide
  • For speed, read our WordPress optimization guide

If you would rather we handled the installation, we run setup and migration remotely.