Installing a Web Server on an Empty Server: From Zero to the First Request

The correct order for installing a web server, PHP, and a database on an empty server, testing each layer before moving to the next, and the errors you'll actually run into along the way.

6 min Updated 18 Oct 2026

You've bought the server, logged in via SSH, and now you're staring at an empty prompt. curl localhost returns nothing, systemctl status nginx says the unit wasn't found, and you don't know whether to bring up the web server first or PHP. If you get the order wrong right here, two hours later you'll be fighting a 502 Bad Gateway error and a log that contains nothing useful.

The correct order is: web server, then PHP, then database. Test each layer before moving to the next. This takes ten minutes and saves you hours later.

Before installing the web server, check these three things

First, that you're actually on the server you think you are. Run hostnamectl and ip a. If you have a cloud server, you may see a private IP while the public IP is elsewhere.

Second, the system clock. If the clock is behind or ahead, SSL and cookies will behave strangely later:

timedatectl set-timezone Asia/Tehran
timedatectl status

Third, disk space and RAM. On a server with 1 GB of RAM, MySQL with default settings will easily get OOM-killed. Check free -m and df -h before any installation.

Choosing a stack: Nginx or Apache?

My short answer: Nginx. For high concurrency, lower RAM usage, and serving static files, Nginx is the better choice. I choose Apache when you have an application that depends on .htaccess and you don't want to rewrite it.

CriterionNginxApache
Processing modelEvent-driven, multi-processProcess/thread per connection
RAM usage under heavy loadLowerHigher
Static filesFasterAcceptable
Per-directory configurationNone.htaccess

On Debian 12 or Ubuntu 22.04 and later:

apt update
apt install -y nginx
systemctl enable --now nginx
curl -I http://127.0.0.1

If you get HTTP/1.1 200 OK, the first layer is done. If not, check journalctl -u nginx -n 50. The most common cause: port 80 is already occupied by something like Apache or a control panel. Use ss -tlnp | grep :80 to see who's listening.

Installing PHP and connecting it to the web server

Install PHP as FPM, not as an Apache module. FPM is a separate process, you can restart it independently, and Nginx talks to it over a Unix socket.

apt install -y php8.2-fpm php8.2-mysql php8.2-curl php8.2-mbstring
systemctl enable --now php8.2-fpm
ls -l /run/php/php8.2-fpm.sock

Point that socket in the Nginx site config:

server {
    listen 80;
    server_name example.com;
    root /var/www/example;
    index index.php;

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

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

Now drop in a test file and check it from outside the server with curl -I http://example.com/info.php. If you get 502, it almost always means the socket path in the config doesn't match the real path, or you upgraded the PHP version and the socket name changed. This is where people mess up: they write the config with php7.4-fpm.sock, then upgrade PHP to 8.2 and the site goes down with a 502, while PHP itself is healthy and systemctl status php8.2-fpm shows green.

Delete the test file after confirming. An open phpinfo() on the internet gives anyone a complete roadmap of your versions and modules.

Database: MySQL or MariaDB, and the settings that actually matter

Install MariaDB unless your application explicitly requires MySQL 8. Command compatibility is high and it's lighter on low-RAM servers.

apt install -y mariadb-server
mysql_secure_installation

In mysql_secure_installation, answer yes to all questions, especially removing the anonymous user and disabling remote root login. More details are in the guide on MySQL security and restricting access.

A point that's rarely mentioned: bind-address in MariaDB defaults to 127.0.0.1, and that's correct. If you changed it to 0.0.0.0 to connect from another server, you've opened port 3306 to the internet. In that case, at minimum restrict access to a specific IP with ufw allow from 10.0.0.5 to any port 3306.

For PHP applications, create the database user with localhost, not %:

CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strong-password';
GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;

Now connect from inside PHP with PDO and run a SELECT 1. If that works, all three layers are ready.

SSL and hardening, before you make the site public

Install Certbot and get a certificate. First condition: the domain must already point to the server's IP and port 80 must be open from outside. If DNS was just set up, it may take anywhere from a few minutes to a few hours; don't rush it and read the Certbot log.

apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com

The full steps and common errors are explained in installing a free certificate with Certbot. After that, close the firewall: only 22, 80, and 443 should remain open. If you have an admin panel, restrict its access to your own IP.

Testing each layer, in order

  1. curl -I http://127.0.0.1 on the server itself: is the web server alive?
  2. A simple PHP file that just has echo "ok";: is FPM connected?
  3. A PHP script that connects to the database: are the credentials correct?
  4. curl -I https://example.com from outside: are DNS, firewall, and SSL all healthy?

If you get stuck somewhere, instead of guessing, read the log for that layer: /var/log/nginx/error.log, journalctl -u php8.2-fpm, /var/log/mysql/error.log. In ninety percent of cases the answer is in those last few lines.

A note on resources: if you're bringing all of this up on a small VPS and the site becomes slow after installation, the problem is probably not configuration, it's a lack of RAM. Use free -m and vmstat 1 to see how much swap is being used. If you're swapping constantly, either increase the RAM or turn off unnecessary services. For more serious loads, migrating to a cloud server with upgradeable resources is less hassle than tuning a saturated machine.

If you'd rather not manage this whole path yourself and just upload your code, Linux hosting gives you this stack ready-made. But if the goal is learning or full control, this manual path is worth it.

Frequently asked questions

Why does my site give a 502 Bad Gateway error after installing PHP?

In most cases, the FPM socket path in the Nginx config doesn't match the real path on disk. Use ls /run/php/ to see the exact socket name and put that in fastcgi_pass. The second cause is that the PHP-FPM service didn't start at all; check systemctl status php8.2-fpm.

If both are correct, look at /var/log/nginx/error.log. The message connect() to unix:... failed (13: Permission denied) means the issue is the www-data user's access to the socket, not PHP itself.

Should I remove Apache if I'm installing Nginx?

If Apache is listening on port 80, Nginx won't come up, or the site goes to Apache and you think the Nginx config isn't taking effect. Use ss -tlnp | grep :80 to see which process has taken the port. If you don't need Apache, systemctl disable --now apache2 is enough; a full removal isn't necessary.

Which PHP version should I install?

The version your application officially supports, not the newest one available. If you're working with a CMS, check the requirements page for that version. Installing PHP 8.2 on an application written for 7.4 produces deprecated errors and sometimes fatal errors.

A practical tip: don't hardcode the PHP version in the socket name if you plan to upgrade later. Have a symlink or a variable in the config so the upgrade is a one-line change.

After installation, what's the first thing I should do?

Close the firewall and delete the test files. A leftover info.php on the internet shows anyone your exact PHP version, installation paths, and enabled modules. After that, set up automatic database backups; an installation without backups is an unfinished installation.

And if you ever lose access, know that there's a way back. Read up on the methods for reinstalling the server and working with rescue mode once before you actually need them.

Was this page helpful?