Skip to content
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Login Client Area
ALL SYSTEMS OPERATIONAL
VPS

Install a LAMP Stack on a Fresh Ubuntu VPS: Full Guide

Getwebup 6 min read

If your VPS came bare - no control panel, no web server, nothing - and you'd rather run Apache than Nginx, this is the setup. LAMP (Linux, Apache, MySQL/MariaDB, PHP) is still the stack most WordPress installs, cPanel-style hosts, and .htaccess-dependent apps expect out of the box, and it's a fair bit more forgiving to configure than Nginx if you're used to shared hosting.

Before You Start

This walkthrough assumes Ubuntu 22.04 or 24.04, a non-root sudo user, and SSH key access already working. If your firewall is still wide open, close it down first - installing a web stack before locking down SSH just hands attackers something worth breaking into.

sudo apt update && sudo apt upgrade -y

Step 1: Install Apache

sudo apt install apache2 -y
sudo systemctl enable --now apache2

Open the firewall for HTTP and HTTPS:

sudo ufw allow 'Apache Full'
sudo systemctl status apache2

Load your VPS's IP in a browser. You should see the default "Apache2 Ubuntu Default Page." If nothing loads, check that port 80/443 are open both in UFW and in your VPS provider's separate network firewall (common on cloud dashboards - it's not the same thing as UFW).

Step 2: Install MySQL or MariaDB

MariaDB is the default on most current Ubuntu releases and is a drop-in replacement for MySQL:

sudo apt install mariadb-server -y
sudo mysql_secure_installation

Say yes to removing anonymous users, disabling remote root login, dropping the test database, and reloading privileges. Skipping this leaves a root account with no password sitting on the box - not something you want a scanner to find.

Create a dedicated database and user for your app rather than reusing root later:

sudo mysql -u root -p

CREATE DATABASE appdb;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-strong-password-here';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 3: Install PHP and Connect It to Apache

This is the one real fork in the road versus Nginx. Apache can run PHP two ways:

  • mod_php - PHP runs embedded inside the Apache process. Simple to set up, but every Apache worker carries the PHP interpreter's memory overhead even when serving static files.
  • PHP-FPM via mod_proxy_fcgi - PHP runs as a separate pool of workers, same as it does under Nginx. More setup, noticeably better memory use and concurrency under load.

For a small site, mod_php is fine and this is the fastest path:

sudo apt install php libapache2-mod-php php-mysql php-curl php-xml php-mbstring php-zip -y
sudo systemctl restart apache2

If you want PHP-FPM instead (recommended once you're running anything with real traffic, or migrating a site that already expects FPM):

sudo apt install php-fpm php-mysql php-curl php-xml php-mbstring php-zip -y
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2

Check the exact FPM service and conf name with ls /etc/apache2/conf-available/ | grep php - the version number depends on what Ubuntu shipped.

Test PHP is actually being processed, not downloaded as a raw file:

echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php

Visit http://your-server-ip/info.php. A rendered PHP info page means it's wired up correctly; a file download prompt means Apache still isn't handing .php files to the interpreter. Delete this file once you've confirmed it works - a public phpinfo page leaks server paths and module versions to anyone who finds it.

Step 4: Set Up a Virtual Host

Don't build your site into /var/www/html directly - give it its own document root and virtual host so you can add more sites later without a rebuild.

sudo mkdir -p /var/www/yourdomain.com/public_html
sudo chown -R $USER:$USER /var/www/yourdomain.com/public_html
sudo chmod -R 755 /var/www/yourdomain.com

Create the virtual host config:

sudo nano /etc/apache2/sites-available/yourdomain.com.conf
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/yourdomain.com/public_html

    <Directory /var/www/yourdomain.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/yourdomain.com-error.log
    CustomLog ${APACHE_LOG_DIR}/yourdomain.com-access.log combined
</VirtualHost>

The AllowOverride All line matters more than it looks - without it, .htaccess rules (permalinks, redirects, most WordPress plugin behavior) get silently ignored, no error, they just don't apply.

Enable the site, disable the default one, and reload:

sudo a2ensite yourdomain.com.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite
sudo apache2ctl configtest
sudo systemctl reload apache2

Always run apache2ctl configtest before reloading. It catches a stray brace or typo in the vhost file before Apache refuses to start over it.

Step 5: Add Free SSL

sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

Certbot edits your Apache vhost automatically to add the 443 block and redirect HTTP to HTTPS. Confirm auto-renewal is scheduled:

sudo certbot renew --dry-run

Common Errors and Fixes

"Could not reliably determine the server's fully qualified domain name" (AH00558)

Harmless warning, but easy to silence. Set the global server name:

echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf
sudo a2enconf servername
sudo systemctl reload apache2

403 Forbidden on a Working Directory

Usually one of two things: the <Directory> block is missing Require all granted (older tutorials still show Order allow,deny, which is Apache 2.2 syntax and does nothing on 2.4+), or the file permissions on public_html are too tight for the www-data user to traverse into. Check both:

sudo apachectl -S
namei -l /var/www/yourdomain.com/public_html/index.php

.htaccess Rules Not Applying

Almost always AllowOverride None left over from the default vhost, or mod_rewrite not enabled. Confirm both:

sudo a2enmod rewrite
apache2ctl -M | grep rewrite

PHP Files Downloading Instead of Running

If you're on PHP-FPM, this means the proxy_fcgi handler isn't picking up .php requests - check that a2enconf php8.3-fpm (with your actual version) was run and that the FPM socket path in that conf file matches what's listed in systemctl status php8.3-fpm.

LAMP vs LEMP: Which One Should You Actually Pick

FactorLAMP (Apache)LEMP (Nginx)
.htaccess supportNative, per-directoryNot supported - all rules live in one config file
Config style familiar fromShared hosting, cPanelCloud-native, containerized deploys
Memory per connectionHigher with mod_php, comparable with FPMLower - event-driven by design
Best fitWordPress/plugin-heavy sites expecting .htaccessHigh-concurrency, static-heavy, or API-style apps

If you're moving a site off shared cPanel hosting and it leans on .htaccess for redirects, security rules, or plugin behavior, LAMP will save you from rewriting all of that as Nginx directives. If you're starting fresh with no legacy .htaccess dependency, LEMP is usually the leaner choice.

Prevention: Keep It From Breaking Later

  • Run apache2ctl configtest before every reload - not after something breaks.
  • Keep PHP and Apache module versions in sync across staging and production so a working .htaccess rule doesn't quietly stop working after a server migration.
  • Set up unattended security updates so Apache and PHP patches land automatically without you having to chase CVEs.
  • Log rotation is on by default via logrotate, but check /var/log/apache2/ disk usage periodically on a busy site - access logs grow fast.

Frequently asked questions

Should I use mod_php or PHP-FPM with Apache?

PHP-FPM if you can spare the extra setup time. It handles concurrent requests more efficiently and isolates PHP from the web server process, which matters once you have real traffic or multiple sites on one VPS. mod_php is fine for a low-traffic single site where simplicity wins.

Why isn't my .htaccess file doing anything?

Almost always AllowOverride None in the virtual host's Directory block, or mod_rewrite not enabled. Set AllowOverride All, run sudo a2enmod rewrite, then reload Apache.

Can I run Apache and Nginx on the same VPS?

Yes - the common pattern is Nginx on port 80/443 as a reverse proxy in front of Apache on an internal port, letting Nginx handle static files and SSL termination while Apache serves the .htaccess-dependent app behind it. It adds a moving part, so only do it if you specifically need both.

How do I add a second site to the same LAMP server?

Create a new document root under /var/www/, add a new file in /etc/apache2/sites-available/ with its own ServerName and DocumentRoot, then run sudo a2ensite and sudo systemctl reload apache2. Each site gets its own vhost file - don't edit the default one for multiple domains.

Do I need to install phpMyAdmin separately on a bare LAMP VPS?

Yes - a manual LAMP install doesn't include it. sudo apt install phpmyadmin will prompt you to select apache2 and configure the database automatically; just make sure to restrict access to it afterward with a password-protected directory or an IP allowlist.

#lamp-stack #apache #ubuntu #mysql #php #vps

Keep reading

Chat with Support