🐧

Server

58 notes  •  Linux & Server Admin

Install LAMP Stack on Amazon EC2

This guide walks through installing a full LAMP (Linux, Apache, MySQL, PHP) stack on an Amazon EC2 Ubuntu instance, including adding the Ondrej PPA for up-to-date PHP packages.

Prerequisites

  • An Amazon EC2 instance running Ubuntu 16.04 or later
  • SSH access with sudo privileges
  • Ports 80 and 443 open in the EC2 security group

Steps

1. Update the package index

sudo apt-get update

2. Add the Ondrej PHP PPA for latest PHP packages

sudo add-apt-repository ppa:ondrej/apache2
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update

3. Install Apache, MySQL, PHP and common extensions

sudo apt-get -y install apache2 mysql-server
sudo apt-get -y install zip curl php libapache2-mod-php   php-curl php-gd php-mysql php-mbstring php-zip php-xml   php-mcrypt php-cli php-intl

4. Enable the PHP module and restart Apache

sudo a2enmod php7.0
sudo service apache2 restart

5. Increase upload limits in php.ini

sudo nano /etc/php/7.0/apache2/php.ini

Set:

upload_max_filesize = 32M
post_max_size = 32M

6. Secure MySQL installation

sudo mysql_secure_installation

Verify

apache2 -v
php -v
mysql --version

Browse to the server IP to see the Apache default page.

Notes

  • To list available PHP modules: sudo apt-cache search php7.0- | less
  • To switch between PHP versions, use a2dismod php5 and a2enmod php5.6 then restart Apache.
  • After installing phpMyAdmin, choose Apache2 as the web server and opt in to configure the database with dbconfig-common.

Install Sendmail on CentOS/RHEL

Sendmail is a mail transfer agent (MTA) that uses SMTP to relay messages between hosts. Although newer RHEL releases default to Postfix, many administrators prefer Sendmail for compatibility reasons. This guide installs and configures Sendmail on CentOS/RHEL 7, 6, or 5.

Prerequisites

  • CentOS or RHEL 5, 6, or 7 with root or sudo access
  • Internet connectivity to reach package mirrors

Steps

1. Install Sendmail and related packages

sudo yum install sendmail sendmail-cf m4

2. Configure Sendmail

sudo nano /etc/mail/sendmail.mc

To allow connections from all interfaces, locate the DAEMON_OPTIONS line and change it to:

