Developing a Reusable and Readable Bash Script for Automated LAMP Stack Deployment
Tags: devops, cloud, automation
Published: 2024-04-22 18:42:26


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kydinpeapmt32njwie5.png)Automating the deployment of a LAMP (Linux, Apache, MySQL, PHP) stack is a crucial task for any system administrator or DevOps engineer. In this guide, we'll walk through the creation of a powerful Bash script that automates the entire deployment process, from cloning a PHP application from GitHub to configuring Apache web server and MySQL. Our goal is to ensure ease of maintenance and future deployments by developing a script that is both reusable and readable.

1. Updating the System and Installing Apache


 

```
sudo apt update -y || handle_error "Failed to update the system."
sudo apt install apache2 -y || handle_error "Failed to install Apache web server."
```

We begin by updating the Linux system and installing the Apache web server. The -y flag is used to automatically confirm any prompts during the installation process.

2. Adding PHP Repository and Installing PHP

```

sudo add-apt-repository ppa:ondrej/php --yes || handle_error "Failed to add PHP repository."
sudo apt update -y || handle_error "Failed to update repository."
sudo apt install php8.2 php8.2-curl php8.2-dom php8.2-mbstring php8.2-xml php8.2-mysql zip unzip -y || handle_error "Failed to install PHP and extensions."
```
We add the PHP repository maintained by Ondřej Surý and install PHP 8.2 along with necessary extensions required for our LAMP stack.

3. Enabling Apache Modules and Restarting Apache

```
sudo a2enmod rewrite || handle_error "Failed to enable rewrite module for Apache."
sudo systemctl restart apache2 || handle_error "Failed to restart Apache server."
```
We enable the rewrite module for Apache to allow for clean URL configuration and then restart the Apache server to apply the changes.

4. Installing Composer Globally

```
sudo curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer || handle_error "Failed to install Composer globally."
```

Composer, a dependency manager for PHP, is installed globally to facilitate dependency management for our PHP applications.

5. Cloning Laravel Application from GitHub

```
cd /var/www/ || handle_error "Failed to change directory to /var/www/."
sudo git clone https://github.com/laravel/laravel.git laravel || handle_error "Failed to clone Laravel repository."
```

We navigate to the web root directory and clone a Laravel application from its GitHub repository.

6. Configuring Apache Virtual Host

```
sudo tee /etc/apache2/sites-available/latest.conf > /dev/null <<EOF
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot /var/www/laravel/public

    <Directory /var/www/laravel>
        AllowOverride All
    </Directory>

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




```

We configure a virtual host for our Laravel application, pointing Apache to the application's public directory and setting up error and access logs.

7. Enabling and Disabling Virtual Hosts

```
sudo a2ensite latest.conf || handle_error "Failed to enable new Virtual Host."
sudo a2dissite 000-default.conf || handle_error "Failed to disable default Virtual Host."

```

We enable the newly configured virtual host while disabling the default one to ensure our Laravel application is served correctly.

8. Installing MySQL Server and Client

```
sudo apt install mysql-server mysql-client -y || handle_error "Failed to install MySQL server and client."
sudo systemctl start mysql || handle_error "Failed to start MySQL service."


```

MySQL server and client are installed, and the MySQL service is started to set up the database management system.

9. Updating .env File with MySQL Configuration

```

sudo cp .env.example .env
sudo chown -R $USER:$USER /var/www/laravel/.env

echo "APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD= " >> /var/www/laravel/.env
```

We copy the example environment file, set appropriate ownership, and update it with MySQL configuration details.

10. Generating Laravel Application Key and Creating Symbolic Link

```
sudo php artisan key:generate || handle_error "Failed to generate application key."
sudo php artisan storage:link || handle_error "Failed to create storage symbolic link."
```

We generate a unique application key for Laravel and create a symbolic link for storage.

11. Migrating and Seeding Database

```

sudo php artisan migrate
sudo php artisan db:seed
```


Database migration and seeding are performed to set up the database schema and populate it with initial data.

12. Serving the Application

```
sudo php artisan serve
```
Finally, we serve the Laravel application using the built-in PHP development server.

Conclusion
By following this guide and developing a reusable and readable Bash script, one can automate the deployment of a LAMP stack with ease. This script ensures consistency, scalability, and ease of maintenance for future deployments. 



## **Follow-Up: Enhancing Automation with Ansible Playbooks and Cron Jobs**

In our previous blog post, we explored the development of a robust Bash script for automating the deployment of a LAMP stack. Building upon that foundation, we will now leverage Ansible playbooks and cron jobs to further enhance our automation capabilities and ensure seamless management of our server infrastructure.

1. Ansible Playbook for Deployment

Ansible provides a powerful automation framework for orchestrating configuration management tasks across multiple servers. We'll start by creating an Ansible playbook that executes our Bash script on the slave node, ensuring consistent deployment across our server infrastructure.

```
# deploy.yml

- hosts: slave
  tasks:
    - name: Transfer deployment script to slave node
      copy:
        src: /path/to/deploy.sh
        dest: /tmp/deploy.sh

    - name: Execute deployment script on slave node
      shell: /bin/bash /tmp/deploy.sh
```

Explanation:

1. hosts: Specifies the target host or group of hosts where the playbook tasks will be executed. In this case, we target the "slave" server.
2. copy: Copies the deployment script from the control node to the specified destination on the slave node.
3. shell: Executes the deployment script on the slave node using the Bash shell.

2. Cron Job for Uptime Monitoring

```
# Add the following line to the crontab file
0 0 * * * /usr/bin/uptime >> /var/log/server_uptime.log

```


Explanation:

```
0 0 * * *: Specifies the schedule for the cron job. In this case, the job runs every day at midnight (00:00).
/usr/bin/uptime: Executes the uptime command to retrieve information about the server's uptime.
>> /var/log/server_uptime.log: Appends the output of the uptime command to a log file for record-keeping and monitoring.
```

Execution and Verification
Executing Ansible Playbook:
Run the Ansible playbook (ansible-playbook deploy.yml) from the control node.
Verify successful execution by accessing the PHP application through the slave node's IP address.

Cron Job Verification:
Check the /var/log/server_uptime.log file on the slave node to ensure that uptime logs are being recorded as expected.
Tail the log file (tail -f /var/log/server_uptime.log) to monitor real-time uptime updates.

Conclusion
By incorporating Ansible playbooks and cron jobs into my automation workflow, I have further streamlined the deployment process and implemented proactive monitoring for server uptime. These tools enable one

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzn4l0uk8f3rdewkotfl.png) to maintain a reliable and efficient server infrastructure while reducing manual intervention.