Ubuntu Focal LAMP 8.1
Last updated: September 15th 2022
The Perfect Server - Ubuntu LAMP 8.1
This document details how we've set up our Ubuntu LAMP (Linux Apache Mysql and PHP) 8.1 stack. By provisioning a base Ubuntu Focal image, and following these steps exactly, you would be able to duplicate our server image.
This is a living document. Based on on-going experience and community feedback we tweak our stacks and keep this document continuously updated.
Install fail2ban and enable firewall
apt-get update; apt-get upgrade -y; apt-get install -y fail2ban ufw;
# SSH, HTTP and HTTPS ufw allow 22 ufw allow 80 ufw allow 443 # Skip the following 3 lines if you do not plan on using FTP ufw allow 21 ufw allow 50000:50099/tcp ufw allow out 20/tcp # And lastly we activate UFW ufw --force enable
We choose the port range 50000->50099 in order to allow passive FTP connections.
Add some PPAs to stay current
apt-get install -y software-properties-common apt-add-repository ppa:ondrej/apache2 -y apt-add-repository ppa:ondrej/php -y
Set up MariaDB repositories
apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc' add-apt-repository 'deb [arch=amd64,arm64,ppc64el] https://mirrors.dotsrc.org/mariadb/repo/10.6/ubuntu focal main'
Install base packages
apt-get update; apt-get install -y build-essential curl nano wget lftp unzip bzip2 arj nomarch lzop htop openssl gcc git binutils libmcrypt4 libpcre3-dev make python3 python3-pip supervisor unattended-upgrades whois zsh imagemagick uuid-runtime net-tools zip dirmngr apt-transport-https
Set the timezone to UTC
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
Set SSH to KeepAlive
If you want the SSH Daemon to keep your connections alive, you can run the following commands:
sed -i "s/#TCPKeepAlive yes/TCPKeepAlive yes/" /etc/ssh/sshd_config sed -i "s/#ClientAliveInterval 0/ClientAliveInterval 60/" /etc/ssh/sshd_config sed -i "s/#ClientAliveCountMax 3/ClientAliveCountMax 3/" /etc/ssh/sshd_config
Install PHP8.1 and common PHP packages
apt install -y php8.1-cli php8.1-dev php8.1-pgsql php8.1-sqlite3 php8.1-gd php8.1-curl php8.1-memcached php8.1-imap php8.1-mysql php8.1-mbstring php8.1-xml php8.1-imagick php8.1-zip php8.1-bcmath php8.1-soap php8.1-intl php8.1-readline php8.1-common php8.1-pspell php8.1-tidy php8.1-xsl php8.1-opcache php8.1-apcu
Please Note: We are no longer including php8.1-xmlrpc as that has moved to PECL
Install Composer
curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer
Install and configure Memcached
apt-get install -y memcached sed -i 's/-l 0.0.0.0/-l 127.0.0.1/' /etc/memcached.conf systemctl restart memcached
Update PHP CLI configuration
sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/8.1/cli/php.ini sed -i "s/display_errors = .*/display_errors = On/" /etc/php/8.1/cli/php.ini sed -i "s/memory_limit = .*/memory_limit = 512M/" /etc/php/8.1/cli/php.ini sed -i "s/;date.timezone.*/date.timezone = UTC/" /etc/php/8.1/cli/php.ini
Configure sessions directory permissions
chmod 733 /var/lib/php/sessions chmod +t /var/lib/php/sessions
Install Apache and PHP-FPM
apt-get install -y apache2 apache2-utils php8.1-fpm
Tweak PHP-FPM settings
Please note: We are suppressing PHP error output here by setting these options to production values
sed -i "s/error_reporting = .*/error_reporting = E_ALL \& ~E_NOTICE \& ~E_STRICT \& ~E_DEPRECATED/" /etc/php/8.1/fpm/php.ini sed -i "s/display_errors = .*/display_errors = Off/" /etc/php/8.1/fpm/php.ini sed -i "s/memory_limit = .*/memory_limit = 512M/" /etc/php/8.1/fpm/php.ini sed -i "s/upload_max_filesize = .*/upload_max_filesize = 256M/" /etc/php/8.1/fpm/php.ini sed -i "s/post_max_size = .*/post_max_size = 256M/" /etc/php/8.1/fpm/php.ini sed -i "s/;date.timezone.*/date.timezone = UTC/" /etc/php/8.1/fpm/php.ini
Tune PHP-FPM pool settings
sed -i "s/;listen\.mode =.*/listen.mode = 0666/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/;request_terminate_timeout =.*/request_terminate_timeout = 60/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/pm\.max_children =.*/pm.max_children = 70/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/pm\.start_servers =.*/pm.start_servers = 20/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/pm\.min_spare_servers =.*/pm.min_spare_servers = 20/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/pm\.max_spare_servers =.*/pm.max_spare_servers = 35/" /etc/php/8.1/fpm/pool.d/www.conf sed -i "s/;pm\.max_requests =.*/pm.max_requests = 500/" /etc/php/8.1/fpm/pool.d/www.conf
Tweak Apache settings - let's hide what OS and Webserver this server is running
sed -i "s/ServerTokens OS/ServerTokens Prod/" /etc/apache2/conf-available/security.conf sed -i "s/ServerSignature On/ServerSignature Off/" /etc/apache2/conf-available/security.conf
If you want XDebug - install it and follow the on-screen instructions
This is not installed per default on Webdock stacks - included here for reference.
pecl install xdebug
Install latest NodeJS LTS
curl -fsSL https://deb.nodesource.com/setup_17.x | sudo -E bash - apt-get install -y nodejs
Install MariaDB (MySQL) and set a strong root password
Remember to make a note of your password, you are going to need it in a minute
apt install mariadb-server mariadb-backup -y
Secure your MariaDB installation
mysql_secure_installation
Install phpMyAdmin
Please check this phpMyAdmin issue:
https://github.com/phpmyadmin/phpmyadmin/issues/16753
and if it is not marked as resolved, you need to change the composer create-project command below to:
composer create-project phpmyadmin/phpmyadmin --repository-url=https://www.phpmyadmin.net/packages.json --no-dev
We will install phpMyAdmin using Composer as Ubuntu packages are no longer being maintained.
cd /var/www composer create-project phpmyadmin/phpmyadmin cp /var/www/phpmyadmin/config.sample.inc.php /var/www/phpmyadmin/config.inc.php mysql -u root -pYOUR_ROOT_PASSWORD < /var/www/phpmyadmin/sql/create_tables.sql sed -i "s/\$cfg\['blowfish_secret'\] = '';.*/\$cfg\['blowfish_secret'\] = '$(uuidgen)';/" /var/www/phpmyadmin/config.inc.php mkdir /var/www/phpmyadmin/tmp; chown www-data:www-data /var/www/phpmyadmin/tmp;
Symlink PHPMyAdmin, create logs dir and set permissions and ownership on /var/www
ln -s /var/www/phpmyadmin/ /var/www/html/phpmyadmin; mkdir /var/www/logs; chown www-data:www-data /var/www/html; chown www-data:www-data /var/www/logs; chown www-data:www-data /var/www; chmod -R g+rw /var/www;
Install Mongodb
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list apt update apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev mongodb-org
add extension=mongodb.so to PHP-fpm and PHP-cli configuration:
pecl install mongodb echo "extension=mongodb.so" > /etc/php/8.1/fpm/conf.d/30-mongodb.ini echo "extension=mongodb.so" > /etc/php/8.1/cli/conf.d/30-mongodb.ini
Install Redis
apt install redis-server -y;
Set systemd for supervised and restart Redis
sed -i "s/supervised.*/supervised systemd/" /etc/redis/redis.conf; systemctl restart redis.service;
You may want to further secure your Redis installation
Create Apache virtual host config
Edit the file /etc/apache2/sites-available/webdock.conf and set the following
Now disable the default and symlink in your config
rm /etc/apache2/sites-enabled/000-default.conf ln -s /etc/apache2/sites-available/webdock.conf /etc/apache2/sites-enabled/webdock.conf
Make sure Apache modules are enabled
a2enmod suexec rewrite ssl actions include cgi actions proxy_fcgi alias headers;
Install Letsencrypt Certbot
The apt version of Certbot is now deprecated, so we install it using snap instead.
snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot
Restart PHP-FPM and Apache
systemctl restart php8.1-fpm; systemctl restart apache2;
Setup and configure FTP
We are now building and installing Pure-FTPd directly from source instead of using APT as the official Ubuntu packages are very much out of date, and doing it this way simplifies config somewhat
We start with generating our TLS certificate
openssl dhparam -out /etc/ssl/private/pure-ftpd-dhparams.pem 2048 openssl req -x509 -days 36500 -nodes -newkey rsa:2048 -sha256 -keyout \ /etc/ssl/private/pure-ftpd.pem \ -out /etc/ssl/private/pure-ftpd.pem chmod 600 /etc/ssl/private/*.pem
Download, build and install Pure-FTPd - check what the latest version is at pureftpd.org and update here if appropriate:
wget https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.49.tar.gz -O /tmp/pure-ftpd-1.0.49.tar.gz cd /tmp; tar -xf pure-ftpd-1.0.49.tar.gz; cd pure-ftpd-1.0.49; ./configure --prefix=/usr --with-everything --with-tls --with-certfile=/etc/ssl/private/pure-ftpd.pem; make install; cd /tmp; rm -rf ./pure-*;
Set our config and setup PureDB for authentication. Here we are disallowing anonymous login, setting MinUID to 33 so that users in the www-data group can log in, enabling TLS and non-TLS connections and lastly setting our chosen passive port range:
sed -i "s/BrokenClientsCompatibility .*/BrokenClientsCompatibility yes/" /etc/pure-ftpd.conf sed -i "s/NoAnonymous .*/NoAnonymous yes/" /etc/pure-ftpd.conf sed -i "s/# PureDB /PureDB/" /etc/pure-ftpd.conf sed -i "s/MinUID .*/MinUID 33/" /etc/pure-ftpd.conf sed -i "s/# TLS /TLS /" /etc/pure-ftpd.conf sed -i "s/# PassivePortRange .*/PassivePortRange 50000 50099/" /etc/pure-ftpd.conf touch /etc/pureftpd.passwd; /usr/bin/pure-pw mkdb;
By editing the config file and setting TLS to a value of "2" you can force TLS connections. However, as we are self-signing our certificate here, you may encounter problems connecting with your FTP client and may need to forcibly ignore certificate errors.
Create the systemd service file so Pure-FTPd starts on boot
cat > /etc/systemd/system/pure-ftpd.service << EOF # pure-ftpd binary startup for Webdock servers # To reload systemd daemon after changes to this file: # systemctl --system daemon-reload [Unit] Description=Pure-FTPd FTP server After=network-online.target [Service] Type=forking ExecStart=/usr/sbin/pure-ftpd /etc/pure-ftpd.conf PIDFile=/var/run/pure-ftpd.pid Restart=always RestartSec=1 [Install] WantedBy=multi-user.target EOF
Enable the daemon
systemctl --system daemon-reload; systemctl enable pure-ftpd; systemctl start pure-ftpd;
Complete the configuration
systemctl restart pure-ftpd
Activate Fail2Ban for Pure-FTPd
cat > /etc/fail2ban/jail.d/pure-ftpd.conf << EOF [pure-ftpd] enabled=true maxretry=5 EOF
Restart Fail2Ban
systemctl restart fail2ban
For a further discussion on other services which can be protected with Fail2Ban, please see our Fail2Ban configuration guide.
(Optional) Install BotGuard Server Module
BotGuard provides a service to protect your website from malicious bots, crawlers, scrapers, and hacker attacks. It selectively blocks bad bot traffic in real time, while granting unrestricted access to the website to human users, search engines, and affiliate bots. Read more on their website.
Please note: This is a completely optional step and not required for the functioning of your server. We include it here as Webdock offers 1 free domain protected per Server as part of our VPS Server packages.
Start with installing a missing required package and adding their repository key:
apt install apt-transport-https -y curl -fsSL https://repo.botguard.net/botguard.gpg | apt-key add -
Next, install the module itself. Read more in their integration guide here.
add-apt-repository "deb https://repo.botguard.net/debian $(lsb_release -cs) main" apt update; apt install libapache2-mod-botguard -y systemctl restart apache2
BotGuard is now installed and once you have your domain set up in their dashboard you can edit /etc/apache2/mods-available/botguard.conf in order to set your assigned BotGuard servers.
For more information, please see the BotGuard Integration Guide for Apache
Set up logrotate for Apache logs
Execute the following to give you log rotation for Apache - this gives you 10 days of logs, rotated daily
cat > /etc/logrotate.d/vhost << EOF /var/www/logs/*.log { rotate 10 daily compress delaycompress sharedscripts postrotate /usr/sbin/apache2ctl graceful > /dev/null endscript } EOF
Setup unattended security upgrades
cat > /etc/apt/apt.conf.d/10periodic << EOF APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; EOF
You can further tweak unattended upgrades if you wish in /etc/apt/apt.conf.d/50unattended-upgrades. The default in Focal is to only install security upgrades automatically.
Restart your server
Make sure all services come up properly. You can see what services are listening on which ports on your server by running
netstat -tapn
Congratulations. All services should now come up and you have a production-ready webserver stack running. You can further tune your webserver and PHP-FPM settings based on your use-case (e.g. whether you have a high or low traffic site, mostly serve static or dynamic content etc.). Try Googling "optimize php-fpm" or "optimize apache" for example and pick settings that fit your requirements and chosen Webdock profile. If you find some optimized defaults you would like us to include in our stacks, please let us know and we will take a look.
Related articles
-
Ubuntu Jammy LAMP 8.2
Learn how to set up the Perfect Ubuntu Jammy Web Server - Linux Apache and the latest PHP version
Last updated: August 19th 2024
-
Ubuntu Jammy LEMP 8.2
Learn how to set up the Perfect Ubuntu Web Server on Ubuntu Jammy - Linux NginX and the latest PHP version
Last updated: August 19th 2024
-
Ubuntu LEMP 8.1
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 8.1
Last updated: May 10th 2023
-
Ubuntu Focal LEMP 8.1
Learn how to set up the Perfect Focal Ubuntu Web Server - Linux NginX PHP 8.1
Last updated: September 15th 2022
-
Ubuntu Focal LEMP 7.4
Learn how to set up the Perfect Ubuntu Focal Web Server - Linux NginX PHP 7.4
Last updated: September 15th 2022
-
Ubuntu LEMP 7.3
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 7.3
Last updated: September 9th 2022
-
Ubuntu LEMP 7.2
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 7.2
Last updated: September 15th 2022
-
Ubuntu LEMP 7.1
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 7.1
Last updated: September 9th 2022
-
Ubuntu LEMP 5.6
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 5.6
Last updated: September 9th 2022
-
Ubuntu LAMP 8.1
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 8.1
Last updated: May 10th 2023
-
Ubuntu Focal LAMP 7.4
Learn how to set up the Perfect Ubuntu Focal Web Server - Linux Apache PHP 7.4
Last updated: September 15th 2022
-
Ubuntu LAMP 7.3
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 7.3
Last updated: September 9th 2022
-
Ubuntu LAMP 7.2
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 7.2
Last updated: September 15th 2022
-
Ubuntu LAMP 7.1
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 7.1
Last updated: September 9th 2022
-
Ubuntu LAMP 5.6
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 5.6
Last updated: September 9th 2022
-
Ubuntu LEMP 7.4
Learn how to set up the Perfect Ubuntu Web Server - Linux NginX PHP 7.4
Last updated: September 7th 2023
-
Ubuntu LAMP 7.4
Learn how to set up the Perfect Ubuntu Web Server - Linux Apache PHP 7.4
Last updated: September 7th 2023