DAEMON_OPTIONS(`Port=smtp, Addr=0.0.0.0, Name=MTA')dnl

3. Rebuild the sendmail.cf configuration

sudo m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

4. Start Sendmail and enable it on boot

# CentOS/RHEL 7
sudo systemctl start sendmail
sudo systemctl enable sendmail

# CentOS/RHEL 6/5
sudo service sendmail start
sudo chkconfig sendmail on

Verify

# Check service status
sudo systemctl status sendmail

# Send a test email
echo "Test message" | sendmail -v your@email.com

Troubleshooting

  • Check logs at /var/log/maillog for delivery errors.
  • Ensure port 25 is open in your firewall: sudo firewall-cmd --add-service=smtp --permanent && sudo firewall-cmd --reload
  • If relaying is blocked, verify the RELAY settings in /etc/mail/access and rebuild with sudo makemap hash /etc/mail/access < /etc/mail/access

Copy Files Between Servers with scp

The scp command uses SSH to securely copy files and directories between two hosts. It supports key-based authentication, custom ports, and PEM keys for cloud instances.

Prerequisites

  • SSH access to the remote server
  • The openssh-client package installed locally

Steps

1. Copy a file from a remote server to the current directory

scp root@hostname:/path/to/file .

2. Specify a non-standard SSH port with -P

scp -P 2222 username@myserver.com:/root/file.txt .

3. Copy a local file to a remote server using a PEM key

scp -i /path/to/key.pem /path/to/local/file.jpg user@remote-host:/destination/path/

4. Copy a large file with a PEM key and custom port

scp -i ~/.ssh/mykey.pem -P 18765   /local/path/backup.wpress   user@example.com:/remote/path/

5. Copy an entire directory recursively

scp -r /local/directory user@remote:/destination/

Verify

After the transfer completes, SSH into the remote server and confirm the file exists:

ssh user@remote ls -lh /destination/path/

Notes

  • The -P flag (capital P) sets the port for scp; this differs from ssh -p (lowercase).
  • For very large transfers, consider rsync with the --progress flag, which supports resume on interruption.
  • Use -C to enable compression for slow links.

Configure PureFTPd

PureFTPd is a free, secure FTP server. This guide covers key configuration steps including passive mode setup and fixing the "unroutable address" error that occurs behind NAT (common on cPanel servers).

Prerequisites

  • PureFTPd installed on a Linux server
  • Root or sudo access
  • Knowledge of the server's public IP address

Steps

1. Check current network interfaces and IP addresses

ifconfig

On cPanel servers, view the NAT mapping:

cat /var/cpanel/cpnat

Or retrieve the public IP:

curl https://cpanel.com/showip.shtml

2. Edit the PureFTPd configuration file

sudo nano /etc/pure-ftpd.conf

3. Enable passive port range

Uncomment and set the PassivePortRange directive:

PassivePortRange              30000 50000

4. Set the forced passive IP (for NAT/cPanel environments)

Uncomment and set ForcePassiveIP to the server's public IP:

ForcePassiveIP               203.0.113.10

This resolves the error: "Server sent passive reply with unroutable address. Using server address instead."

5. Restart PureFTPd

sudo service pure-ftpd restart

Verify

# Check which lines have Passive settings
grep Passive /etc/pure-ftpd.conf

# Confirm the service is running
sudo service pure-ftpd status

Troubleshooting

  • If passive connections still fail, ensure the PassivePortRange ports (30000–50000) are open in your firewall.
  • On cPanel, open WHM > Service Configuration > FTP Server Configuration to apply changes through the control panel UI.

Install SSL on Tomcat Server

This guide covers generating a Java keystore and creating a self-signed (or CA-signed) SSL certificate for an Apache Tomcat server using the keytool utility bundled with the JRE.

Prerequisites

  • Apache Tomcat installed and running
  • Java JRE/JDK installed
  • Root or sudo access

Steps

1. Locate the JRE installation

find / -name jre 2>/dev/null

Example output: /usr/java/jdk1.7.0_17/jre

2. Generate a keystore and key pair

/usr/java/jdk1.7.0_17/jre/bin/keytool -genkey   -alias tomcat   -keyalg RSA   -keystore /opt/tomcat/keystore/tomcat.keystore   -keysize 2048

When prompted, enter the server hostname as the "first and last name" (Common Name).

3. Generate a Certificate Signing Request (CSR)

keytool -certreq -alias tomcat   -keystore /opt/tomcat/keystore/tomcat.keystore   -file tomcat.csr

Submit tomcat.csr to your Certificate Authority to obtain a signed certificate.

4. Import the CA certificate chain

keytool -import -alias root   -keystore /opt/tomcat/keystore/tomcat.keystore   -trustcacerts   -file ca-bundle.crt

5. Import the signed certificate

keytool -import -alias tomcat   -keystore /opt/tomcat/keystore/tomcat.keystore   -file your_domain.crt

6. Configure Tomcat to use the keystore

Edit /opt/tomcat/conf/server.xml and add or update the SSL connector:

<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"
  maxThreads="150" scheme="https" secure="true"
  keystoreFile="/opt/tomcat/keystore/tomcat.keystore"
  keystorePass="your_keystore_password"
  clientAuth="false" sslProtocol="TLS" />

7. Restart Tomcat

sudo systemctl restart tomcat

Verify

Browse to https://your-domain.com. Check the certificate details in your browser to confirm the CN and expiry date.

Troubleshooting

  • Ensure port 443 is open in your firewall.
  • If you see a "keystore tampered with, or password was incorrect" error, verify the keystorePass matches what was set during keytool generation.
  • Check Tomcat logs at $CATALINA_HOME/logs/catalina.out for SSL initialization errors.

Install SSL Certificate on Tomcat

After your SSL certificate is issued by a Certificate Authority (CA), import it into Tomcat's Java keystore. This guide covers both PKCS#7 and X.509 (CRT) certificate formats.

Prerequisites

  • A keystore file already containing the private key (generated during CSR creation)
  • Certificate files from your CA (.p7b/.cer for PKCS#7, or .crt + CA bundle for X.509)
  • Java keytool available on the server

Steps

Option A — Import a PKCS#7 certificate (.p7b or .cer)

PKCS#7 files already include the intermediate and root certificates:

keytool -import -trustcacerts   -alias tomcat   -keystore /path/to/tomcat.keystore   -file your_domain.p7b

Option B — Import an X.509 certificate (.crt) with a separate CA bundle

Step 1: Import the CA bundle first:

keytool -import -trustcacerts   -alias intermediate   -keystore /path/to/tomcat.keystore   -file ca-bundle.crt

Step 2: Import the domain certificate:

keytool -import -trustcacerts   -alias tomcat   -keystore /path/to/tomcat.keystore   -file your_domain.crt

Configure the SSL Connector in server.xml

<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"
  scheme="https" secure="true"
  keystoreFile="/path/to/tomcat.keystore"
  keystorePass="your_password"
  clientAuth="false" sslProtocol="TLS" />

Restart Tomcat

sudo systemctl restart tomcat

Verify

# List keystore contents to confirm the certificate was imported
keytool -list -v -keystore /path/to/tomcat.keystore

Browse to https://your-domain.com and verify the padlock shows valid certificate details.

Troubleshooting

  • If you see "Certificate reply does not contain public key for <alias>", ensure the alias used during import matches the alias of the private key in the keystore.
  • Verify the certificate chain order: root CA must be trusted before importing the domain certificate.

Configure SSL in Apache Tomcat

SSL/TLS secures communication between clients and your Tomcat server by encrypting data in transit and authenticating the server identity. This guide walks through enabling HTTPS on Apache Tomcat.

Prerequisites

  • Apache Tomcat 7 or later installed
  • A Java keystore containing your SSL certificate and private key
  • Access to $CATALINA_HOME/conf/server.xml

Steps

1. Locate your keystore file

If you do not have a keystore, generate one:

keytool -genkey -alias tomcat -keyalg RSA   -keystore /etc/tomcat/keystore.jks -keysize 2048

2. Edit server.xml to add an HTTPS connector

sudo nano /etc/tomcat/conf/server.xml

Add or uncomment the following connector block:

<Connector port="443"
  protocol="org.apache.coyote.http11.Http11NioProtocol"
  maxThreads="150"
  SSLEnabled="true"
  scheme="https"
  secure="true"
  keystoreFile="/etc/tomcat/keystore.jks"
  keystorePass="your_keystore_password"
  clientAuth="false"
  sslProtocol="TLS"
  sslEnabledProtocols="TLSv1.2,TLSv1.3"
  ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" />

3. (Optional) Redirect HTTP to HTTPS

In the existing port 8080 connector, add:

redirectPort="443"

4. Restart Tomcat

sudo systemctl restart tomcat

Verify

# Check Tomcat is listening on port 443
sudo ss -tlnp | grep 443

Open https://your-server:443 in a browser and confirm the certificate is valid.

Troubleshooting

  • Review $CATALINA_HOME/logs/catalina.out for SSL startup errors.
  • If the connector fails to start, verify the keystore path and password are correct.
  • Ensure port 443 is allowed through the host firewall and any cloud security group rules.

Enable HSTS (HTTP Strict Transport Security)

HSTS (HTTP Strict Transport Security) instructs browsers to only connect to your site over HTTPS, even if a user types http://. This prevents protocol-downgrade attacks and cookie hijacking.

Prerequisites

  • A valid SSL certificate installed and HTTPS working
  • Apache or Nginx web server with mod_headers (Apache) enabled

Steps

1. Enable mod_headers in Apache

sudo a2enmod headers
sudo systemctl restart apache2

2. Add the HSTS header to your virtual host or .htaccess

In your HTTPS VirtualHost block (/etc/apache2/sites-available/your-site.conf):

<VirtualHost *:443>
    ServerName example.com
    # ... other directives ...

    # Enable HSTS for 1 year, include subdomains
    Header always set Strict-Transport-Security         "max-age=31536000; includeSubDomains; preload"
</VirtualHost>

3. Redirect HTTP to HTTPS

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

4. Reload Apache

sudo systemctl reload apache2

Verify

# Check the header is being sent
curl -I https://example.com | grep Strict-Transport-Security

Expected output:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Notes

  • max-age sets how long (in seconds) browsers enforce HTTPS. 31536000 = 1 year.
  • includeSubDomains extends enforcement to all subdomains.
  • preload allows submission to browser preload lists — only add this if you are confident all subdomains serve valid HTTPS.
  • Do not enable HSTS until your SSL certificate is correctly configured. An HSTS site with a broken certificate is inaccessible to users for the entire max-age duration.

Fix phpMyAdmin 403 Forbidden on CentOS 7

After installing phpMyAdmin on CentOS 7, Apache may return a 403 Forbidden error. This is caused by restrictive directory permissions or the default phpMyAdmin Apache configuration denying all access.

Prerequisites

  • phpMyAdmin installed (typically at /usr/share/phpMyAdmin)
  • Apache running with root or sudo access

Steps

1. Fix filesystem permissions on the phpMyAdmin directory

sudo chmod 755 /usr/share/phpMyAdmin

2. Edit the phpMyAdmin Apache configuration

sudo nano /etc/httpd/conf.d/phpMyAdmin.conf

3. Allow access from all IPs (or restrict to your IP)

Find the Require ip 127.0.0.1 or Deny from All lines and replace with:

# To allow all IPs (use only on trusted networks or with additional auth):
Require all granted

# Or, to restrict to a specific IP:
Require ip 203.0.113.10

A typical updated config block looks like:

<Directory /usr/share/phpMyAdmin/>
   AddDefaultCharset UTF-8
   <IfModule mod_authz_core.c>
     Require all granted
   </IfModule>
</Directory>

4. Restart Apache

sudo systemctl restart httpd

Verify

Open http://your-server-ip/phpMyAdmin in a browser. You should see the phpMyAdmin login page.

Notes

  • On a public-facing server, restrict phpMyAdmin access to known IP addresses rather than allowing all.
  • Consider adding HTTP basic authentication as an additional layer in front of phpMyAdmin.
  • If SELinux is enabled, you may also need: sudo setsebool -P httpd_can_network_connect 1

Configure sudo Access on RHEL

The sudo command lets trusted users run administrative commands without logging in as root. This guide creates a non-root user with sudo privileges on Red Hat Enterprise Linux.

Prerequisites

  • RHEL 6 or 7 system
  • Root access to add users and edit sudoers

Steps

1. Create a new user

sudo useradd username
sudo passwd username

2. Add the user to the wheel group (RHEL sudo group)

sudo usermod -aG wheel username

3. Verify wheel group access is enabled in sudoers

sudo visudo

Ensure the following line is uncommented:

%wheel  ALL=(ALL)  ALL

For passwordless sudo (optional), use:

%wheel  ALL=(ALL)  NOPASSWD: ALL

4. (Alternative) Grant sudo to a specific user directly

sudo visudo

Add the line:

username  ALL=(ALL)  ALL

Verify

# Switch to the new user and test sudo
su - username
sudo whoami

Expected output: root

Troubleshooting

  • Never edit /etc/sudoers directly with a text editor — always use visudo, which validates syntax before saving.
  • If a user gets "not in the sudoers file", confirm group membership: groups username
  • After editing sudoers, changes take effect immediately — no restart required.

Install Apache Web Server on RHEL

Red Hat Enterprise Linux does not install the Apache web server by default. This guide covers checking for an existing installation and installing Apache (httpd) using yum.

Prerequisites

  • RHEL 6 or 7 with root or sudo access
  • Active subscription or configured repository mirror

Steps

1. Check if Apache is already installed

rpm -q httpd

If installed, output will be similar to httpd-2.4.6-97.el7.x86_64. If not, proceed to install.

2. Install Apache

sudo yum install httpd

3. Start the Apache service

sudo systemctl start httpd

4. Enable Apache to start on boot

sudo systemctl enable httpd

5. Allow HTTP traffic through the firewall

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Verify

sudo systemctl status httpd

Open a browser and navigate to http://your-server-ip. You should see the Apache test page.

Notes

  • The document root is /var/www/html/ by default.
  • Configuration files are in /etc/httpd/conf/ and /etc/httpd/conf.d/.
  • Apache logs are at /var/log/httpd/access_log and /var/log/httpd/error_log.

Troubleshoot High Server Load on Linux

High server load is typically caused by excessive CPU usage, memory exhaustion, or disk I/O bottlenecks. This guide provides commands for diagnosing current and historical resource usage to identify the root cause.

Prerequisites

  • SSH access to the server with sudo privileges
  • Basic familiarity with Linux process management

Steps

1. Check current load average

uptime
# or
cat /proc/loadavg

2. Identify CPU-intensive processes

top
# Press 'P' to sort by CPU usage
# or use:
ps aux --sort=-%cpu | head -20

3. Check memory and swap usage

free -m
vmstat 1 5

4. Check disk I/O

iostat -x 1 5
# or
iotop

5. Review historical resource usage with sar

# Install sysstat if needed
sudo yum install sysstat   # RHEL/CentOS
sudo apt-get install sysstat  # Ubuntu/Debian

# View CPU history
sar -u
# View memory history
sar -r
# View disk I/O history
sar -d

6. Identify processes using the most resources

# All processes sorted by memory
ps aux --sort=-%mem | head -20

# Check open file handles
lsof | wc -l

# Count Apache connections
netstat -an | grep :80 | wc -l

7. Kill a runaway process

kill -9 PID

Notes

  • A load average above the number of CPU cores sustained over several minutes indicates overload.
  • Heavy swap usage indicates insufficient RAM — the server is using disk as memory, which is very slow.
  • MySQL and PHP-FPM are common culprits. Check their logs at /var/log/mysql/ and /var/log/php-fpm/.
  • For cPanel servers, check /usr/local/cpanel/logs/ for Apache and service logs.

Install SSL Certificate on Apache with mod_ssl

This guide covers installing a CA-issued SSL certificate on Apache using mod_ssl. You will place the certificate files in the correct directories and update the virtual host configuration.

Prerequisites

  • Apache with mod_ssl installed and enabled
  • Certificate files from your CA: domain certificate (.crt) and CA bundle (.ca-bundle)
  • The private key (.key) generated during CSR creation

Steps

1. Place certificate files in the correct directories

# Private key — accessible only by Apache
sudo cp your_domain.key /etc/ssl/private/your_domain.key
sudo chmod 600 /etc/ssl/private/your_domain.key

# Domain certificate and CA bundle
sudo cp your_domain.crt /etc/ssl/certs/your_domain.crt
sudo cp your_domain.ca-bundle /etc/ssl/certs/your_domain.ca-bundle

2. Enable mod_ssl (if not already enabled)

sudo a2enmod ssl
sudo systemctl restart apache2

3. Configure the SSL virtual host

sudo nano /etc/apache2/sites-available/your-site-ssl.conf
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html

    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/your_domain.crt
    SSLCertificateKeyFile /etc/ssl/private/your_domain.key
    SSLCertificateChainFile /etc/ssl/certs/your_domain.ca-bundle

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

4. Enable the site and reload Apache

sudo a2ensite your-site-ssl.conf
sudo systemctl reload apache2

Verify

# Check configuration syntax
sudo apache2ctl configtest

# Confirm port 443 is listening
sudo ss -tlnp | grep 443

Browse to https://example.com and verify the padlock icon and certificate details.

Troubleshooting

  • Check Apache error log: sudo tail -50 /var/log/apache2/ssl-error.log
  • Verify key matches certificate: openssl x509 -noout -modulus -in cert.crt | md5sum and openssl rsa -noout -modulus -in domain.key | md5sum — the MD5 hashes must match.
  • On RHEL/CentOS, the config file is /etc/httpd/conf.d/ssl.conf and the service is httpd.

Configure Strong SSL/TLS Encryption in Apache

A basic SSL configuration will work, but without additional hardening Apache may accept weak cipher suites or outdated protocols. This guide configures Apache for strong TLS encryption.

Prerequisites

  • Apache 2.4 with mod_ssl enabled
  • A valid SSL certificate already installed

Steps

1. Minimal SSL virtual host configuration

LoadModule ssl_module modules/mod_ssl.so

Listen 443

<VirtualHost *:443>
    ServerName www.example.com
    SSLEngine on
    SSLCertificateFile    "/path/to/www.example.com.cert"
    SSLCertificateKeyFile "/path/to/www.example.com.key"
</VirtualHost>

2. Restrict to strong cipher suites only

SSLCipherSuite HIGH:!aNULL:!MD5
SSLHonorCipherOrder on

3. Enforce modern TLS protocols (disable SSLv3, TLS 1.0, TLS 1.1)

SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1

4. Recommended strong cipher suite string

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
SSLHonorCipherOrder on

5. Require strong cipher for a specific URL

<Location /secure>
    SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128
</Location>

6. Reload Apache

sudo systemctl reload apache2

Verify

openssl s_client -connect example.com:443 -tls1_2

Test your configuration at SSL Labs to get a security grade.

Notes

  • Aim for an A or A+ rating on SSL Labs.
  • Add HSTS headers alongside this configuration to prevent protocol downgrade attacks.
  • For Apache 2.4.36+, consider using SSLPolicy directive instead of manual cipher strings.

Convert PPK to PEM (and Vice Versa)

PuTTY uses its own .ppk key format, while Linux SSH and AWS EC2 require the standard .pem format. This guide converts between the two using PuTTY tools.

Prerequisites

  • A .ppk file (PuTTY private key) or .pem file to convert
  • putty-tools package installed on Linux

Steps

1. Install PuTTY tools

sudo apt-get install putty-tools    # Ubuntu/Debian
sudo yum install putty               # RHEL/CentOS

2. Convert PPK to PEM

puttygen your-key.ppk -O private-openssh -o your-key.pem

3. Set correct permissions on the PEM file

chmod 400 your-key.pem

4. Use the PEM file to SSH into a server

ssh -i your-key.pem ec2-user@ec2-xx-xx-xx-xx.compute-1.amazonaws.com

5. Convert PEM to PPK (reverse direction)

puttygen your-key.pem -o your-key.ppk

Verify

# Verify the PEM key is valid
ssh-keygen -y -f your-key.pem

This should output the corresponding public key without errors.

Notes

  • On Windows, use PuTTYgen GUI: File > Load Private Key > Conversions > Export OpenSSH key.
  • PEM files must have permissions 400 or 600; SSH will refuse keys that are world-readable.
  • For AWS EC2, the default username depends on the AMI: ec2-user (Amazon Linux), ubuntu (Ubuntu), centos (CentOS).

Redis Quick Start Guide

Redis is an in-memory data structure store used as a cache, message broker, and database. This guide covers compiling Redis from source (the recommended approach) and basic usage.

Prerequisites

  • GCC compiler and make installed
  • Root or sudo access

Steps

1. Download and compile Redis from source

wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make

2. (Optional) Run the test suite

make test

3. Install binaries system-wide

sudo make install

4. Start the Redis server

redis-server

Or, to run with a config file:

redis-server /etc/redis/redis.conf

5. Connect with the Redis CLI

redis-cli

6. Basic Redis commands

# Set a key
SET mykey "Hello"

# Get a key
GET mykey

# Check if the server is alive
PING
# Expected: PONG

# List all keys
KEYS *

7. Enable Redis as a system service

sudo cp utils/redis_init_script /etc/init.d/redis
sudo update-rc.d redis defaults    # Debian/Ubuntu
# or
sudo systemctl enable redis        # systemd systems

Verify

redis-cli ping

Expected output: PONG

Notes

  • For production, bind Redis to 127.0.0.1 in redis.conf to prevent external access.
  • Set a strong password in redis.conf using the requirepass directive.
  • Package manager versions of Redis (apt/yum) are usually outdated; compiling from source ensures the latest stable release.

Mount an S3 Bucket on Linux EC2 with s3fs

s3fs allows you to mount an Amazon S3 bucket as a local filesystem directory on a Linux EC2 instance. This guide covers installing s3fs and mounting a bucket.

Prerequisites

  • An AWS S3 bucket already created
  • AWS IAM credentials with S3 read/write access
  • EC2 instance running CentOS/RHEL or Ubuntu

Steps

1. Install dependencies

# CentOS/RHEL
sudo yum install gcc libstdc++-devel gcc-c++ fuse fuse-devel curl-devel libxml2-devel mailcap automake openssl-devel

# Ubuntu/Debian
sudo apt-get install build-essential libfuse-dev fuse libcurl4-openssl-dev libxml2-dev mime-support automake libtool

2. Install s3fs from the package manager (preferred)

# Ubuntu
sudo apt-get install s3fs

# CentOS (via EPEL)
sudo yum install epel-release
sudo yum install s3fs-fuse

3. Configure AWS credentials

echo "ACCESS_KEY_ID:SECRET_ACCESS_KEY" > ~/.passwd-s3fs
chmod 600 ~/.passwd-s3fs

4. Create a mount point and mount the bucket

sudo mkdir /mnt/s3bucket

s3fs your-bucket-name /mnt/s3bucket   -o passwd_file=~/.passwd-s3fs   -o allow_other   -o use_cache=/tmp

5. Mount automatically on boot

Add to /etc/fstab:

s3fs#your-bucket-name /mnt/s3bucket fuse _netdev,passwd_file=/root/.passwd-s3fs,allow_other,use_cache=/tmp 0 0

Verify

df -h | grep s3fs
ls /mnt/s3bucket

Troubleshooting

  • If mounting fails, add -o dbglevel=info -f to the s3fs command to see debug output.
  • For EC2 instances with an IAM role attached, you can use -o iam_role=auto instead of a credentials file.
  • Ensure the EC2 security group allows outbound HTTPS (port 443) to reach S3 endpoints.

Install IonCube Loaders on Amazon Linux

IonCube Loader is a PHP extension required to run applications encoded with IonCube. This guide covers installing IonCube on Amazon Linux and Ubuntu EC2 instances.

Prerequisites

  • PHP installed (know your PHP version and extension directory)
  • Root or sudo access

Steps

1. Download and extract the IonCube loaders

cd /tmp
wget http://downloads2.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz
tar xfvz ioncube_loaders_lin_x86-64.tar.gz

2. Find your PHP extension directory

php -i | grep extension_dir

Example output: extension_dir => /usr/lib/php5/20121212

3. Copy the correct loader for your PHP version

# Replace 5.6 with your PHP version (5.6, 7.0, 7.1, 7.2, etc.)
sudo cp /tmp/ioncube/ioncube_loader_lin_5.6.so /usr/lib/php5/20121212/ioncube/

4. Add IonCube to the PHP configuration

Create or edit the IonCube ini file. It must be loaded before other extensions:

# For Apache PHP:
sudo nano /etc/php5/apache2/conf.d/00-ioncube.ini

# For CLI PHP:
sudo nano /etc/php5/cli/conf.d/00-ioncube.ini

Add the line:

zend_extension = /usr/lib/php5/20121212/ioncube/ioncube_loader_lin_5.6.so

5. Restart Apache

sudo service apache2 restart

Verify

php -v

Output should include a line similar to:

with the ionCube PHP Loader (enabled) + Intrusion Protection from ioncube24.com

Troubleshooting

  • If the CLI still reports "ionCube Loader not installed", ensure 00-ioncube.ini also exists in the CLI config directory (/etc/php5/cli/conf.d/).
  • The loader filename must match your exact PHP version. Run php -v to confirm the version.
  • IonCube must be loaded as a zend_extension, not a regular extension.

Set Up vsftpd for a User Directory on Ubuntu 16.04

vsftpd (Very Secure FTP Daemon) is a lightweight, secure FTP server. This guide configures vsftpd to restrict an FTP user to their home directory (chroot jail) on Ubuntu 16.04.

Prerequisites

  • Ubuntu 16.04 with root or sudo access
  • Ports 20, 21, and a passive port range open in the firewall

Steps

1. Install vsftpd

sudo apt-get install vsftpd

2. Create a dedicated FTP user

sudo adduser ftpuser
sudo mkdir -p /home/ftpuser/ftp
sudo chown nobody:nogroup /home/ftpuser/ftp
sudo chmod a-w /home/ftpuser/ftp
sudo mkdir /home/ftpuser/ftp/files
sudo chown ftpuser:ftpuser /home/ftpuser/ftp/files

3. Configure vsftpd

sudo nano /etc/vsftpd.conf

Set the following options:

listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
chroot_local_user=YES
allow_writeable_chroot=YES
user_sub_token=$USER
local_root=/home/$USER/ftp
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=50000
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

4. Add the user to the allowed userlist

echo "ftpuser" | sudo tee -a /etc/vsftpd.userlist

5. Restart vsftpd

sudo systemctl restart vsftpd

Verify

ftp localhost

Log in as ftpuser. The user should be confined to their home directory.

Troubleshooting

  • If connections time out, open the passive port range in UFW: sudo ufw allow 40000:50000/tcp
  • "500 OOPS: vsftpd: refusing to run with writable root inside chroot" — set allow_writeable_chroot=YES or remove write permission from the root directory.
  • Check logs at /var/log/vsftpd.log for connection errors.

Install Linux Malware Detect (Maldet) on Ubuntu

Linux Malware Detect (LMD / Maldet) is a malware scanner designed for shared hosting environments. It uses threat signatures derived from network edge intrusion detection systems and integrates with ClamAV for improved detection.

Prerequisites

  • Ubuntu server with root or sudo access
  • ClamAV installed (optional but recommended)

Steps

1. Download and install Maldet

cd /tmp
wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
tar xfz maldetect-current.tar.gz
cd maldetect-*/
sudo bash install.sh

2. Configure Maldet

sudo nano /usr/local/maldetect/conf.maldet

Key settings to review:

# Enable email alerts
email_alert="1"
email_addr="admin@example.com"

# Move detected malware to quarantine
quarantine_hits="1"

# Enable ClamAV engine if installed
clamav_scan="1"

3. Update malware signatures

sudo maldet --update-sigs

4. Run a scan on a directory

sudo maldet --scan-all /var/www/html

5. Review scan results

sudo maldet --report list

6. Set up a daily cron job

The installer typically creates a cron job automatically. Verify:

cat /etc/cron.daily/maldet

Verify

maldet -v

Check the version and confirm it runs without errors.

Notes

  • Quarantined files are stored at /usr/local/maldetect/quarantine/.
  • Run maldet --checkout SCANID to restore a quarantined file if it was a false positive.
  • Combine with ClamAV for better detection: sudo apt-get install clamav clamav-daemon

Analyze Disk Usage with TreeSize / du

The du command reports disk usage by directory. This guide shows how to use it effectively and provides a shell script that mimics the TreeSize tool, displaying directory sizes in a human-readable format sorted by size.

Prerequisites

  • A Linux shell with standard utilities (du, sort, awk)

Steps

1. Quick disk usage of current directory (one level deep)

du -h --max-depth=1 | sort -rh

2. Disk usage of a specific directory

du -sh /var/www/*

3. Create a TreeSize-style script

Create the file and make it executable:

sudo nano /usr/local/bin/treesize
sudo chmod +x /usr/local/bin/treesize

Paste the following content:

#!/bin/sh
du -k --max-depth=1 "$@" | sort -nr | awk '
BEGIN {
    split("KB,MB,GB,TB", Units, ",");
}
{
    u = 1;
    while ($1 >= 1024) {
        $1 = $1 / 1024;
        u += 1
    }
    $1 = sprintf("%.1f %s", $1, Units[u]);
    print $0;
}
'

4. Run treesize from any directory

# Current directory
treesize

# Specific directory
treesize /var/www

Verify

treesize /var

You should see output like:

2.3 GB  .
1.1 GB  ./www
512.0 MB ./lib
...

Notes

  • The built-in alternative: du -h --max-depth=1 /var | sort -rh | head -20
  • To find the largest files (not directories): find / -type f -printf '%s %p ' | sort -rn | head -20
  • For a full interactive disk usage viewer, install ncdu: sudo apt-get install ncdu

Create and Install SSL Certificate on Apache (Ubuntu)

This guide covers creating a self-signed SSL certificate and configuring Apache to serve HTTPS on Ubuntu. Self-signed certificates are suitable for development and internal use; for production, use a CA-issued certificate or Let's Encrypt.

Prerequisites

  • Ubuntu 14.04 or later with Apache installed
  • mod_ssl enabled
  • Root or sudo access

Steps

1. Enable the Apache SSL module

sudo a2enmod ssl
sudo systemctl restart apache2

2. Generate a self-signed certificate

sudo openssl req -x509 -nodes -days 365   -newkey rsa:2048   -keyout /etc/ssl/private/apache-selfsigned.key   -out /etc/ssl/certs/apache-selfsigned.crt

Fill in the prompts. For Common Name, enter your server's domain or IP address.

3. Create an SSL virtual host configuration

sudo nano /etc/apache2/sites-available/default-ssl.conf
<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/html

    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/apache-selfsigned.crt
    SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key

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

4. Enable the SSL site and reload Apache

sudo a2ensite default-ssl.conf
sudo systemctl reload apache2

5. (Optional) Redirect HTTP to HTTPS

sudo nano /etc/apache2/sites-available/000-default.conf

Add inside the VirtualHost block:

Redirect permanent / https://example.com/
sudo systemctl reload apache2

Verify

sudo apache2ctl configtest
sudo ss -tlnp | grep 443

Navigate to https://your-server-ip to confirm HTTPS is working (expect a browser warning for self-signed certificates).

Notes

  • For a trusted certificate, use Certbot (Let's Encrypt): sudo apt-get install certbot python-certbot-apache && sudo certbot --apache
  • Self-signed certificates cause browser warnings — only use them in development or internal environments.

Install and Secure phpMyAdmin on Ubuntu 14.04

phpMyAdmin provides a web-based interface for managing MySQL databases. This guide installs it on Ubuntu 14.04 and secures it with Apache authentication.

Prerequisites

  • Ubuntu 14.04 with a LAMP stack (Apache, MySQL, PHP) installed
  • A non-root user with sudo privileges

Steps

1. Install phpMyAdmin

sudo apt-get update
sudo apt-get install phpmyadmin

When prompted: select apache2 as the web server, and choose Yes to configure the database with dbconfig-common.

2. Enable the phpMyAdmin configuration in Apache

sudo php5enmod mcrypt
sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
sudo a2enconf phpmyadmin
sudo service apache2 reload

3. Add an Apache authentication layer (security)

sudo nano /etc/apache2/conf-available/phpmyadmin.conf

Add inside the <Directory /usr/share/phpmyadmin> block:

Options SymLinksIfOwnerMatch
DirectoryIndex index.php
AllowOverride All

4. Create an .htaccess file to require authentication

sudo nano /usr/share/phpmyadmin/.htaccess
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/phpmyadmin/.htpasswd
Require valid-user

5. Create a login user for the htpasswd file

sudo htpasswd -c /etc/phpmyadmin/.htpasswd admin_user
sudo service apache2 restart

Verify

Open http://your-server-ip/phpmyadmin. You should be prompted for the htpasswd credentials first, then the MySQL login.

Notes

  • Consider changing the phpMyAdmin URL path to something non-obvious to reduce automated attacks.
  • For Ubuntu 16.04+, use sudo phpenmod mcrypt instead of php5enmod.
  • Keep phpMyAdmin updated: sudo apt-get upgrade phpmyadmin

Find Files Modified Today or Since a Specific Time

The find command with the -mtime and -newer options lets you locate recently changed files — useful for auditing changes, debugging, or incident response.

Prerequisites

  • A Unix/Linux shell

Steps

1. Find files modified in the last 24 hours

find . -mtime -1 -print

2. Find files modified in the last 60 minutes

find . -mmin -60

3. Find files modified in the last 7 days

find . -mtime -7 -print

4. Find files modified since a specific date

find . -newer /tmp/reference-file

Create a reference file with a specific timestamp:

touch -t 202401150000 /tmp/ref
find /var/www -newer /tmp/ref

5. Show modification times with ls-style output

find . -mtime -1 -ls

6. Search only specific file types

# Only PHP files modified in last 24 hours
find /var/www -name "*.php" -mtime -1 -print

# Only regular files (no directories)
find /var/www -type f -mtime -1 -print

7. Find files modified on a specific day (today)

find . -daystart -mtime 0

Notes

  • -mtime -1 = modified less than 1 day ago (last 24 hours)
  • -mtime 0 = modified today (from midnight)
  • -mtime +7 = modified more than 7 days ago
  • Combine with -exec to act on results: find . -mtime -1 -exec ls -la {} \;

Set Up a Mail Server on Ubuntu 14.04 (Postfix, Dovecot, MySQL)

This guide covers setting up a complete mail server on Ubuntu 14.04 in AWS using Postfix (MTA), Dovecot (IMAP/POP3), MySQL (virtual user storage), amavisd-new, SpamAssassin, ClamAV, and Roundcube webmail.

Prerequisites

  • Ubuntu 14.04 EC2 instance with a static/Elastic IP
  • A registered domain with DNS control
  • Port 25 outbound unblocked by AWS (submit a request to AWS support if needed)
  • MX record pointing to your server

Steps

1. Update the system and set the hostname

sudo apt-get update && sudo apt-get upgrade -y
sudo hostnamectl set-hostname mail.example.com

Set the FQDN in /etc/hosts:

127.0.0.1   mail.example.com localhost

2. Install MySQL and create the mail database

sudo apt-get install mysql-server
mysql -u root -p <<'SQL'
CREATE DATABASE mailserver;
GRANT ALL ON mailserver.* TO 'mailuser'@'localhost' IDENTIFIED BY 'mailpassword';
FLUSH PRIVILEGES;
SQL

3. Install Postfix

sudo apt-get install postfix postfix-mysql

Select Internet Site during setup. Set the system mail name to your domain.

4. Install Dovecot for IMAP/POP3

sudo apt-get install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql

5. Install anti-spam and anti-virus tools

sudo apt-get install amavisd-new spamassassin clamav clamav-daemon postgrey

6. Install Postfix Admin for web-based user management

sudo apt-get install postfixadmin

7. Install Roundcube webmail

sudo apt-get install roundcube roundcube-mysql

8. Configure DNS records

Add these DNS records for your domain:

MX     10  mail.example.com
A          mail.example.com  → your.server.ip
PTR        your.server.ip → mail.example.com (set via hosting provider)
TXT        "v=spf1 mx ~all"

Verify

# Test SMTP
telnet localhost 25
# Type: EHLO localhost

# Check mail queue
mailq

# Check Postfix status
sudo systemctl status postfix
sudo systemctl status dovecot

Notes

  • Set up DKIM and SPF records to improve deliverability (see the companion DKIM guide).
  • AWS blocks port 25 by default on EC2. Use the AWS request form to get it unblocked, or relay through SES on port 587.
  • Keep ClamAV updated: sudo freshclam

Set Up SPF and DKIM on Ubuntu 14.04

SPF and DKIM are email authentication mechanisms that improve deliverability and help prevent your mail from being flagged as spam by recipients such as Gmail. This guide configures both for a Postfix mail server on Ubuntu 14.04.

Prerequisites

  • A Postfix mail server already running
  • DNS control over your domain
  • Root or sudo access

Steps

Part 1: Set Up SPF

1. Add an SPF TXT record to your DNS

TXT @ "v=spf1 mx a ip4:YOUR.SERVER.IP ~all"

This tells receiving servers that only your mail server is authorized to send mail for your domain.

2. Install the Postfix SPF policy agent

sudo apt-get install postfix-policyd-spf-python

3. Add SPF checking to Postfix main.cf

sudo nano /etc/postfix/main.cf
policyd-spf_time_limit = 3600
sudo nano /etc/postfix/master.cf
policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Part 2: Set Up DKIM

4. Install OpenDKIM

sudo apt-get install opendkim opendkim-tools

5. Generate a DKIM key pair

sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -t -s mail -d example.com   -D /etc/opendkim/keys/example.com/
sudo chown -R opendkim:opendkim /etc/opendkim/keys/

6. Configure OpenDKIM

sudo nano /etc/opendkim.conf
AutoRestart         Yes
AutoRestartRate     10/1h
Syslog              yes
SyslogSuccess       Yes
LogWhy              Yes
Canonicalization    relaxed/simple
ExternalIgnoreList  refile:/etc/opendkim/TrustedHosts
InternalHosts       refile:/etc/opendkim/TrustedHosts
KeyTable            refile:/etc/opendkim/KeyTable
SigningTable        refile:/etc/opendkim/SigningTable
Mode                sv
PidFile             /var/run/opendkim/opendkim.pid
SignatureAlgorithm  rsa-sha256
UserID              opendkim:opendkim
Socket              inet:12301@localhost

7. Add the DKIM public key to DNS

sudo cat /etc/opendkim/keys/example.com/mail.txt

Add the displayed value as a TXT record named mail._domainkey.example.com.

8. Restart services

sudo systemctl restart opendkim postfix

Verify

# Test DKIM signing
opendkim-testkey -d example.com -s mail -vvv

Send a test email to check-auth@verifier.port25.com and review the reply for SPF and DKIM pass/fail results.

Notes

  • DNS changes can take up to 48 hours to propagate worldwide.
  • Use ~all (softfail) for SPF initially, then switch to -all (hard fail) once you confirm all legitimate sources are listed.

Install Composer on Ubuntu

Composer is the standard dependency manager for PHP. This guide covers installing Composer globally on Ubuntu and common usage patterns including running as the www-data user.

Prerequisites

  • PHP installed (PHP 5.6 or higher)
  • curl or wget available
  • Root or sudo access

Steps

1. Download and install Composer globally

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer

2. Verify the installation

composer --version

3. Install project dependencies

cd /path/to/your/project
composer install

4. Install production dependencies only (no dev packages)

composer install --no-dev --optimize-autoloader

5. Run Composer as the www-data user (recommended for web projects)

sudo -u www-data /usr/local/bin/composer install   --no-ansi   --no-dev   --no-interaction   --no-progress   --no-scripts   --optimize-autoloader

6. Increase memory limit if Composer runs out of memory

COMPOSER_MEMORY_LIMIT=-1 composer update

Verify

composer diagnose

This checks for common issues with the Composer installation and PHP configuration.

Notes

  • Keep Composer updated: sudo composer self-update
  • Store composer.lock in version control to ensure reproducible builds.
  • Never run Composer as root in production. Use sudo -u www-data instead.

Speed Up Apache for Maximum Performance

Apache performance can be significantly improved through MPM tuning, enabling caching, compression, and keep-alive settings. This guide covers the key configuration changes to optimize Apache for high-traffic sites.

Prerequisites

  • Apache 2.4 installed
  • Root or sudo access

Steps

1. Choose the right MPM (Multi-Processing Module)

For PHP with mod_php: use Prefork. For PHP-FPM: use Event or Worker.

# Check current MPM
apache2ctl -V | grep MPM

# Switch to Event MPM (for PHP-FPM setups)
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2

2. Tune MPM Prefork settings

sudo nano /etc/apache2/mods-available/mpm_prefork.conf
<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxRequestWorkers   150
    MaxConnectionsPerChild 10000
</IfModule>

3. Enable mod_deflate for gzip compression

sudo a2enmod deflate
sudo nano /etc/apache2/mods-enabled/deflate.conf
AddOutputFilterByType DEFLATE text/html text/plain text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE image/svg+xml

4. Enable mod_expires for browser caching

sudo a2enmod expires

Add to your virtual host or .htaccess:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType text/css "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"
</IfModule>

5. Enable Keep-Alive

sudo nano /etc/apache2/apache2.conf
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

6. Disable unused modules

sudo a2dismod status autoindex
sudo systemctl restart apache2

Verify

# Check Apache is running correctly
sudo apache2ctl configtest
sudo systemctl status apache2

# Test compression
curl -H "Accept-Encoding: gzip" -I http://your-site.com

Notes

  • Use ab (ApacheBench) to benchmark before and after: ab -n 1000 -c 10 http://your-site.com/
  • For high-traffic sites, consider moving to Nginx as a reverse proxy in front of Apache.
  • Monitor Apache server status at http://your-server/server-status with mod_status enabled.

Switch Apache MPM from Prefork to Worker

Apache's MPM (Multi-Processing Module) determines how it handles connections. Prefork spawns a process per request (safe for mod_php), while Worker uses threads (better performance, required for PHP-FPM). This guide switches from Prefork to Worker.

Prerequisites

  • Apache 2.4 on Debian/Ubuntu
  • If using PHP: must be configured with PHP-FPM (not mod_php), as mod_php is not thread-safe
  • Root or sudo access

Steps

1. Stop Apache

sudo service apache2 stop

2. Disable mod_php if enabled (not thread-safe)

sudo a2dismod php7.0   # adjust version as needed

3. Disable the Prefork MPM

sudo a2dismod mpm_prefork

4. Enable the Worker MPM

sudo a2enmod mpm_worker

5. Enable PHP-FPM and its Apache proxy module

sudo apt-get install php-fpm
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php7.0-fpm

6. Start Apache

sudo service apache2 start

Verify

# Confirm the active MPM
apache2ctl -V | grep MPM

# Check server-status
curl http://localhost/server-status

The output should show Server MPM: worker.

Notes

  • For modern setups, consider mpm_event instead of mpm_worker — it handles keep-alive connections more efficiently.
  • PHP-FPM must be running before Apache starts. Check with: sudo systemctl status php7.0-fpm
  • Worker MPM configuration is in /etc/apache2/mods-available/mpm_worker.conf.

Fix PHP Code Displaying as Plain Text in Apache

When Apache displays PHP source code instead of executing it, the PHP module is either not enabled or not loaded correctly. This guide covers the fix for Ubuntu/Debian systems.

Prerequisites

  • Apache and PHP installed
  • Root or sudo access

Steps

1. Enable the PHP Apache module

# For PHP 7.0:
sudo a2enmod php7.0

# For PHP 7.4:
sudo a2enmod php7.4

# For PHP 8.1:
sudo a2enmod php8.1

2. Disable any conflicting PHP version modules

# If you previously had PHP 5.x enabled:
sudo a2dismod php5

# If you have multiple PHP versions:
sudo a2dismod php7.4
sudo a2enmod php8.1

3. Verify the PHP module configuration exists

ls /etc/apache2/mods-enabled/ | grep php

4. Restart Apache

sudo systemctl restart apache2

Verify

Create a test file:

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

Open http://your-server/phptest.php in a browser. You should see the PHP information page, not raw source code.

Remove the test file when done:

sudo rm /var/www/html/phptest.php

Troubleshooting

  • If using PHP-FPM, ensure mod_php is disabled and instead enable: sudo a2enmod proxy_fcgi setenvif
  • Check that the PHP module file exists: ls /etc/apache2/mods-available/ | grep php
  • Check the Apache error log for additional clues: sudo tail -20 /var/log/apache2/error.log

Fix PHP IonCube Loader Error

If you receive an "IonCube Loader is not installed" error when running PHP from the command line — even though IonCube is listed in your Apache php.ini — the CLI PHP configuration is using a separate ini file that also needs the loader entry.

Prerequisites

  • IonCube loader files already installed in the PHP extension directory
  • Root or sudo access

Steps

1. Locate the IonCube loader path already used by Apache PHP

grep -r ioncube /etc/php5/apache2/php.ini

Example output:

zend_extension = /usr/lib/php5/20121212/ioncube/ioncube_loader_lin_5.5.so

2. Add the same line to the CLI php.ini

sudo nano /etc/php5/cli/php.ini

Add at the top of the file (before any other extensions):

zend_extension = /usr/lib/php5/20121212/ioncube/ioncube_loader_lin_5.5.so

3. Alternatively, create a separate ini file for CLI

echo "zend_extension = /usr/lib/php5/20121212/ioncube/ioncube_loader_lin_5.5.so"   | sudo tee /etc/php5/cli/conf.d/00-ioncube.ini

Verify

php -v

The output should include the IonCube line:

with the ionCube PHP Loader (enabled)
# Also test running an encoded file
php encoded-file.php

Notes

  • PHP has separate ini files for CLI (/etc/php5/cli/) and Apache (/etc/php5/apache2/). Changes to one do not affect the other.
  • IonCube must always be the first zend_extension loaded. File naming prefixed with 00- ensures load order.
  • For PHP 7.x paths, use /etc/php/7.x/cli/conf.d/ instead.

FastCGI vs mod_php: Why FastCGI is Faster

Many administrators notice that Nginx with PHP via FastCGI (PHP-FPM) outperforms Apache with mod_php. This guide explains why and when to choose each approach.

How mod_php Works

With mod_php, the PHP interpreter is embedded directly inside each Apache worker process. This means:

  • Every Apache process loads the PHP interpreter into memory, even for requests that serve static files.
  • Apache must use the Prefork MPM (multi-process, not multi-threaded) because mod_php is not thread-safe.
  • Each Apache worker holds PHP in memory whether or not it is processing a PHP request.

How FastCGI / PHP-FPM Works

With FastCGI, the web server (Nginx or Apache with Event MPM) passes PHP requests to a separate PHP-FPM process pool:

  • The web server can handle static files without loading PHP at all.
  • PHP-FPM manages its own pool of PHP worker processes independently.
  • Nginx can use an event-driven architecture for all connections, not just PHP ones.
  • PHP-FPM workers are reused across requests without restarting.

Performance Summary

Architecture          | Static file overhead | PHP memory overhead | Concurrency model
----------------------|---------------------|---------------------|-----------------
Apache + mod_php      | High (PHP in memory)| High (per process)  | Process-based
Nginx + PHP-FPM       | Low (no PHP loaded) | Low (shared pool)   | Event-driven
Apache + Event + FPM  | Medium              | Low                 | Thread-based

When to Use Each

  • Nginx + PHP-FPM: Best for high-traffic sites, API servers, or when serving many static assets alongside PHP.
  • Apache + mod_php: Simpler configuration, good for shared hosting or sites with .htaccess-heavy WordPress/Drupal setups.
  • Apache + Event MPM + PHP-FPM: A good middle ground if you need Apache features (mod_rewrite, .htaccess) with better performance.

Switch Apache to PHP-FPM

sudo apt-get install php-fpm
sudo a2dismod php7.4
sudo a2enmod proxy_fcgi setenvif mpm_event
sudo a2enconf php7.4-fpm
sudo systemctl restart apache2 php7.4-fpm

Notes

  • PHP-FPM pool configuration is at /etc/php/7.4/fpm/pool.d/www.conf.
  • Tune pm.max_children based on available RAM: divide available RAM by average PHP process size (check with ps aux | grep php-fpm).

Install Apache 2.4, MariaDB 10, and PHP 7 on Ubuntu

This guide installs a modern LAMP stack on Ubuntu 16.04 using the latest stable releases of Apache 2.4, MariaDB 10, and PHP 7.

Prerequisites

  • Ubuntu 16.04 64-bit server
  • A sudo user
  • Internet access

Steps

1. Update the system

sudo apt-get update && sudo apt-get upgrade -y

2. Install Apache 2.4

sudo apt-get install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2

3. Install MariaDB 10

sudo apt-get install mariadb-server mariadb-client -y
sudo systemctl start mariadb
sudo systemctl enable mariadb
sudo mysql_secure_installation

4. Install PHP 7

sudo apt-get install php7.0 libapache2-mod-php7.0 php7.0-mysql   php7.0-curl php7.0-gd php7.0-mbstring php7.0-xml php7.0-zip -y

5. Restart Apache to load PHP module

sudo systemctl restart apache2

6. (Optional) Add PPA for newer PHP versions

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.4 libapache2-mod-php7.4

Verify

# Check versions
apache2 -v
mysql --version
php -v

# Test PHP processing
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/phpinfo.php

Browse to http://your-server-ip/phpinfo.php to confirm PHP is running. Delete the file afterward.

Notes

  • The MariaDB root password is set during mysql_secure_installation.
  • Apache document root: /var/www/html/
  • PHP configuration: /etc/php/7.0/apache2/php.ini
  • MariaDB configuration: /etc/mysql/mariadb.conf.d/

Move Apache Web Root to a New Location on Ubuntu

By default, Apache serves files from /var/www/html. You may need to move this to a different partition or directory — for example, to a larger data disk. This guide safely relocates the Apache document root on Ubuntu 16.04.

Prerequisites

  • Ubuntu 16.04 with Apache installed
  • The new location already mounted and accessible
  • Root or sudo access

Steps

1. Copy existing web files to the new location

sudo rsync -avz /var/www/html/ /new/web/root/

2. Update the Apache default virtual host

sudo nano /etc/apache2/sites-available/000-default.conf

Change the DocumentRoot line:

DocumentRoot /new/web/root

3. Update the Directory block in apache2.conf

sudo nano /etc/apache2/apache2.conf

Find and update the Directory block to match the new path:

<Directory /new/web/root/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

4. Set correct ownership and permissions

sudo chown -R www-data:www-data /new/web/root
sudo find /new/web/root -type d -exec chmod 755 {} \;
sudo find /new/web/root -type f -exec chmod 644 {} \;

5. Test and reload Apache

sudo apache2ctl configtest
sudo systemctl reload apache2

Verify

curl -I http://localhost

Confirm the site loads correctly from the new document root.

Notes

  • If using AppArmor (Ubuntu), you may need to update the Apache AppArmor profile at /etc/apparmor.d/usr.sbin.apache2 to allow access to the new path.
  • Keep the old directory until you have confirmed everything works from the new location.
  • Update any PHP application configuration files that have hardcoded absolute paths.

Run Apache httpd and Tomcat on Port 80 Together

When you need Apache httpd and Apache Tomcat on the same server and port 80, you can use httpd as a reverse proxy. httpd handles port 80 for all traffic and forwards Java application requests to Tomcat (typically running on port 8080).

Prerequisites

  • Apache httpd installed and running on port 80
  • Apache Tomcat running on localhost port 8080
  • mod_proxy modules available

Steps

1. Enable the required proxy modules

sudo a2enmod proxy proxy_http proxy_ajp
sudo systemctl restart apache2

2. Create a virtual host to proxy traffic to Tomcat

sudo nano /etc/apache2/sites-available/javaapp.conf
<VirtualHost *:80>
    ServerName javaapp.example.com

    ProxyRequests Off
    ProxyPreserveHost On

    <Proxy *>
        Require all granted
    </Proxy>

    ProxyPass        / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

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

3. Enable the site

sudo a2ensite javaapp.conf
sudo systemctl reload apache2

4. Configure Tomcat to recognize the proxy

Edit $CATALINA_HOME/conf/server.xml and add proxy attributes to the HTTP Connector:

<Connector port="8080" protocol="HTTP/1.1"
  proxyName="javaapp.example.com"
  proxyPort="80"
  scheme="http" />

5. Restart Tomcat

sudo systemctl restart tomcat

Verify

curl -I http://javaapp.example.com

The response should be served from Tomcat through the Apache proxy.

Notes

  • For SSL termination, configure HTTPS on the Apache virtual host and keep Tomcat on HTTP internally.
  • Multiple Java apps can be hosted by using different ServerName virtual hosts, each proxying to a different Tomcat port or context path.

Host Jira on a Subdomain with Apache

This guide configures Apache as a reverse proxy to expose a Jira instance (running on port 8080) via a subdomain such as jira.example.com on port 80.

Prerequisites

  • Jira installed and running on localhost port 8080
  • Apache with mod_proxy enabled
  • A DNS A record for jira.example.com pointing to the server

Steps

1. Enable the required Apache modules

sudo a2enmod proxy proxy_http proxy_ajp
sudo systemctl restart apache2

2. Create the virtual host configuration

sudo nano /etc/apache2/sites-available/jira.conf
<VirtualHost *:80>
    ServerName jira.example.com

    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    <Proxy *>
        Require all granted
    </Proxy>

    ProxyPass        / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

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

3. Enable the site

sudo a2ensite jira.conf
sudo systemctl reload apache2

4. Update Jira's base URL configuration

Edit /opt/atlassian/jira/conf/server.xml and add proxy settings to the Connector:

<Connector port="8080" ...
    proxyName="jira.example.com"
    proxyPort="80"
    scheme="http" />

5. Restart Jira

sudo /etc/init.d/jira restart
# or
sudo systemctl restart jira

Verify

curl -I http://jira.example.com

Open http://jira.example.com in a browser and confirm Jira loads correctly.

Notes

  • Also update Jira's Base URL in Administration > System > General Configuration to http://jira.example.com.
  • For HTTPS, add an SSL virtual host and set scheme="https" and proxyPort="443" in server.xml.

Set Up SSH Key Login and Disable Password Auth

SSH key authentication is more secure than password login because keys are mathematically strong and cannot be brute-forced. This guide sets up key-based SSH on a CentOS server and optionally disables password authentication.

Prerequisites

  • A CentOS or RHEL server with SSH access
  • An SSH key pair (generate if needed)

Steps

1. Generate an SSH key pair on your local machine

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

This creates ~/.ssh/id_rsa (private) and ~/.ssh/id_rsa.pub (public).

2. Copy the public key to the server

ssh-copy-id username@server-ip

Or manually:

cat ~/.ssh/id_rsa.pub | ssh username@server-ip   "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

3. Set correct permissions on the server

ssh username@server-ip
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

4. Test key-based login

ssh -i ~/.ssh/id_rsa username@server-ip

Confirm you can log in without being asked for a password.

5. Disable password authentication in sshd_config

sudo nano /etc/ssh/sshd_config

Set the following options:

PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no

6. Restart SSH

sudo systemctl restart sshd

Verify

# Open a NEW terminal and test login before closing the current session
ssh username@server-ip

Troubleshooting

  • Do not close your current SSH session until you have confirmed key login works in a new window.
  • If you get "Permission denied (publickey)", check file permissions on ~/.ssh/ and ~/.ssh/authorized_keys.
  • On AWS EC2, password authentication is disabled by default; use the key pair selected at instance launch.

Kill a Process Running on a Specific Port in Linux

When a port is occupied by a lingering process, you can identify and kill it using lsof, fuser, or netstat. This guide covers all three approaches.

Prerequisites

  • Root or sudo access
  • lsof or net-tools installed

Steps

Method 1: Using lsof (recommended)

# List processes listening on port 8080
sudo lsof -i:8080

# Kill the process listening on port 8080
sudo kill $(sudo lsof -t -i:8080)

# Force kill (SIGKILL) if the process ignores regular kill
sudo kill -9 $(sudo lsof -t -i:8080)

Method 2: Using fuser

# Show process using port 8080
sudo fuser 8080/tcp

# Kill it immediately
sudo fuser -k 8080/tcp

Method 3: Using netstat + grep + kill

# Find the PID of the process on port 8080
sudo netstat -tlnp | grep :8080

# Example output: tcp  0  0  0.0.0.0:8080  ...  12345/java
# Kill the process by PID
sudo kill 12345

Method 4: Using ss (modern alternative to netstat)

sudo ss -tlnp | grep :8080

Verify

# Confirm nothing is listening on the port after kill
sudo lsof -i:8080

No output means the port is now free.

Notes

  • kill PID sends SIGTERM (graceful shutdown). kill -9 PID sends SIGKILL (immediate, no cleanup).
  • Prefer SIGTERM first; only use SIGKILL if the process does not stop.
  • If lsof is not installed: sudo apt-get install lsof (Ubuntu) or sudo yum install lsof (CentOS).

Configure Apache Virtual Hosts

Apache Virtual Hosts allow you to host multiple websites on a single server. Each site gets its own configuration with its own domain name, document root, and log files.

Prerequisites

  • Apache 2.4 installed on Ubuntu/Debian or RHEL/CentOS
  • A domain name resolving to the server (or a hosts file entry for testing)
  • Root or sudo access

Steps

1. Create the document root directory

sudo mkdir -p /var/www/dev
sudo chown -R www-data:www-data /var/www/dev

2. Create the virtual host configuration file

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

    ErrorLog  ${APACHE_LOG_DIR}/dev.webjiffy.com-error.log
    LogLevel  warn
    CustomLog ${APACHE_LOG_DIR}/dev.webjiffy.com-access.log combined

    <Directory /var/www/dev>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

3. Enable the virtual host

sudo a2ensite dev.webjiffy.com.conf
sudo systemctl reload apache2

4. For RHEL/CentOS: place the config in conf.d

sudo nano /etc/httpd/conf.d/dev.webjiffy.com.conf

Then restart httpd:

sudo systemctl restart httpd

Verify

sudo apache2ctl configtest
curl -H "Host: dev.webjiffy.com" http://localhost

Notes

  • Enable mod_rewrite for .htaccess redirects: sudo a2enmod rewrite
  • To test locally without DNS, add an entry to /etc/hosts: 127.0.0.1 dev.webjiffy.com
  • Multiple virtual hosts are evaluated in alphabetical order; a 000-default.conf catches unmatched requests.

Switch PHP Versions with update-alternatives

When multiple PHP versions are installed (e.g., PHP 5.6 and PHP 7.1), update-alternatives lets you switch the default version for both the CLI and Apache without uninstalling either version.

Prerequisites

  • Multiple PHP versions installed (e.g., via the Ondrej PPA)
  • Root or sudo access

Steps

1. Switch the CLI default PHP version

# Interactive selection
sudo update-alternatives --config php

# Or set directly (switch to PHP 7.1)
sudo update-alternatives --set php /usr/bin/php7.1

2. Switch the Apache PHP module

# Disable current PHP version module (e.g., 5.6)
sudo a2dismod php5.6

# Enable the new version (e.g., 7.1)
sudo a2enmod php7.1

sudo systemctl restart apache2

3. Switch from PHP 5.6 to PHP 7.1 (full example)

sudo a2dismod php5.6
sudo a2enmod php7.1
sudo update-alternatives --set php /usr/bin/php7.1
sudo systemctl restart apache2

4. Switch from PHP 7.1 back to PHP 5.6

sudo a2dismod php7.1
sudo a2enmod php5.6
sudo update-alternatives --set php /usr/bin/php5.6
sudo systemctl restart apache2

Verify

# Confirm the CLI version
php -v

# Confirm the Apache version (create a test file)
echo "<?php echo PHP_VERSION; ?>" | sudo tee /var/www/html/ver.php
curl http://localhost/ver.php
sudo rm /var/www/html/ver.php

Notes

  • If using PHP-FPM, switch the FPM version too: sudo systemctl stop php5.6-fpm && sudo systemctl start php7.1-fpm
  • Check installed PHP versions: update-alternatives --list php
  • The Ondrej PPA is the standard source for multiple PHP versions on Ubuntu: sudo add-apt-repository ppa:ondrej/php

Linux Server Reboot Survival Guide

Server reboots — whether planned or unexpected — can cause services to fail to restart, reveal misconfigured startup scripts, or expose dependency ordering problems. This guide covers how to prepare for and recover from reboots.

Before Rebooting: Pre-Reboot Checklist

  • Notify users of planned downtime
  • Ensure all services are set to start on boot (systemctl enable)
  • Check for pending package updates that may need a reboot
  • Verify disk space is not critically low (reboots can fail with full disks)
  • Review cron jobs and background processes that need to resume
# Check which services are enabled to auto-start
systemctl list-unit-files --state=enabled

# Check pending reboot requirement (Debian/Ubuntu)
ls /var/run/reboot-required

Steps: Graceful Reboot

1. Schedule a reboot with a countdown

sudo shutdown -r +10 "Rebooting in 10 minutes for maintenance"

# Cancel a scheduled shutdown
sudo shutdown -c

2. Immediate reboot

sudo reboot
# or
sudo shutdown -r now

3. After the reboot: verify services started

# Check failed units
systemctl --failed

# Check service status
sudo systemctl status apache2 mysql nginx php-fpm

# Check logs for startup errors
sudo journalctl -b -p err

Enable Services to Auto-Start

sudo systemctl enable apache2
sudo systemctl enable mysql
sudo systemctl enable nginx
sudo systemctl enable redis

Troubleshooting Services That Did Not Start

# View detailed logs for a failed service
sudo journalctl -u apache2 --since "1 hour ago"

# Check configuration before starting
sudo apache2ctl configtest
sudo mysqld --validate-config

Notes

  • After a kernel update, the server must reboot to use the new kernel — old kernel bugs remain until reboot.
  • Use tmux or screen for long-running tasks so they survive SSH disconnections during reboot prep.
  • Test reboot readiness periodically in staging before a production event.

Find or Reset MariaDB Root Default Password

On a fresh MariaDB installation, the root user is authenticated via the system's sudo mechanism rather than a password. This guide covers securing the installation and resetting the root password if needed.

Prerequisites

  • MariaDB installed
  • Root or sudo system access

Steps

1. Run the secure installation script after initial install

sudo mysql_secure_installation

This prompts you to set a root password, remove anonymous users, disallow remote root login, remove the test database, and reload privileges.

2. Log in as root using sudo (no password needed initially)

sudo mysql -u root

3. Set or change the root password

sudo mysql -u root
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_new_password';
FLUSH PRIVILEGES;
EXIT;

4. If you have forgotten the root password: reset via safe mode

# Stop MariaDB
sudo systemctl stop mariadb

# Start in safe mode (skip grant tables)
sudo mysqld_safe --skip-grant-tables &

# Connect without a password
mysql -u root

# Reset the password
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';
EXIT;

# Stop safe mode and restart normally
sudo mysqladmin shutdown
sudo systemctl start mariadb

Verify

mysql -u root -p

Enter the new password. If you reach the MariaDB prompt, the password is set correctly.

Notes

  • On Ubuntu/Debian with MariaDB 10.4+, root uses unix_socket authentication by default. You must use sudo mysql rather than mysql -u root -p.
  • To allow traditional password auth: ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('yourpassword');

Update rsync to the Latest Version

The default rsync version packaged with CentOS 6 and 7 does not support the --info=progress2 flag for overall transfer progress display. This guide upgrades rsync to version 3.1.1+ from the RPMforge repository.

Prerequisites

  • CentOS 6 or CentOS 7 with root or sudo access
  • Internet access to download the RPM

Steps

1. Upgrade rsync on CentOS 7 (64-bit)

sudo yum install http://mirror.hmc.edu/rpmforge/redhat/el7/en/x86_64/extras/RPMS/rsync-3.1.1-1.el7.rfx.x86_64.rpm

2. Upgrade rsync on CentOS 6 (64-bit)

sudo yum install http://mirror.hmc.edu/rpmforge/redhat/el6/en/x86_64/extras/RPMS/rsync-3.1.1-1.el6.rfx.x86_64.rpm

3. Alternative: compile rsync from source

sudo yum install gcc make
wget https://download.samba.org/pub/rsync/rsync-latest.tar.gz
tar xvzf rsync-latest.tar.gz
cd rsync-*/
./configure
make
sudo make install

Verify

rsync --version

Confirm the version is 3.1.1 or higher.

Test with overall progress display:

rsync -a --info=progress2 /source/ /destination/

Notes

  • For large data migrations, use --info=progress2 combined with --stats for a summary after completion.
  • For resumable transfers, add --partial --append-verify.
  • Ubuntu/Debian repositories typically include newer rsync versions: sudo apt-get install rsync

Install PHP 5.6 or 7.1 on Ubuntu 16.04/14.04 via PPA

Ubuntu's default repositories may not include older PHP versions like 5.6 or specific releases of 7.x. The Ondrej Surý PPA provides up-to-date packages for multiple PHP versions side-by-side.

Prerequisites

  • Ubuntu 16.04, 14.04, or 12.04
  • Root or sudo access
  • software-properties-common installed

Steps

1. Add the Ondrej PHP PPA

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update

2. Install PHP 5.6

sudo apt-get install php5.6 libapache2-mod-php5.6 php5.6-mysql   php5.6-mbstring php5.6-curl php5.6-xml php5.6-gd php5.6-zip

3. Install PHP 7.1

sudo apt-get install php7.1 libapache2-mod-php7.1 php7.1-mysql   php7.1-mbstring php7.1-curl php7.1-xml php7.1-gd php7.1-zip

4. Set the active Apache PHP version

# Disable 7.1, enable 5.6
sudo a2dismod php7.1
sudo a2enmod php5.6
sudo systemctl restart apache2

5. Set the CLI default version

sudo update-alternatives --set php /usr/bin/php5.6

Verify

php -v
apache2 -v

Notes

  • To list all available PHP versions: apt-cache search php | grep "^php[0-9]"
  • If you need to remove a higher version first: sudo apt-get remove php7.x php7.x-*
  • Multiple PHP versions can coexist; use update-alternatives and a2enmod to switch between them (see the companion guide on switching PHP versions).

Configure vsftpd (Basic)

vsftpd is a secure, fast FTP server. This guide covers installing vsftpd, creating a chroot-jailed FTP user, and configuring passive mode for NAT/firewall environments.

Prerequisites

  • Ubuntu or Debian server with root or sudo access
  • Ports 20, 21, and the passive port range open in the firewall

Steps

1. Install vsftpd

sudo apt-get install vsftpd

2. Configure vsftpd

sudo nano /etc/vsftpd.conf

Use the following configuration:

listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_file=/var/log/vsftpd.log
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
chroot_local_user=YES
allow_writeable_chroot=YES
pasv_enable=YES
pasv_min_port=13000
pasv_max_port=13500
port_enable=YES
# Replace with your server's public IP
pasv_address=203.0.113.10
pasv_addr_resolve=YES

3. Create the FTP user

sudo adduser ftpuser
sudo passwd ftpuser

4. Restrict the user to their home directory

Ensure the home directory is not world-writable (vsftpd requirement):

sudo chmod a-w /home/ftpuser
sudo mkdir /home/ftpuser/uploads
sudo chown ftpuser:ftpuser /home/ftpuser/uploads

5. Restart vsftpd

sudo systemctl restart vsftpd
sudo systemctl enable vsftpd

Verify

ftp localhost

Log in as ftpuser. You should be confined to the home directory.

Troubleshooting

  • If passive connections fail, open ports 13000-13500 in UFW: sudo ufw allow 13000:13500/tcp
  • Check logs: sudo tail -f /var/log/vsftpd.log
  • "500 OOPS: vsftpd: refusing to run with writable root inside chroot" — the chroot directory must not be writable by the FTP user. Move uploads to a subdirectory.

Reset Root Password via Rescue Mode

If you are locked out of a Linux server and cannot log in as root, you can reset the root password by booting into rescue/recovery mode and using chroot.

Prerequisites

  • Access to the hosting provider's console or VPS rescue mode
  • Ability to boot the server into rescue mode

Steps

1. Request rescue mode from your hosting provider

In your control panel (e.g., Linode Manager, DigitalOcean, Vultr), activate rescue/recovery mode for the server and boot into it.

2. Find the main disk partition

fdisk -l

Identify your root partition (e.g., /dev/xvda1, /dev/sda1).

3. Mount the root partition

mount /dev/xvda1 /mnt

4. Chroot into the mounted system

chroot /mnt

5. Reset the root password

passwd root

Enter and confirm the new password when prompted.

6. Exit chroot and reboot normally

exit
umount /mnt
reboot

Verify

After the server boots back to its normal operating system, log in via SSH with the new root password:

ssh root@your-server-ip

Notes

  • The partition name (/dev/xvda1, /dev/sda1) varies by provider and virtualization type. Check fdisk -l output carefully.
  • Some rescue systems require mounting additional filesystems before chroot: mount --bind /dev /mnt/dev && mount --bind /proc /mnt/proc && mount --bind /sys /mnt/sys
  • After regaining access, consider setting up SSH key authentication to prevent future lockouts.

Common Linux Server Error Fixes

This guide documents fixes for common Linux server errors, including missing shared libraries and Java-related issues.

Error: libawt_xawt.so: libXext.so.6: cannot open shared object file

This error occurs when running Oracle JDK 8 on a minimal Ubuntu 64-bit installation that is missing required X11 libraries.

Fix:

sudo apt-get install libxrender1 libxtst6 libxi6

Error: error while loading shared libraries: libXext.so.6

Similar to the above, this often affects headless server environments running Java GUI or AWT applications.

Fix (Ubuntu 16.04 64-bit):

sudo apt-get install libxrender1 libxtst6 libxi6 libxext6

Error: Cannot connect to X11 server

Java applications that require a display (e.g., JasperReports) fail on headless servers.

Fix: Set a virtual display

sudo apt-get install xvfb
export DISPLAY=:99
Xvfb :99 -screen 0 1024x768x24 &

General: Find which package provides a missing library

# Ubuntu/Debian
apt-file search libXext.so.6

# CentOS/RHEL
yum provides "*/libXext.so.6"

Notes

  • On 64-bit systems, 32-bit libraries are in separate packages (e.g., lib32z1). Install the 64-bit version unless running 32-bit applications.
  • After installing missing libraries, restart the application service to reload dependencies.
  • Use ldd /path/to/binary to see all library dependencies and which ones are missing.

Troubleshoot Memory and Networking Issues

Many common Linux server issues stem from memory exhaustion or networking misconfiguration. This guide covers diagnosing and resolving both categories of problems.

Memory Issues

1. Check current memory and swap usage

free -m

If "Swap" shows heavy usage, the server is running low on RAM.

2. Monitor swap activity in real time

vmstat 1 10

Watch the si (swap in) and so (swap out) columns. Non-zero values indicate active swapping.

3. Find the processes consuming the most memory

ps aux --sort=-%mem | head -20

4. Clear the page cache (safe, does not drop application memory)

sudo sync; echo 1 | sudo tee /proc/sys/vm/drop_caches

Networking Issues

5. Check network interface status

ip addr show
ip link show

6. Test connectivity

# Ping the default gateway
ip route | grep default
ping -c 4 $(ip route | grep default | awk '{print $3}')

# Test DNS resolution
nslookup google.com
dig google.com

7. Check for port conflicts and listening services

sudo ss -tlnp
sudo netstat -tlnp

8. Review firewall rules

# Ubuntu (ufw)
sudo ufw status verbose

# CentOS/RHEL (firewalld)
sudo firewall-cmd --list-all

# iptables
sudo iptables -L -n -v

9. Check routing table

ip route show

Notes

  • Keep swap partition size to 256 MB or less on VPS/cloud instances — heavy swap use signals a need for more RAM, not more swap.
  • If a service is not reachable, check both the local firewall and any cloud-level security groups.
  • Network packet loss can be checked with: ping -c 100 8.8.8.8 | tail -2

Fix "UNEXPECTED INCONSISTENCY; RUN fsck" Error

This error occurs at boot when the filesystem has not been cleanly unmounted, typically after an unclean shutdown or power loss. The boot process detects inconsistencies and requires fsck to be run manually.

Prerequisites

  • Access to the server console or rescue mode
  • Knowledge of the affected device name (e.g., /dev/sda1)

Steps

1. Boot into rescue mode or single-user mode

The filesystem cannot be checked while it is mounted. Boot from a rescue image or use single-user mode if the system partially boots.

2. Identify the affected partition

The error message will name the device, for example: /dev/sda1: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY

3. Run fsck on the partition

sudo fsck -y /dev/sda1

The -y flag automatically answers "yes" to all repair prompts without manual intervention.

4. If the above fails, force a check

sudo fsck -f /dev/sda1

5. Reboot after fsck completes

sudo reboot

Verify

After reboot, confirm the filesystem is clean:

sudo dmesg | grep -i "ext4\|fsck\|error"

No errors should be reported for the partition.

Notes

  • Never run fsck on a mounted filesystem — it can cause data corruption. Always ensure the partition is unmounted first.
  • If the root filesystem needs checking, you must boot from rescue media or use a recovery environment.
  • Schedule regular filesystem checks on reboot using: sudo tune2fs -c 30 /dev/sda1 (check every 30 mounts)

Configure Pure-FTPd

Pure-FTPd is a free, secure FTP server with a focus on simplicity. Configuration is done through individual directive files or a single conf file. This guide covers the key settings for a secure, functional deployment.

Prerequisites

  • Pure-FTPd installed (sudo apt-get install pure-ftpd or sudo yum install pure-ftpd)
  • Root or sudo access

Steps

1. Edit the main configuration file

sudo nano /etc/pure-ftpd/pure-ftpd.conf

2. Key security settings to configure

# Chroot all users to their home directories
ChrootEveryone              yes

# Disable anonymous logins
NoAnonymous                 yes

# Limit simultaneous connections
MaxClientsNumber            50
MaxClientsPerIP             8

# Set passive port range (open these in your firewall too)
PassivePortRange            30000 50000

# For servers behind NAT, force the public IP for passive mode
ForcePassiveIP              203.0.113.10

# Enable TLS/SSL (recommended)
TLS                         1
CertFile                    /etc/ssl/private/pure-ftpd.pem

3. Generate a self-signed TLS certificate

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout /etc/ssl/private/pure-ftpd.pem   -out /etc/ssl/private/pure-ftpd.pem
sudo chmod 600 /etc/ssl/private/pure-ftpd.pem

4. Create a virtual FTP user

sudo pure-pw useradd ftpuser -u www-data -d /var/www/html
sudo pure-pw mkdb

5. Restart Pure-FTPd

sudo systemctl restart pure-ftpd
sudo systemctl enable pure-ftpd

Verify

sudo systemctl status pure-ftpd
ftp localhost

Notes

  • Open the passive port range in your firewall: sudo ufw allow 30000:50000/tcp
  • On cPanel servers, use WHM to configure Pure-FTPd settings to avoid conflicts with the control panel.
  • Check logs at /var/log/syslog or /var/log/messages for FTP connection issues.

Harden SSH Server Security

Hardening OpenSSH reduces the attack surface of your server. This guide covers key configuration changes to the SSH server on Ubuntu 16.04 LTS (applicable to most Linux distributions).

Prerequisites

  • OpenSSH server installed
  • Root or sudo access
  • A working SSH key pair already set up (before disabling password auth)

Steps

1. Backup the current SSH configuration

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

2. Edit sshd_config

sudo nano /etc/ssh/sshd_config

3. Apply hardening settings

# Disable root login
PermitRootLogin no

# Disable password authentication (use keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no

# Use only SSH protocol 2
Protocol 2

# Change the default port (reduces automated scanning)
Port 2222

# Limit login attempts
MaxAuthTries 3

# Disconnect idle sessions after 5 minutes
ClientAliveInterval 300
ClientAliveCountMax 0

# Restrict to specific users (optional)
AllowUsers youruser

# Disable X11 forwarding if not needed
X11Forwarding no

# Use strong host key algorithms
HostKeyAlgorithms ecdsa-sha2-nistp256,ssh-ed25519

# Limit login grace time
LoginGraceTime 30

4. Test the configuration before restarting

sudo sshd -t

5. Restart SSH

sudo systemctl restart ssh

Verify

# Open a NEW terminal and confirm you can still log in
ssh -p 2222 youruser@your-server-ip

Notes

  • Always test in a new terminal before closing your current session. A misconfiguration can lock you out.
  • If you changed the SSH port, update your firewall: sudo ufw allow 2222/tcp && sudo ufw delete allow 22/tcp
  • Consider installing fail2ban to automatically block IPs with repeated failed login attempts: sudo apt-get install fail2ban

Switch Between Multiple PHP Versions on Ubuntu

When multiple PHP versions are installed on Ubuntu (via the Ondrej PPA), you can switch the default version for Apache and the CLI using a2dismod/a2enmod and update-alternatives.

Prerequisites

  • Multiple PHP versions installed (e.g., PHP 5.6 and PHP 7.2)
  • Root or sudo access

Steps

Switch Apache from PHP 5.6 to PHP 7.2

sudo a2dismod php5.6
sudo a2enmod php7.2
sudo systemctl restart apache2

Switch CLI from PHP 5.6 to PHP 7.2

sudo update-alternatives --set php /usr/bin/php7.2
sudo update-alternatives --set phar /usr/bin/phar7.2
sudo update-alternatives --set phar.phar /usr/bin/phar.phar7.2

Switch Apache from PHP 7.2 back to PHP 5.6

sudo a2dismod php7.2
sudo a2enmod php5.6
sudo systemctl restart apache2

Switch CLI from PHP 7.2 back to PHP 5.6

sudo update-alternatives --set php /usr/bin/php5.6

Interactive version selection

sudo update-alternatives --config php

Choose from the numbered list of installed versions.

Verify

# Check CLI version
php -v

# Check Apache version via a test page
echo "<?php echo PHP_VERSION; ?>" | sudo tee /var/www/html/ver.php
curl http://localhost/ver.php
sudo rm /var/www/html/ver.php

Notes

  • Only one PHP version module can be active in Apache at a time.
  • If using PHP-FPM, switch the FPM pool: sudo systemctl stop php5.6-fpm && sudo systemctl start php7.2-fpm
  • List all available PHP alternatives: update-alternatives --list php

Fix Can't SSH into AWS EC2 After Enabling Firewall

Enabling ufw on an AWS EC2 instance without first allowing SSH traffic will immediately lock you out of the server. This guide explains how to prevent this and recover if it happens.

The Problem

Running sudo ufw enable without adding an SSH allow rule first blocks port 22, cutting off your SSH session. AWS EC2 security groups alone are not sufficient — the OS-level firewall also applies.

Prevention: The Correct Order

1. Allow SSH before enabling ufw

sudo ufw allow 22/tcp
sudo ufw allow OpenSSH
sudo ufw enable

2. Verify the rule is in place before enabling

sudo ufw status numbered

Confirm port 22 appears in the rules list before proceeding.

Recovery: If You Are Already Locked Out

Option 1: Use the AWS EC2 Serial Console (if enabled)

  1. In the AWS Console, go to EC2 > Instances > select your instance
  2. Click Actions > Monitor and troubleshoot > EC2 Serial Console
  3. Log in and run: sudo ufw disable or sudo ufw allow 22/tcp

Option 2: Stop the instance and edit user data

  1. Stop the instance (do not terminate)
  2. Detach the root volume and attach it to another instance as a secondary volume
  3. Mount it, chroot in, and run: sudo ufw disable
  4. Re-attach and restart the original instance

Option 3: AWS Systems Manager Session Manager

If the SSM agent is installed and the instance has the appropriate IAM role, you can connect without SSH:

aws ssm start-session --target instance-id

Then disable ufw or add the SSH rule.

Verify

sudo ufw status verbose

Confirm port 22 is allowed before testing SSH from a new terminal.

Notes

  • AWS EC2 security groups and OS-level firewalls (ufw, iptables, firewalld) are independent layers. Both must allow the traffic.
  • For ufw, also allow your passive FTP port range, HTTP (80), and HTTPS (443) as needed.
  • Consider using AWS Session Manager as a backup access method regardless of firewall state.

Configure vsftpd on CentOS 7

This guide covers installing and configuring vsftpd on CentOS 7 with SSL/TLS enabled for encrypted FTP transfers.

Prerequisites

  • CentOS 7 with root or sudo access
  • Firewall open for FTP ports 20, 21, and the passive port range

Steps

1. Install vsftpd

sudo yum install vsftpd -y
sudo systemctl start vsftpd
sudo systemctl enable vsftpd

2. Generate a self-signed SSL certificate

sudo mkdir -p /etc/ssl/private
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout /etc/ssl/private/vsftpd.pem   -out /etc/ssl/private/vsftpd.pem

3. Configure vsftpd with SSL

sudo nano /etc/vsftpd/vsftpd.conf
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
listen=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

# SSL settings
ssl_enable=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
require_ssl_reuse=NO
ssl_ciphers=HIGH

# Passive mode settings
pasv_min_port=13000
pasv_max_port=13100
port_enable=YES
# Replace with your server's public IP
pasv_address=203.0.113.10
pasv_addr_resolve=YES

4. Manage allowed and denied users

# Add allowed users (whitelist mode)
echo "ftpuser" | sudo tee -a /etc/vsftpd/user_list

# Users in /etc/vsftpd/ftpusers are always denied
# (system accounts like root are listed here by default)

5. Open firewall ports

sudo firewall-cmd --permanent --add-port=21/tcp
sudo firewall-cmd --permanent --add-port=20/tcp
sudo firewall-cmd --permanent --add-port=13000-13100/tcp
sudo firewall-cmd --reload

6. Restart vsftpd

sudo systemctl restart vsftpd

Verify

sudo systemctl status vsftpd
# Test connection with an FTP client using explicit TLS/SSL

Notes

  • Use FileZilla with "Require explicit FTP over TLS" mode to connect with SSL.
  • Check SELinux if connections are refused: sudo setsebool -P ftpd_full_access 1
  • Logs are at /var/log/vsftpd.log.

Configure SFTP Access for Web Server Document Root

SFTP (SSH File Transfer Protocol) provides a secure alternative to FTP. This guide configures SFTP access to a web server's document root, with the SFTP user chrooted for security and unable to access an interactive shell.

Prerequisites

  • OpenSSH server installed
  • Root or sudo access

Scenario 1: Single SFTP User

1. Create the SFTP user

sudo adduser sftpuser
sudo passwd sftpuser

2. Set chroot directory ownership (must be owned by root)

sudo chown root:root /var/www
sudo mkdir -p /var/www/html
sudo chown sftpuser:sftpuser /var/www/html

3. Configure SSH for SFTP-only chroot access

sudo nano /etc/ssh/sshd_config

Add at the end of the file:

Match User sftpuser
    ChrootDirectory /var/www
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

4. Restart SSH

sudo systemctl restart sshd

Scenario 2: Multiple SFTP Users Sharing the Document Root

1. Create a shared group

sudo groupadd webdevelopers

2. Add users to the group

sudo usermod -aG webdevelopers dev1
sudo usermod -aG webdevelopers dev2

3. Set group ownership on the document root

sudo chgrp -R webdevelopers /var/www/html
sudo chmod -R 2775 /var/www/html

The 2 (setgid) ensures new files inherit the group ownership.

4. Configure SSH for the group

sudo nano /etc/ssh/sshd_config
Match Group webdevelopers
    ChrootDirectory /var/www
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

5. Restart SSH

sudo systemctl restart sshd

Verify

sftp sftpuser@your-server-ip

The user should be able to upload files but should not be able to run interactive shell commands.

Notes

  • The ChrootDirectory must be owned by root and not writable by any other user — this is an OpenSSH requirement.
  • www-data (Apache's user) also needs read access to the document root. Adjust group membership accordingly.

Fix Server Permissions After Accidental chown -R /

Running chown -R someuser: / recursively changes ownership of all files on the system, breaking sudo, SSH, and many services. This guide restores correct ownership and permissions on Ubuntu 16.04.

Prerequisites

  • You still have an active root session (or access via rescue mode)
  • The system is Ubuntu 16.04 (Xenial) — adjust paths for other distributions

Steps

1. Restore root ownership of all system files

cd /
chown -R root: .

2. Fix /var directory ownership

cd /var
chown -R root:syslog log
chown -R root:staff local

3. Fix /etc directory ownership

cd /etc
chown root:daemon at.deny
chown root:shadow gshadow gshadow-
chown -R root:landscape landscape
chown root:shadow shadow shadow-

4. Restore home directory ownership

chown -R ubuntu: /home/ubuntu

5. Restore web root ownership

chown -R www-data: /var/www/html

6. Fix sudo permissions (critical)

chown -R root:root /usr/bin/sudo
chmod u+s /usr/bin/sudo
chown -R root:root /usr/lib/sudo/sudoers.so
chmod a=rx,u+s /usr/lib/sudo/sudoers.so

7. Fix PHP session directory

chown -R ubuntu:www-data /var/lib/php/sessions

8. Fix grub scripts (make executable)

chmod a+x /etc/grub.d/*

9. Reboot to verify

reboot

Verify

# Test sudo works
sudo whoami

# Test SSH login as a non-root user
ssh ubuntu@localhost

Notes

  • This fix is specific to Ubuntu 16.04. Other distributions have different expected ownerships — consult the distribution's package database or a fresh install for reference.
  • To prevent this in the future, use chown -R user: /specific/path rather than starting from /.
  • For a comprehensive fix, compare ownership with a fresh installation using dpkg --verify on Debian/Ubuntu.

Mount DigitalOcean Spaces as a Folder with s3fs

DigitalOcean Spaces is an S3-compatible object storage service. Using s3fs, you can mount a Spaces bucket as a local directory on your server, enabling direct file access.

Prerequisites

  • A DigitalOcean Spaces bucket created
  • Spaces access key and secret key
  • s3fs installed on the server

Steps

1. Install s3fs

# Ubuntu/Debian
sudo apt-get install s3fs

# CentOS/RHEL
sudo yum install epel-release && sudo yum install s3fs-fuse

2. Create the credentials file

echo "YOUR_ACCESS_KEY:YOUR_SECRET_KEY" > ~/.passwd-s3fs
chmod 600 ~/.passwd-s3fs

3. Create a mount point

sudo mkdir /mnt/spaces

4. Mount the Spaces bucket

s3fs your-bucket-name /mnt/spaces   -o url=https://sgp1.digitaloceanspaces.com   -o use_cache=/tmp   -o allow_other   -o use_path_request_style   -o uid=0   -o gid=0

Replace sgp1 with your Spaces region (e.g., nyc3, ams3, fra1).

5. Mount automatically on boot

Add to /etc/fstab:

s3fs#your-bucket-name /mnt/spaces fuse   _netdev,allow_other,use_cache=/tmp,url=https://sgp1.digitaloceanspaces.com,  use_path_request_style,passwd_file=/root/.passwd-s3fs 0 0

Verify

df -h | grep s3fs
ls /mnt/spaces

Notes

  • Do not store real credentials in configuration examples. Rotate your access keys if they were ever committed to version control.
  • s3fs performance is limited by network latency — it is not suitable as a replacement for local storage in I/O-intensive workloads.
  • For better performance, use the DigitalOcean Spaces API or rclone for bulk transfers instead of s3fs.

Allow Multiple Developers SFTP Access to Web Root

When multiple developers need FTP/SFTP write access to a shared web directory, the cleanest approach is to create a shared group, assign the web root to that group, and set the setgid bit so all new files inherit the group. This avoids permission conflicts between developers and the web server.

Prerequisites

  • Linux server with root access
  • Developer user accounts already created
  • Web root directory (e.g., /var/www/vhosts/example.com)

Steps

1. Create a shared group for the project

sudo groupadd exampleadmins

2. Add developers to the group

sudo usermod -aG exampleadmins dev01
sudo usermod -aG exampleadmins dev02
sudo usermod -aG exampleadmins dev03

3. Add the web server user to the group

sudo usermod -aG exampleadmins www-data    # Ubuntu/Debian
sudo usermod -aG exampleadmins apache       # CentOS/RHEL

4. Change group ownership of the web root

sudo chgrp -R exampleadmins /var/www/vhosts/example.com

5. Set permissions with the setgid bit

sudo chmod -R 2775 /var/www/vhosts/example.com

The 2 (setgid) ensures all new files and directories created inside inherit the group. 775 gives owner and group full access, others read+execute.

6. Verify the setgid is applied

ls -la /var/www/vhosts/example.com

You should see drwxrwsr-x — the s in group execute position indicates setgid.

Verify

# Switch to a developer account and create a test file
su - dev01
touch /var/www/vhosts/example.com/testfile
ls -la /var/www/vhosts/example.com/testfile

The test file should show exampleadmins as the group owner.

Notes

  • Create a backup of current permissions before making changes: sudo getfacl -R /var/www/vhosts/example.com > /tmp/permissions-backup.txt
  • For SFTP-only access (no shell), combine this with the SFTP chroot configuration (see the companion SFTP guide).
  • The web server process must be a member of the shared group to read newly uploaded files.