Install EC2 Debian 11, PHP8.2, Mariadb, Apache2
This is a stable installation as at May 2025 using x86_64 Debian 11 Linux and hardware architecture on a t3a instance – e.g. t3a.nano or t3a.micro.
If you install on t3 by mistake, you can snapshot and re-attach it to a t3a instance.
I prefer NGINX, but Apache2 is a good starting place. On either platform, WordPress editing sometimes freezes. We do not know why as yet.
I will show an NGINX installation on Debian 12 and AWS Linux2023 separately to this tehnical note.
My example uses Sydney – ap-southeast-2 and subnet ap-southeast-2a. I use GP3 hard disk. Make sure Credit Specification is Standard.
Please subscribe to Debian 11 (x86_64) in the Market Place at $0 cost. (You can try ARM on a t4 instance if you wish.)
I use laurenceshaw.au in the examples. All my Linux commands are via the vi editor. My SSH key is a .pem file on an iMac logging into Linux as root.
Please be reasonably familiar with pre-requisites such as iMac root terminal login, Connecting to the EC2 instance, sudo su once logged in, and use of FileZilla with your .pem key (.ppk on Windows Putty)
Launch an Instance - Configurations
First Linux configurations
On an iMac terminal, previously set up your ability to use root login for the ssh command to work. (Internet search to see how, or view previous articles). These small shell scripts can be helpful when you log into a terminal session and change to root with “sudo su”.
vi ssh.sh #!/bin/sh :>/var/root/.ssh/known_hosts exit [save and exit] chmod 777 ssh.sh [use your own .pem key file name and location, and the ssh command from the EC2 Connect tab.] vi domain.sh #!/bin/sh cd PEM ssh -i "domain.pem" admin@ec2-xx-xx-xx-xx.ap-southeast-2.compute.amazonaws.com exit [save and exit] chmod 777 domain.sh These can assist for quick logins and clearing the ssh keys on your iMac. For example: ./domain.sh
Log into the EC2 instance, and set your environment before working on the instance.
Assumption: you have attached an IP4 address and are able to SSH login. $ sudo su # All commands will be under root. Where needed I will make comments... (Use 1GB swap space. Less will cause issues. Use your own timezone. DOMAIN is you domain name, or possibley something else descriptive) export EXINIT='set noautoindent' export VISUAL=vim echo "vm.swappiness=10" >> /etc/sysctl.conf echo "vm.vfs_cache_pressure=200" >> /etc/sysctl.conf sysctl -w vm.swappiness=10 sysctl -w vm.vfs_cache_pressure=200 dd if=/dev/zero of=/swapfile bs=1024 count=1048576 mkswap /swapfile chmod 0600 /swapfile swapon /swapfile echo "/swapfile swap swap defaults 0 0" >> /etc/fstab a="Australia/Brisbane";export a;echo $a ln -sf /usr/share/zoneinfo/$a /etc/localtime date vi /etc/vim/vimrc.local let skip_defaults_vim = 1 if has('mouse') set mouse=r endif [save and exit] cd ~ vi .bashrc export EXINIT='set noautoindent' export VISUAL=vim export PS1="[\u@DOMAIN: \w]\\$ " alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' [save and exit] cd /home/admin vi .bashrc export EXINIT='set noautoindent' export VISUAL=vim export PS1="[\u@DOMAIN: \w]\\$ " alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' [save and exit] apt update apt upgrade SETUP A BACKDOOR EMERGENCY LOGIN - useful for EC2 serial console login if something has gone wrong. We will add a backup/backdoor user. If you get the sss_cache error shown below, please use the fix shown. Changes are based on building a new site before it goes live. We will use "snoopy" (the dog) as the user name... adduser snoopy (Give snoopy a password then add snoopy to /etc/sudoers - Using the vi editor, go to the end of the file (SHIFT G), and append the entry. Then use :w! to save the entry as it is a read only file.) (Again, all commands are from root user) vi /etc/sudoers snoopy ALL=(ALL) NOPASSWD:ALL [Exit the file after saving with SHIFT ZZ] (Add the user to groups admin and root: (for Linux 2023, it is wheel and root)) usermod -aG admin snoopy; usermod -aG root snoopy (We will make a copy of a good verion of /home/admin/.ssh to /home:) cd /home/admin cp -pr .ssh ../SSH_BACKUP This completes the creation of a backup user that you can use in an emergency on the EC2 Contact console. IF YOU GET THIS ERROR: ------------------------------- [sss_cache] [sysdb_domain_cache_connect] (0x0010): DB version too old [0.22], expected [0.23] for domain implicit_files! Higher version of database is expected! In order to upgrade the database, you must run SSSD. Removing cache files in /var/lib/sss/db should fix the issue, but note that removing cache files will also remove all of your cached credentials. Could not open available domains -------------------------------- To fix this, do the following: cd /var/lib/sss/db rm * sss_cache -E Then add the backup/backdoor user.
We will next add the Linux packages. Keep in mind, after doing all the work, stop and restart the instance and if adding major components, it can help to do the commands: sync;sync;reboot
Install Packages
I’m providing quite a number of packages to cover WordPress and general use of apps. I will show how to use letsencrypt, but in the immediacy will show use of a paid SSL certificate for laurenceshaw.au.
Preliminary work – your CAA records…
In your DNS settings, if using Comodo or Sectigo, add two CAA records. If these fail in the future, just contact the supplier to see what the records should be:
CAA 0 issue sectigo.com
CAA 0 issue digicert.com
If using Letsencrypt (certbot): 0 issue letsencrypt.org
If a paid certificate fails due to having letsencrypt in the DNS records, you could configure an authentication record instead, or temporarily remove the letsencrypt record. It should still be possible hoserver to install letsenscypt SSL without its CAA record.
Again, use root login to the EC2 instance:
PRELIMINARY WORK for a PAID SSL Certificate (and add CAA records to the DNS) Let's say we have a paid SSL certficate that you have edited to include all the chaining (this is a separate topic) Upload the .crt and .key files with FileZilla to /home/admin cd /etc/ssl/certs cp /home/admin/*crt . cd ../private cp /home/admin/*key . This is now out of the way. (Letsencrypt will be covered, but for now we use this.) PRELIMINARY APT installations with KEY WARNING FIXES - this is for Debian 11. Should be ok for Debian 12? apt update Sometimes we do or do not get an error: Get:5 https://packages.sury.org/php bullseye InRelease [7551 B] Err:5 https://packages.sury.org/php bullseye InRelease The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B188E2B695BD4743 Reading package lists... Done W: GPG error: https://packages.sury.org/php bullseye InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B188E2B695BD4743 E: The repository 'https://packages.sury.org/php bullseye InRelease' is not signed. N: Updating from such a repository can't be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. To fix this: apt autoclean apt-key adv --fetch-keys 'https://packages.sury.org/php/apt.gpg' YOu may see this message: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg) We will fix this in a moment. It does not stop updates from working though. apt update apt upgrade If still not working, try these commands first and re-attempt the fix above: apt -y install software-properties-common ca-certificates lsb-release apt-transport-https sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add - apt -y install curl gnupg2 ca-certificates lsb-release debian-archive-keyring If there was not an error, still do the above 4 commands. apt update apt upgrade If you see the message apt autoremove, it is okay to do it. I know this is not good, but it seems not to happen on all installations. Fixing the legacy warning... You will see at the top of the output a warning similar to this: apt-key list Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)). /etc/apt/trusted.gpg -------------------- pub rsa3072 2019-03-18 [SC] [expires: 2026-02-04] 1505 8500 A023 5D97 F5D1 0063 B188 E2B6 95BD 4743 uid [ unknown] DEB.SURY.ORG Automatic Signing Key <deb@sury.org> sub rsa3072 2019-03-18 [E] [expires: 2026-02-04] The fix is simple: (after you execute apt update the warning will not be there. If issues, use Google Advanced Search to assist on the exact error you get.) cd /etc/apt cp trusted.gpg trusted.gpg.d apt update apt upgrade ATP PACKAGE INSTALLATIONS now that the warnings and errors are fixed. A t3a.micro instance installs much faster than a t3a.nano instance. Check you did install with GP3 disk, and you used standard credit specifications - see the EC2 top right menu. These kinds of steps are a learning curve, but should be veery familiar if by the time you start offering the service to others. apt -y install gnupg apt -y install php8.2 Re-run this command to make sure gpung2 is insalled: apt -y install curl gnupg2 ca-certificates lsb-release debian-archive-keyring apt -y install php8.2-cli php8.2-mbstring php8.2-xml php8.2-common php8.2-curl php8.2-imap php8.2-bz2 apt -y install mariadb apt -y install php8.2-mysqli php8.2-fpm gcc libjpeg* zip php8.2-zip apt -y install php8.2-gd a2enmod proxy_fcgi setenvif a2enmod ssl a2enconf php8.2-fpm a2ensite default-ssl a2enmod rewrite systemctl reload apache2 apt -y install libgd-tools ipset For certbot/lets encrypt: (we do not install the certbot-apache plugin, and we only use pip for updating letsencrypt certificated) apt -y install python3-venv apt -y install php8.2-xmlrpc php8.2-soap php8.2-intl python3 -m venv /opt/certbot/ /opt/certbot/bin/pip install --upgrade pip /opt/certbot/bin/pip install certbot ln -s /opt/certbot/bin/certbot /usr/bin/certbot apt -y install certbot Additional Packages: I like to install dnsutils so I can use the dig commands, and apt install whois so I can check domains. I also install imagemagick (apt install imagemagick) so I can crop my own photographs into square thumnail sizes. To add php-imagick in case that helps WordPress plugins, you can install with apt install php-imagick You can hunt around forums on using it in Linux2023, but L2023 will not have a php package to match as far as I know.
Install and Configure Mariadb, various PHP, phpMyAdmin
NOTE: I am not installing memcached for apache2. I do however install it for Nginx. I never install ACPU - it has been too problematic for me. apt install mariadb-server mysql_secure_installation "Enter current password for root" (enter for none): OK, successfully used password, moving on... "Switch to unix_socket authentication [Y/n]" n "Change the root password?" [Y/n] Y (nominate your database password) Y for the remaining questions] systemctl stop mariadb systemctl start mariadb systemctl enable mariadb systemctl enable apache2 systemctl enable php8.2-fpm VARIOUS CONFIGURATIONS cd / find . -name php.ini -print ./etc/php/8.2/fpm/php.ini ./etc/php/8.2/cli/php.ini ./etc/php/8.2/apache2/php.ini cd /etc/php/8.2/fpm Use your own timezone, and modify values to your own preference. If later uploading .sql files through phpMyAdmin, the max file sizees below will apply as a limit. I prefer 512MB for memory_limit. Others may use 128 or 256. I prefer upload_max_filesise and post_max_size as 100MB. cp -p php.ini php.ini.bak vi php.ini date.timezone = Australia/Brisbane max_execution_time = 300 max_input_time = 600 max_input_vars = 2500 memory_limit = 512M post_max_size = 50M upload_max_filesize = 50M [save and exit] cd / find . -name www.conf -print ./etc/php/8.2/fpm/pool.d/www.conf cd /etc/php/8.2/fpm/pool.d cp -p www.conf www.conf.bak Some fo the following values will already be correct: vi www.conf user = www-data group = www-data listen = /run/php/php8.2-fpm.sock listen.owner = www-data listen.group = www-data ;listen.mode = 0660 listen.mode = 0660 ; pm = dynamic pm = ondemand pm.max_children = 75 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 35 pm.process_idle_timeout = 10s; pm.max_requests = 500 Then at the bottom of the file: (use the same memory value you had in php.ini) php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on php_admin_value[disable_functions] = exec,passthru,system php_admin_flag[allow_url_fopen] = off php_admin_value[memory_limit] = 512M [save and exit] We add the emergency lines. You can place these lines anywhere near the commented lines for "emergency". This helps prevent memory leaks, and ability to gracefully use systemctl reload php8.2-fpm on crontab once a night. cd .. cp -p php-fpm.conf php-fpm.conf.bak vi php-fpm.conf emergency_restart_threshold = 10 emergency_restart_interval = 1m process_control_timeout = 60s [save and exit] crontab is already installed on Debian 11. (from memory, I think it is 'apt install cron' on Deb12. I use deb11 at the moment as. know it is stable) Let's add "reload" for php8.2-fpm to crontab: crontab -e 15 0 * * * /usr/bin/systemctl reload php8.2-fpm >/dev/null 2>&1 [save and exit] cd /etc/php/8.2/mods-available cp -p opcache.ini opcache.ini.bak vi opcache.ini zend_extension=opcache.so opcache.jit=off opcache.enable=1 opcache.enable_cli=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=4000 [save and exit] apt update apt upgrade sync;sync;reboot Wait a bit and log back in as root. After all configs are done, please use the EC2 console to stop and start the instance for a "clean slate". cd /var/ chmod 2775 www cd www chmod 2775 html cd html echo " < ?phpZphpinfo(); ? > "|sed 's/ //g'|sed 's/Z/ /g' > info.php Create a simple index.html file (you can remove it after installing WordPress). Use your own domain name. vi index.html BONJOUR DOMAIN [save and exit] cd /var/www/html chown www-data * chgrp www-data * chmod 664 * We are not yet ready to test info.php or the domain name as we have to install SSL into apache2. We will do this shortly. We can however next install phpMyAdmin to manage the database. cd /usr/share wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz ls tar xvf phpMyAdmin-latest-all-languages.tar.gz rm phpMyAdmin-latest-all-languages.tar.gz ls Use the file name, e.g.: mv phpMyAdmin-5.2.2-all-languages phpMyAdmin cd phpMyAdmin mkdir tmp chmod 777 tmp cp -p config.sample.inc.php config.inc.php vi config.inc.php Search for the blowfish line and insert an appropriate value in the single quotes. I use the following blowfish generator: (paste the value into your line) https://phpsolved.com/phpmyadmin-blowfish-secret-generator/?g=[insert_php]echo%20$code;[/insert_php] Paste the generated value into the blowfish value. For exmample: $cfg['blowfish_secret'] = 'nzpC-qoCt}t/yTKOp5w0o,ULnX,xdKny'; Then after the SaveDir line, add TempDir... $cfg['SaveDir'] = ''; $cfg['TempDir'] = '/tmp'; [save and exit] cd /var/www/html ln -s /usr/share/phpMyAdmin phpMyAdmin
Freezing Problems with mariadb:
It is sometimes nigh impossible to find where the system freezes when editing or displaying a page even after we have given “good” values in our configurations.
phpMyAdmin has a statistics page that graphically can show all is ok. And Amazon EC2 can show CPU, disk writes, RAM all good.
I don’t have an answer to this, but this may help:
cd /etc/mysql cp -p my.cnf my.cnf.bak vi my.cnf [mysqld] innodb_buffer_pool_size=512M optimizer_search_depth=0 log_error=/var/log/mariadb-error.log log_warnings=9 [save and exit] At least we now have an error log. You could try omitting the pool size and optimizer lines. These configurations were found by users on public forums relating to a Help Desk app where the system kept freezing, even though no errors, slow logs, or graphical overloads were shown.
We now wish to add a helpful shell scripts to restart services:
cd /home/admin vi restart.sh #!/bin/sh systemctl restart apache2 systemctl restart mariadb systemctl reload php8.2-fpm swapoff -a swapon -a free -m exit [save and exit] chmod 777 restart.sh chown root restart.sh chgrp admin restart.sh This helps when testing. If using crontab, you could use reload instead of restart. We use reload as our preference for php. swapoff/on is also optional but I use it. You can also use systemctl status -l SERVIVCE, e.g. /usr/bin/systemctl status -l apache2 to make sure no errors or where errors are being notified. All log files are under /var/log - e.g. /var/log/apache2. Please check all of these out.
We will now show the optional but helpful use of the Amazon “aws” command to create backups and store in S3 buckets. Then we will address SSL.
phpMyAdmin basics
Using phpMyAdmin is another learning curve.
These configurations make you ready to install WordPress.
Assuming you made a softlink, e.g.:
cd /var/www/html
ln -s /usr/share/phpMyAdmin phpMyAmdin
Then log into phpMyAdmin as root user and password.
https://my_domain.com/phpMyAdmin
Log in as root with the mariadb password you created and add a database and user so we can install WordPress to that database.
Fix the initial error message at the bottom of the screen where it says “find out why”. Just click on the link and follow the fix.
The screen shots below are fairly old, so use utf8mb4_general_ci or utf8_general_ci instead of Latin.
aws software - optional but helpful
Amazon uses the aws command to access S3 buckets. This is useful for storing backup files and databases.
In other notes, I have shown how to create access to S3 buckets from your Linux instance using an IAM role. You can then add that to the EC2 instance from the EC2 console top right menu in your region. (Actions > Security > Modify IAM Role)
To create the Role if not already done, go to IAM > Roles > Add Role
Select Trusted Entity Type: Aws Service, Use Case: S3, then Permissions Policies:
AdministratorAccess
AmazonS3FullAccess
AmazonSESFullAccess
CloudWatchFullAccessV2
The Trust Relationships tab will look like this:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Effect”: “Allow”,
“Principal”: {
“Service”: “ec2.amazonaws.com”
},
“Action”: “sts:AssumeRole”
}
]
}
When completed, AWS IAM will give you a public and private key. I keep these in a spreadsheet, as you must not lose these.
Then add it to the instance from the Actions pop-down menu as shown above.
To add this to the instance:
cd ~ mkdir .aws cd .aws You must have the empty, two blank lines as shown below. Use the Keys you were given when creating the IAM role. vi config [default] aws_access_key_id = AKIA4......... aws_secret_access_key = 3vvWqH......... region = ap-southeast-2 [save and exit] Press the Enter key for each response during the next configuration: aws configure
Here are two shell scripts that show the use of the aws command. You can modify later when you have a WordPress site, assuming under /var/www/html, and a database with a user created in phpMyAdmin. These can be run via crontab. The shell scripts will use a bucket you previously created in your region. As a side-note, I use Oregon for all email buckets for Australia.
aws COMMAND - THIS IS OPTIONAL BUT VALUABLE - perhaps return to it later cd /home/admin vi info.log [save and exit - just add one blank line] chmod 777 info.log; chown root info.log; chgrp admin info.log Use your own S3 bucket (e.g. create one in your region), website directories and names: vi aws.sh #!/bin/sh d=`date | awk '{print $2,$3,$NF}'|tr " " "-"` echo backups $d >> /home/admin/info.log tar_html() { cd /var/www/ tar cvf domain.tar ./html # if enough disk space, you can gzip the tar file to save on S3 Bucket space: # gzip domain-$d.tar # aws s3 mv domain-$d.tar.gz s3://domain/domain-$d.tar.gz # if not using gzip: aws s3 mv domain-$d.tar.gz s3://domain/domain-$d.tar } # call the functions - you could have multiple functions for multiple domains and backups, hence the use of functions is easier tar_html exit [save and exit] vi awsdb.sh #!/bin/sh d=`date | awk '{print $2,$3,$NF}'|tr " " "-"` cd /home/admin echo database backups $d >> /home/admin/info.log # Your domain database - these can be any names you wish to use db_domain() { cd /home/admin mysqlcheck --user=DB_USER --password=DB_PASSWORD DB_NAME >> /home/admin/info.log mysqldump --user=DB_USER --password=DB_PASSWORD DB_NAME >> /home/admin/DB_NAME-$d.sql # You can gzip if you wish. This example will not do it. aws s3 mv DB_NAME-$d.sql s3://domain/.DB_NAME-$d.sql } db_domain exit [save and exit] You would have set DB_USER in phpMyAdmin, along with the DB_NAME and DB_PASSWORD. For example if the user is "snoopy", the database name is "snoo" and you set the password to "H0und#d0g", mysqldump --user=snoopy --password=H0und#d0g snoo >> /home/admin/DB_NAME-$d.sql It may seem labourious but it is highly useful. You can of course configure without the aws command and S3 buckets for now. If you configure all this, you can test it. Make sure your IAM role was added in the EC2 console. Debian configurations on other platforms like Akami/Linode can install aws software as well, but a few trial and errors if you do that for the first time, using AWS documentation. aws s3 ls s3://domain/ Notice how we use the trailing forward slash to list anything. You can also create subdirectories, such as domain/sub or domain/.sub. For example, s3 ls s3://snoopy.me/.backups/ AWS doco may suggest use of a line like this: aws configure < /home/admin/aws.txt where aws.txt has the same lines we put in ~/.aws/config.
Paid SSL on apache2 for single or multiple domains - Part 1
Obtain your SSL certificate. One way to create the CSR is to open a free account with CleanTalk, and go through the process of creating a certificate, then download or copy the .CSR information, and the .KEY file. (Dashboard > Services > SSL Dashboard)
Here is an example screenshot. When you pay for a certificate e.g. from Comodo Store, (Sectigo for CAA records), you should have your admin@domain email working. Otherwise use the options for a DNS authentication record. I prefer to get emails working first. In the example below, use your ABN name or your registered business name (or trust name – trusts need trust deed documentation for a .com.au or .au top level domain registration.) Just use “IT” for the organisation Unit.
Free SSL - Letsencrypt (certbot) - apache2 for single or multiple domains - Part 2
LetsEncrypt can be tricky. To do a fresh installation, you usually have the CAA record (but not critical), as “0 issue letsencrypt.org”.
You must have your 000-default.conf file with no lines referencing a rewrite to https, as https does not yet exist.
You move default-ssl.conf to default-ss.conf.bak so that there is no SSL configuration involved.
You use –dry-run until you get a success message.
You then un-comment the rewrite rules, and edit the ssl conf file to have the domain name for port 443, and add the certificate paths. Restart apache2 and you are good to go by testing your https://domain.com site.
Here are example commands:
cd /etc/apache2 cd site-av* pwd vi 000-default.conf (Uncomment any Rewrite redirections to https for the proposed domain. See Part 1 above for the 000-default.conf file contents) [save and exit] mv default-ssl.conf default-ssl.conf.bak systemctl restart apache2 (Use your own email that you like to have for registering domains with letsencrypt, and use your domain, subdomain, or other domain as shown. The example has me@gmail.com and laurenceshaw.au with /var/www/html as the website directory.) /usr/bin/certbot certonly --non-interactive --agree-tos -m me@gmail.com -d laurenceshaw.au --webroot -w /var/www/html --dry-run - The dry run was successful. Now remove the ---dry-run and execute it. Then edit the .conf files, as shown in Part 1 above. I'll give contents here in case it helps. vi 000-default.conf (remove comments from the domain's rewrite lines.) <VirtualHost *:80> ServerName laurenceshaw.au ServerAlias www.laurenceshaw.au Redirect permanent / https://laurenceshaw.au/ RewriteEngine on RewriteCond %{SERVER_NAME} =laurenceshaw.au RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> [save and exit] If you were working on a multi-domain or subdomain, you'd have a stanza(s) below this that look like this after SSL is installed and you removed the comments rewrites: <VirtualHost *:80> ServerName tech.laurenceshaw.au Redirect permanent / https://tech.laurenceshaw.au/ RewriteEngine on RewriteCond %{SERVER_NAME} =tech.laurenceshaw.au RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] ServerAdmin webmaster@localhost DocumentRoot /var/www/tech ErrorLog ${APACHE_LOG_DIR}/error.log </VirtualHost> Now we fix the default-ssl.conf file: cp -p default-ssl.conf.bak default-ssl.conf vi default-ssl.conf <IfModule mod_ssl.c> <VirtualHost _default_:443> ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCertificateFile /etc/letsencrypt/live/laurenceshaw.au/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/laurenceshaw.au/privkey.pem SSLProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2 SSLProxyProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2 SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 SSLProxyCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA SSLHonorCipherOrder on SSLCompression off SSLInsecureRenegotiation Off SSLSessionTickets Off SSLOpenSSLConfCmd ECDHParameters secp384r1 SSLOpenSSLConfCmd Curves secp384r1 <FilesMatch "\.(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory /usr/lib/cgi-bin> SSLOptions +StdEnvVars </Directory> </VirtualHost> </IfModule> [save and exit] systemctl restart apache2 (If errors, see systemctl status -l apache2) Note that there are two long lines, SSLCipherSuite and SSLProxyCipherSuite that must be one line each, not accidentally split into multiple lines by your editor. Now we can add an example of a multi-domain. Append after the above </VirtualHost> stanza, and before </If Module> the following: (with your own domains that configiured SSL correctly) vi default-ssl.conf <VirtualHost *:443> ServerName tech.laurenceshaw.au:443 DocumentRoot /var/www/tech SSLEngine on SSLCertificateFile /etc/letsencrypt/live/tech.laurenceshaw.au/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/tech.laurenceshaw.au/privkey.pem SSLProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2 SSLProxyProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2 SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 SSLProxyCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA SSLHonorCipherOrder on SSLCompression off SSLInsecureRenegotiation Off SSLSessionTickets Off SSLOpenSSLConfCmd ECDHParameters secp384r1 SSLOpenSSLConfCmd Curves secp384r1 </VirtualHost> [save and exit] Restart apache2. I don't like adding configuration files outside these default files. I've found in the past added files do not always work.
Free SSL - Letsencrypt (certbot) Auto-renewal script - Part 3
We now need a shell script to auto-renew Lets Encrypt
Replace with your own values as mentioned in Part 2 above.
cd /home/admin vi certbot.sh #!/bin/bash d=`date` c1=`head -1 /home/admin/certbot.dat` c1=$(expr $c1 + 1) if [ "$c1" = "65" ] ; then echo "0" > /home/admin/certbot.dat echo "Certbot Renewal" $d >> /home/admin/info.log /usr/bin/certbot -v certonly --non-interactive --agree-tos -m me@gmail.com -d laurenceshaw.au --webroot -w /var/www/html >/dev/null 2>&1 sudo /usr/bin/systemctl reload apache2 >/dev/null 2>&1 sudo /usr/bin/openssl x509 -noout -dates -in /etc/letsencrypt/live/laurenceshaw.au/cert.pem >> /home/admin/info.log else echo "Certbot day $c1 of 65" >> /home/admin/info.log echo $c1 > /home/admin/certbot.dat fi sleep 10 d=`date` c1=`head -1 /home/admin/certbot_tech.dat` c1=$(expr $c1 + 1) if [ "$c1" = "65" ] ; then echo "0" > /home/admin/certbot_tech.dat echo "Certbot Renewal" $d >> /home/admin/info.log sudo /usr/bin/certbot -v certonly --non-interactive --agree-tos -m me@gmail.com -d tech.laurenceshaw.au --webroot -w /var/www/tech >/dev/null 2>&1 sudo /usr/bin/systemctl reload apache2 >/dev/null 2>&1 sudo /usr/bin/openssl x509 -noout -dates -in /etc/letsencrypt/live/tech.laurenceshaw.au/cert.pem >> /home/admin/info.log else echo "Certbot day $c1 of 65" >> /home/admin/info.log echo $c1 > /home/admin/certbot_tech.dat fi exit [save and exit] You could of course have these stanzas as shell script functions. e.g. domain() { insert code lines here.... } dubdomain() { insert code lines here... } domain subdomain exit This way you can manage lots of domains simply by commenting our those you don't want at any particular time. Insert a blank line into info.log Add a single line to certbot.dat and in this example also to certbot_tech.dat with the numeral 0 at the top as the only line. chmod 777 info.log certbot.* chown root certbot* info.log chgrp admin certbot* info.log crontab -e 15 1 * * * /home/admin/certbot.sh [save and exit] *** If your certbot.dat files are somehow corrupted with the wrong numerals, you can use the line (for your domain): *** /usr/bin/openssl x509 -noout -dates -in /etc/letsencrypt/live/laurenceshaw.au/cert.pem and work out how many days the certificate has been running, and put into that single top line of the .dat file. Otherwise, if the renewal fails, you have to go through the whole process again of editing the 000-default.conf and default-ssl.conf files. We use 65 days (approx) for renewals. Less than this usually fails. The shell script is not checking for failure or fixing the .dat files.) We do not install the certbot apache plugin. We only use the above commands. You could install postfix and sendmail scripting if you wish, to notify if the SSL certificate has expired. A fair bit of work to do that. You can also monitor your website with Uptime Robot, but that does not check for SSL working.
Adding WordPress
You do need to learn how to use https://your_domain.com/phpMyAdmin.
See the section above on “phpMyAdmin basics”.
We can add a database now usually as utf8mb4_general_ci or utf8_general_ci.
Then we add a user for administrating it – username, localhost, password, and grant all permissions to that database.
If you do not use phpMyAdmin you need to see other articles or documents from Amazon’s installation of WordPress.
The default phpMyAdmin installation will show at the bottom of the screen a missing database that you simply click on to install.
Let’s assume you have this done.
Recall you would have used “ln -s /usr/share/phpMyAdmin phpMyAdmin” to link phpMyAdmin into your /var/www/html directory (or where you choose to have it)
Upload WordPress to your site, unzip and place the contents into /var/www/html or where you need for the domain.
e.g.
cd /var/www/html unzip wordpress-6.8.1-en_AU.zip cd wordpress mv * .. cd .. ./chdir.sh. ---> this is a script shown below.
We need a shell script to change permissions:
cd /var/www/html vi chdir.sh #!/bin/sh chown -R www-data * chgrp -R www-data * find . -type d -exec chmod 2775 {} \; find . -type f -exec chmod 0664 {} \; if [ -f "./.htaccess" ] ; then chown www-data .htaccess chgrp www-data .htaccess chmod 664 .htaccess fi chmod 777 *.sh chown root chdir.sh chgrp root chdir.sh chmod 770 chdir.sh exit [save and exit] chmod 777 chdir.sh After placing WordPress files, in this example into /var/www/html: ./chdir.sh I have /var/www/html as chmod 2775, chdir www-data and chgrp www-data, and /var/www as chmod 2775
Make sure your installation directory no longer has any test index.html file. We want PHP to run by default.
Then you can run the WP install script with https://my_domain.com
If the installation tries to use FTP, your permissions are incorrect. Check /var/www/html is www-data group and owner, and 2775 permissions. www can be root, but check it is 2775.
I prefer using the same admin user and password as the database itself.
Then test your WordPress installation can login and works.