<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blog.adityajaishi.com.np</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 18:24:50 GMT</lastBuildDate><atom:link href="https://blog.adityajaishi.com.np/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[devops]]></title><description><![CDATA[Intuji - DevOps Final Assignmment
As part of my final assignment . I have prepared documentation of how i complete this task ste by step.

Building a Fully Containerized Full Stack Application with CI/CD, Monitoring, and Log Management
In this post, ...]]></description><link>https://blog.adityajaishi.com.np/devops</link><guid isPermaLink="true">https://blog.adityajaishi.com.np/devops</guid><dc:creator><![CDATA[Aditya Jaishi]]></dc:creator><pubDate>Fri, 25 Oct 2024 09:18:27 GMT</pubDate><content:encoded><![CDATA[<p><strong>Intuji - DevOps Final Assignmment</strong></p>
<p>As part of my final assignment . I have prepared documentation of how i complete this task ste by step.</p>
<hr />
<h3 id="heading-building-a-fully-containerized-full-stack-application-with-cicd-monitoring-and-log-management"><strong>Building a Fully Containerized Full Stack Application with CI/CD, Monitoring, and Log Management</strong></h3>
<p>In this post, I will share my journey of developing a fully containerized full stack application using React for the frontend, Node.js for the backend, and MySQL for the primary database and replica databse. I integrated a CI/CD pipeline with Jenkins, set up monitoring using Grafana, and managed logs with the ELK/EFK stack. Let’s dive into the process step by step.</p>
<hr />
<h3 id="heading-1-setting-up-the-environment"><strong>1. Setting Up the Environment</strong></h3>
<p>To get started, I ensured that I had the necessary tools installed on my machine:</p>
<ul>
<li><p><strong>Docker</strong>: To run and manage all components in containers.</p>
</li>
<li><p><strong>Docker Compose</strong>: To simplify the orchestration of multi-container applications.</p>
</li>
<li><p><strong>React</strong>: For building the user interface.</p>
</li>
<li><p><strong>Node.js</strong>: For handling server-side logic.</p>
</li>
<li><p><strong>MySQL</strong>: As the primary database and Replica Database</p>
</li>
<li><p><strong>Jenkins</strong>: For automating the deployment pipeline.</p>
</li>
<li><p><strong>Grafana</strong>: For monitoring application performance.</p>
</li>
<li><p><strong>ELK/EFK Stack</strong>: For centralized logging and analytics.</p>
</li>
</ul>
<hr />
<h3 id="heading-2-frontend-react-in-a-container"><strong>2. Frontend (React) in a Container</strong></h3>
<p>I started by creating a React application that would serve as the frontend interface.</p>
<h4 id="heading-step-1-create-a-react-app"><strong>Step 1: Create a React App</strong></h4>
<p>Using create-react-app, I set up my frontend project:</p>
<pre><code class="lang-bash">npx create-react-app frontend
<span class="hljs-built_in">cd</span> frontend
</code></pre>
<h4 id="heading-step-2-configure-environment-variables">Step 2: Configure Environment Variables</h4>
<p>To keep sensitive information organized, I created a <code>.env</code> file in the React project to store the backend API URL:</p>
<pre><code class="lang-bash">REACT_APP_API_URL=<span class="hljs-string">'http://52.202.190.246:3005'</span>
</code></pre>
<h4 id="heading-step-3-dockerize-the-react-app"><strong>Step 3: Dockerize the React App</strong></h4>
<p>I created a Dockerfile for the frontend to containerize the application:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Step 1: Use Node.js image to build the project</span>
FROM node:14-alpine AS build-stage

<span class="hljs-comment"># Set the working directory inside the container</span>
WORKDIR /app

<span class="hljs-comment"># Copy the package.json and package-lock.json</span>
COPY package*.json ./

<span class="hljs-comment"># Install the project dependencies</span>
RUN npm install

<span class="hljs-comment"># Copy the rest of the application source code</span>
COPY . .

<span class="hljs-comment"># Build the application (assuming this creates a 'build' folder)</span>
RUN npm run build

<span class="hljs-comment"># Step 2: Use Nginx to serve the build files</span>
FROM nginx:alpine AS production-stage

<span class="hljs-comment"># Copy the build output from the previous stage to Nginx's html directory</span>
COPY --from=build-stage /app/build /usr/share/nginx/html

<span class="hljs-comment"># Expose port 80</span>
EXPOSE 80
<span class="hljs-comment"># Command to run Nginx in the foreground</span>
CMD [<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>]
</code></pre>
<p>here is my src/App.js file for react frontend</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./styles.css'</span>; <span class="hljs-comment">// Assuming styles.css is in the same folder</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);
    <span class="hljs-keyword">const</span> [errorMessage, setErrorMessage] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [successMessage, setSuccessMessage] = useState(<span class="hljs-string">''</span>);

    <span class="hljs-comment">// Load users from the backend using Axios</span>
    <span class="hljs-keyword">const</span> loadUsers = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">`<span class="hljs-subst">${process.env.REACT_APP_API_URL}</span>/data`</span>);
            setUsers(response.data);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error loading users:'</span>, error);
            setErrorMessage(<span class="hljs-string">'Error loading users. Please try again.'</span>);
        }
    };

    <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
        e.preventDefault();
        setErrorMessage(<span class="hljs-string">''</span>); <span class="hljs-comment">// Clear previous error message</span>
        setSuccessMessage(<span class="hljs-string">''</span>); <span class="hljs-comment">// Clear previous success message</span>

        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Send data to the backend to save it in the database</span>
            <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${process.env.REACT_APP_API_URL}</span>/submit`</span>, {
                name,
                email,
            });

            <span class="hljs-comment">// Clear input fields after successful submission</span>
            setName(<span class="hljs-string">''</span>);
            setEmail(<span class="hljs-string">''</span>);
            setSuccessMessage(<span class="hljs-string">'User registered successfully!!'</span>);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error submitting form:'</span>, error);
            setErrorMessage(<span class="hljs-string">'Error submitting form. Please try again!!.'</span>);
        }
    };

    <span class="hljs-comment">// Handle fetching and displaying the data when clicking "Read Data" button</span>
    <span class="hljs-keyword">const</span> handleReadData = <span class="hljs-function">() =&gt;</span> {
        loadUsers();
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Registration Form<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>&gt;</span>Name:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setName(e.target.value)}
                    required
                /&gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEmail(e.target.value)}
                    required
                /&gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

            {/* Display success or error messages */}
            {successMessage &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"success-message"</span>&gt;</span>{successMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
            {errorMessage &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"error-message"</span>&gt;</span>{errorMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}

            {/* Button to read data */}
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleReadData}</span>&gt;</span>Read Data<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Registered Users<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dataTable"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                    {users.length &gt; 0 ? (
                        users.map((user, index) =&gt; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{user.email}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                        ))
                    ) : (
                        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">colSpan</span>=<span class="hljs-string">"2"</span>&gt;</span>No registered users yet.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                    )}
                <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#4A90E2</span>;
}

<span class="hljs-selector-tag">form</span> {
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span>,
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"email"</span>]</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#4A90E2</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#357ABD</span>;
}

<span class="hljs-selector-tag">table</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">border-collapse</span>: collapse;
}

<span class="hljs-selector-tag">th</span>, <span class="hljs-selector-tag">td</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
    <span class="hljs-attribute">text-align</span>: left;
    <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
}

<span class="hljs-selector-tag">th</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#4A90E2</span>;
    <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-selector-tag">tr</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f1f1f1</span>;
}
</code></pre>
<h3 id="heading-3-backend-nodejs-in-a-container"><strong>3. Backend (Node.js) in a Container</strong></h3>
<p>Next, I set up the backend using Node.js to process requests and handle business logic.</p>
<h4 id="heading-step-1-create-a-nodejs-app"><strong>Step 1: Create a Node.js App</strong></h4>
<p>In a separate directory, I initialized the backend project</p>
<pre><code class="lang-bash">mkdir backend
<span class="hljs-built_in">cd</span> backend
npm init -y
npm install express mysql dotenv cores axios winston
</code></pre>
<h4 id="heading-step-2-set-up-api-routes-and-database-connection">Step 2: Set Up API Routes and Database Connection</h4>
<p>I configured the server in <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mysql2/promise'</span>);
<span class="hljs-keyword">const</span> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">'body-parser'</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);
<span class="hljs-keyword">const</span> client = <span class="hljs-built_in">require</span>(<span class="hljs-string">'prom-client'</span>);
<span class="hljs-keyword">const</span> winston = <span class="hljs-built_in">require</span>(<span class="hljs-string">'winston'</span>); <span class="hljs-comment">// Import winston for logging</span>

<span class="hljs-comment">// Configure the logger</span>
<span class="hljs-keyword">const</span> logger = winston.createLogger({
    <span class="hljs-attr">level</span>: <span class="hljs-string">'info'</span>,
    <span class="hljs-attr">format</span>: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    <span class="hljs-attr">transports</span>: [
        <span class="hljs-keyword">new</span> winston.transports.File({ <span class="hljs-attr">filename</span>: <span class="hljs-string">'app.log'</span> }), <span class="hljs-comment">// Log to file</span>
        <span class="hljs-keyword">new</span> winston.transports.Console(), <span class="hljs-comment">// Log to console</span>
    ],
});

<span class="hljs-keyword">const</span> dbHostPrimary = process.env.DB_HOST; <span class="hljs-comment">// Primary DB host</span>
<span class="hljs-keyword">const</span> dbHostReplica = process.env.DB_REPLICA_HOST; <span class="hljs-comment">// Replica DB host (Add this to your .env)</span>
<span class="hljs-keyword">const</span> dbUser = process.env.DB_USER;
<span class="hljs-keyword">const</span> dbPassword = process.env.DB_PASSWORD;
<span class="hljs-keyword">const</span> dbName = process.env.DB_NAME;

<span class="hljs-keyword">const</span> app = express();
app.use(cors());
app.use(bodyParser.json());

<span class="hljs-comment">// Prometheus metrics setup</span>
<span class="hljs-keyword">const</span> register = <span class="hljs-keyword">new</span> client.Registry();
<span class="hljs-keyword">const</span> httpRequestDurationMicroseconds = <span class="hljs-keyword">new</span> client.Histogram({
    <span class="hljs-attr">name</span>: <span class="hljs-string">'http_request_duration_seconds'</span>,
    <span class="hljs-attr">help</span>: <span class="hljs-string">'Duration of HTTP requests in seconds'</span>,
    <span class="hljs-attr">labelNames</span>: [<span class="hljs-string">'method'</span>, <span class="hljs-string">'route'</span>, <span class="hljs-string">'code'</span>],
    <span class="hljs-attr">registers</span>: [register],
});

<span class="hljs-comment">// Middleware to record request duration</span>
app.use(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> end = httpRequestDurationMicroseconds.startTimer();
    res.on(<span class="hljs-string">'finish'</span>, <span class="hljs-function">() =&gt;</span> {
        end({ <span class="hljs-attr">method</span>: req.method, <span class="hljs-attr">route</span>: req.route ? req.route.path : req.path, <span class="hljs-attr">code</span>: res.statusCode });
    });
    next();
});

<span class="hljs-comment">// Endpoint to expose metrics</span>
app.get(<span class="hljs-string">'/metrics'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    res.set(<span class="hljs-string">'Content-Type'</span>, register.contentType);
    res.end(<span class="hljs-keyword">await</span> register.metrics());
});

<span class="hljs-keyword">let</span> primaryPool; <span class="hljs-comment">// Declare primary pool variable</span>
<span class="hljs-keyword">let</span> replicaPool; <span class="hljs-comment">// Declare replica pool variable</span>

<span class="hljs-comment">// Check if the database exists and create it if it doesn't</span>
<span class="hljs-keyword">const</span> checkAndCreateDatabase = <span class="hljs-keyword">async</span> (dbName) =&gt; {
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> mysql.createConnection({
        <span class="hljs-attr">host</span>: dbHostPrimary,
        <span class="hljs-attr">user</span>: dbUser,
        <span class="hljs-attr">password</span>: dbPassword,
    });

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> [rows] = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">'SHOW DATABASES LIKE ?'</span>, [dbName]);
        <span class="hljs-keyword">if</span> (rows.length === <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">`CREATE DATABASE <span class="hljs-subst">${dbName}</span>`</span>);
            logger.info(<span class="hljs-string">`Database '<span class="hljs-subst">${dbName}</span>' created.`</span>); <span class="hljs-comment">// Log database creation</span>
        } <span class="hljs-keyword">else</span> {
            logger.info(<span class="hljs-string">`Database '<span class="hljs-subst">${dbName}</span>' already exists.`</span>); <span class="hljs-comment">// Log existence</span>
        }
    } <span class="hljs-keyword">catch</span> (error) {
        logger.error(<span class="hljs-string">'Error checking or creating database:'</span>, error); <span class="hljs-comment">// Log error</span>
    } <span class="hljs-keyword">finally</span> {
        connection.end();
    }
};

<span class="hljs-comment">// Create users table if it does not exist</span>
<span class="hljs-keyword">const</span> createUsersTable = <span class="hljs-keyword">async</span> (dbName) =&gt; {
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> primaryPool.getConnection();
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">`CREATE TABLE IF NOT EXISTS <span class="hljs-subst">${dbName}</span>.users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            email VARCHAR(100) NOT NULL UNIQUE
        );`</span>);
        logger.info(<span class="hljs-string">'Users table created or already exists.'</span>); <span class="hljs-comment">// Log users table creation</span>
    } <span class="hljs-keyword">catch</span> (err) {
        logger.error(<span class="hljs-string">'Error creating users table:'</span>, err.message); <span class="hljs-comment">// Log error</span>
    } <span class="hljs-keyword">finally</span> {
        connection.release();
    }
};

<span class="hljs-keyword">const</span> initDatabase = <span class="hljs-keyword">async</span> (dbName) =&gt; {
    <span class="hljs-keyword">await</span> checkAndCreateDatabase(dbName);
    <span class="hljs-keyword">await</span> createUsersTable(dbName);
};

<span class="hljs-comment">// Start the Express server and initialize the database</span>
<span class="hljs-keyword">const</span> startServer = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> DB_NAME = <span class="hljs-string">'aditya'</span>; <span class="hljs-comment">// Specify your database name</span>
    <span class="hljs-keyword">await</span> checkAndCreateDatabase(DB_NAME); <span class="hljs-comment">// Check and create database first</span>

    <span class="hljs-comment">// Create the connection pools after ensuring the database exists</span>
    primaryPool = mysql.createPool({
        <span class="hljs-attr">host</span>: dbHostPrimary,
        <span class="hljs-attr">user</span>: dbUser,
        <span class="hljs-attr">password</span>: dbPassword,
        <span class="hljs-attr">database</span>: DB_NAME,
        <span class="hljs-attr">waitForConnections</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">connectionLimit</span>: <span class="hljs-number">10</span>,
        <span class="hljs-attr">queueLimit</span>: <span class="hljs-number">0</span>,
    });

    replicaPool = mysql.createPool({
        <span class="hljs-attr">host</span>: dbHostReplica, <span class="hljs-comment">// Use the replica host</span>
        <span class="hljs-attr">user</span>: dbUser,
        <span class="hljs-attr">password</span>: dbPassword,
        <span class="hljs-attr">database</span>: DB_NAME,
        <span class="hljs-attr">waitForConnections</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">connectionLimit</span>: <span class="hljs-number">10</span>,
        <span class="hljs-attr">queueLimit</span>: <span class="hljs-number">0</span>,
    });

    <span class="hljs-keyword">await</span> createUsersTable(DB_NAME); <span class="hljs-comment">// Create the users table</span>

    <span class="hljs-keyword">const</span> PORT = <span class="hljs-number">3001</span>;
    app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
        logger.info(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${PORT}</span>`</span>); <span class="hljs-comment">// Log server start</span>
    });
};

<span class="hljs-comment">// Endpoint to submit data to the primary database</span>
app.post(<span class="hljs-string">'/submit'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> { name, email } = req.body;
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> primaryPool.getConnection(); <span class="hljs-comment">// Use primary pool</span>
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">'INSERT INTO users (name, email) VALUES (?, ?)'</span>, [name, email]);
        logger.info(<span class="hljs-string">'Inserted user:'</span>, result[<span class="hljs-number">0</span>].insertId); <span class="hljs-comment">// Log user insertion</span>
        res.status(<span class="hljs-number">201</span>).json({ <span class="hljs-attr">id</span>: result[<span class="hljs-number">0</span>].insertId, name, email });
    } <span class="hljs-keyword">catch</span> (error) {
        logger.error(<span class="hljs-string">'Error submitting user:'</span>, error); <span class="hljs-comment">// Log error</span>
        res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Internal Server Error'</span> });
    } <span class="hljs-keyword">finally</span> {
        connection.release();
    }
});

<span class="hljs-comment">// Endpoint to get users from the replica database</span>
app.get(<span class="hljs-string">'/data'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> replicaPool.getConnection(); <span class="hljs-comment">// Use replica pool</span>
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> [rows] = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">'SELECT * FROM users'</span>);
        res.json(rows);
    } <span class="hljs-keyword">catch</span> (err) {
        logger.error(<span class="hljs-string">'Error fetching users:'</span>, err); <span class="hljs-comment">// Log error</span>
        res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Error fetching users'</span>);
    } <span class="hljs-keyword">finally</span> {
        connection.release();
    }
});

<span class="hljs-comment">// Start the server</span>
startServer();
</code></pre>
<h4 id="heading-step-3-configure-environment-variables">Step 3: Configure Environment Variables</h4>
<p>In the backend directory, I created a <code>.env</code> file:</p>
<pre><code class="lang-bash">DB_HOST=db_container
DB_USER=root
DB_PASSWORD=Aditya123!
DB_NAME=aditya
MYSQL_ROOT_PASSWORD=Aditya123!
MYSQL_DATABASE=aditya
DB_REPLICA_HOST=db_replica
</code></pre>
<h4 id="heading-step-4-dockerize-the-backend">Step 4: Dockerize the Backend</h4>
<p>I created a <code>Dockerfile</code> for the backend:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Use Node.js as the base image</span>
FROM node:18

<span class="hljs-comment"># Install MySQL client</span>
RUN apt-get update &amp;&amp; \
    apt-get install -y default-mysql-client netcat-openbsd &amp;&amp; \
    rm -rf /var/lib/apt/lists/*

<span class="hljs-comment"># Create a directory for the backend</span>
RUN mkdir -p /backend

<span class="hljs-comment"># Set the working directory inside the container</span>
WORKDIR /backend

<span class="hljs-comment"># Copy package.json and package-lock.json to the working directory</span>
COPY package*.json ./

<span class="hljs-comment"># Install all dependencies listed in package.json</span>
RUN npm install cors express mysql2 dotenv axios winston

<span class="hljs-comment"># Copy the rest of the application code</span>
COPY . .

<span class="hljs-comment"># Add a script to wait for the database to be ready</span>
<span class="hljs-comment">#COPY wait-for-it.sh ./</span>
<span class="hljs-comment">#RUN chmod +x wait-for-it.sh</span>

<span class="hljs-comment"># Expose the backend port</span>
EXPOSE 3001

<span class="hljs-comment"># Start the application, ensuring it waits for both databases</span>
CMD [<span class="hljs-string">"node"</span>, <span class="hljs-string">"server.js"</span>]
</code></pre>
<h3 id="heading-4-database-mysql-in-a-container">4. Database (MySQL) in a Container</h3>
<p>For data management, I set up MySQL in a container.</p>
<h4 id="heading-step-1-run-mysql-in-docker">Step 1: Run MySQL in Docker</h4>
<p>In the <code>docker-compose.yml</code> file, I added a MySQL service. I have also provided full compose file below.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">db_container:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">database</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">${MYSQL_ROOT_PASSWORD}</span>
      <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">${MYSQL_DATABASE}</span>
      <span class="hljs-attr">MYSQL_SERVER_ID:</span> <span class="hljs-number">1</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql_data:/var/lib/mysql</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>
    <span class="hljs-attr">healthcheck:</span>
      <span class="hljs-attr">test:</span> [<span class="hljs-string">"CMD"</span>, <span class="hljs-string">"mysqladmin"</span>, <span class="hljs-string">"ping"</span>, <span class="hljs-string">"-h"</span>, <span class="hljs-string">"localhost"</span>]
      <span class="hljs-attr">interval:</span> <span class="hljs-string">10s</span>
      <span class="hljs-attr">timeout:</span> <span class="hljs-string">5s</span>
      <span class="hljs-attr">retries:</span> <span class="hljs-number">5</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">--server-id=1</span> <span class="hljs-string">--log-bin=mysql-bin</span>
    <span class="hljs-attr">logging:</span>
      <span class="hljs-attr">driver:</span> <span class="hljs-string">"json-file"</span>
      <span class="hljs-attr">options:</span>
        <span class="hljs-attr">max-size:</span> <span class="hljs-string">"10m"</span>
        <span class="hljs-attr">max-file:</span> <span class="hljs-string">"3"</span>
</code></pre>
<p>I also configured a replica database for redundancy:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">db_replica:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">database_replica</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">${MYSQL_ROOT_PASSWORD}</span>
      <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">${MYSQL_DATABASE}</span>
      <span class="hljs-attr">MYSQL_SERVER_ID:</span> <span class="hljs-number">2</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql_replica_data:/var/lib/mysql</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>
    <span class="hljs-attr">healthcheck:</span>
      <span class="hljs-attr">test:</span> [<span class="hljs-string">"CMD"</span>, <span class="hljs-string">"mysqladmin"</span>, <span class="hljs-string">"ping"</span>, <span class="hljs-string">"-h"</span>, <span class="hljs-string">"localhost"</span>]
      <span class="hljs-attr">interval:</span> <span class="hljs-string">10s</span>
      <span class="hljs-attr">timeout:</span> <span class="hljs-string">5s</span>
      <span class="hljs-attr">retries:</span> <span class="hljs-number">5</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">--server-id=2</span>
    <span class="hljs-attr">logging:</span>
      <span class="hljs-attr">driver:</span> <span class="hljs-string">"json-file"</span>
      <span class="hljs-attr">options:</span>
        <span class="hljs-attr">max-size:</span> <span class="hljs-string">"10m"</span>
        <span class="hljs-attr">max-file:</span> <span class="hljs-string">"3"</span>
</code></pre>
<p>in order to replicate from primary db to replica db</p>
<p>in primary db :</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SHOW</span> <span class="hljs-keyword">MASTER</span> <span class="hljs-keyword">STATUS</span>;
</code></pre>
<p>Note down the file and position .</p>
<p>in replica db:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">STOP</span> <span class="hljs-keyword">SLAVE</span>;
<span class="hljs-keyword">RESET</span> <span class="hljs-keyword">SLAVE</span> <span class="hljs-keyword">ALL</span>;
<span class="hljs-keyword">CHANGE</span> <span class="hljs-keyword">MASTER</span> <span class="hljs-keyword">TO</span>
  MASTER_HOST=<span class="hljs-string">'db_container'</span>,
  MASTER_USER=<span class="hljs-string">'root'</span>,
  MASTER_PASSWORD=<span class="hljs-string">'Aditya123!'</span>,
  MASTER_LOG_FILE=<span class="hljs-string">'mysql-bin.000018'</span>,
  MASTER_LOG_POS=<span class="hljs-number">1087</span>;

<span class="hljs-keyword">START</span> <span class="hljs-keyword">SLAVE</span>;
</code></pre>
<p>Now primary db and replica db are synchronized and replica db is replicated.</p>
<h3 id="heading-5-cicd-pipeline-with-jenkins">5. CI/CD Pipeline with Jenkins</h3>
<p>Next, I set up a CI/CD pipeline using Jenkins for automation.</p>
<h4 id="heading-step-1-run-jenkins-in-a-docker-container">Step 1: Run Jenkins in a Docker Container</h4>
<p>I added a Jenkins service to the <code>docker-compose.yml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jenkins:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">jenkins</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">jenkins/jenkins:lts</span>
    <span class="hljs-attr">user:</span> <span class="hljs-string">root</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8080:8080"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"50000:50000"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">jenkins_home:/var/jenkins_home</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/var/run/docker.sock:/var/run/docker.sock</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">JENKINS_ADMIN_ID:</span> <span class="hljs-string">aditya</span>
      <span class="hljs-attr">JENKINS_ADMIN_PASSWORD:</span> <span class="hljs-string">aditya</span>
    <span class="hljs-attr">privileged:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">backend</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">frontend</span>
    <span class="hljs-attr">logging:</span>
      <span class="hljs-attr">driver:</span> <span class="hljs-string">"json-file"</span>
      <span class="hljs-attr">options:</span>
        <span class="hljs-attr">max-size:</span> <span class="hljs-string">"10m"</span>
        <span class="hljs-attr">max-file:</span> <span class="hljs-string">"3"</span>
</code></pre>
<h4 id="heading-step-2-configure-jenkins-jobs">Step 2: Configure Jenkins Jobs</h4>
<p>In Jenkins, I created jobs for building and deploying the frontend, backend, and database. Each job is triggered on code commits.</p>
<p>After creating user and password in jenkins i have installed necessary plugins alongwith following plugins.</p>
<ul>
<li><p>Slack notification: for slack notification handling</p>
</li>
<li><p>Github Integration: For integrating with github</p>
</li>
</ul>
<p>Provide necessary credential for github:</p>
<p>As my github repo is private i have to provide PAT (personal access token) and slack token as credential in jenkins.</p>
<p>Create token in github</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729833413554/4f31b48b-32f3-4650-9332-4f0d490ebb51.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729832979139/281684bf-00b0-4b4f-8b01-ad6ac63018c1.png" alt class="image--center mx-auto" /></p>
<p>put your PAT in secret field.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729832816237/d50280f5-3f57-4250-8f42-7a61092175d7.png" alt class="image--center mx-auto" /></p>
<p>Make sure you have workspace and channel in slack</p>
<h4 id="heading-step-3-set-up-notifications">Step 3: Set Up Notifications</h4>
<p>To keep track of build status, I integrated Slack notifications for build successes and failures.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729833235564/1f3d95f1-d392-44bc-a462-00d88a7a034e.png" alt class="image--center mx-auto" /></p>
<p>Note down the APP credential</p>
<p>put your OAuth token of slack in secret field below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729832909131/562d88a7-9131-458d-b72f-d253baaf99a2.png" alt class="image--center mx-auto" /></p>
<p>Make sure you have workspace and channel in slack</p>
<p>in system- go to slack configuration</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729833106111/2ccf644e-36b5-4470-bc9e-1317cec59a0f.png" alt class="image--center mx-auto" /></p>
<p>Now create new item for cerating our pipeline</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729833792211/453bdf8a-51c0-403f-917d-d42f94fdeb7a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729833852817/52813b03-1b91-40b9-ac9e-b185be30c56e.png" alt class="image--center mx-auto" /></p>
<p>Added following code to setup stage in pipeline</p>
<pre><code class="lang-java">pipeline {
    agent any  <span class="hljs-comment">// This will run on any available agent</span>

    environment {
        GITHUB_CREDENTIALS = credentials(<span class="hljs-string">'github-pat'</span>)  <span class="hljs-comment">// Use your GitHub credentials</span>
        SLACK_CHANNEL = <span class="hljs-string">'C07SR8XAK97'</span>  <span class="hljs-comment">// Replace with your Slack channel ID</span>
        SLACK_CREDENTIALS = credentials(<span class="hljs-string">'slack-token'</span>)  <span class="hljs-comment">// Slack credentials for notifications</span>
        <span class="hljs-comment">//EMAIL_RECIPIENTS = 'aditya.infisec@gmail.com'  // Replace with recipient emails</span>
    }

    triggers {
        <span class="hljs-comment">// This listens to the webhook</span>
        githubPush()
    }

    stages {
        stage(<span class="hljs-string">'Checkout'</span>) {
            steps {
                script {
                    withCredentials([string(credentialsId: <span class="hljs-string">'github-pat'</span>, variable: <span class="hljs-string">'GITHUB_TOKEN'</span>)]) {
                        <span class="hljs-comment">// Clone the repository using the token in the URL</span>
                        git branch: <span class="hljs-string">'main'</span>, 
                            url: <span class="hljs-string">"https://${GITHUB_TOKEN}@github.com/Adityakafle/full-stack-project.git"</span>
                    }
                }
            }
        }

        stage(<span class="hljs-string">'Install and Verify Docker'</span>) {
            steps {
                script {
                    <span class="hljs-comment">// Update, upgrade system, install Docker, start and enable Docker service, install Docker Compose, and check versions</span>
                    sh <span class="hljs-string">''</span><span class="hljs-string">'
                    apt-get update -y
                    apt-get upgrade -y
                    apt-get install -y docker.io

                    # Check Docker version
                    docker --version

                    # Install Docker Compose
                    curl -L "https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep '</span>tag_name<span class="hljs-string">' | cut -d '</span><span class="hljs-string">"' -f 4)/docker-compose-$(uname -s)-$(uname -m)"</span> -o /usr/local/bin/docker-compose
                    chmod +x /usr/local/bin/docker-compose

                    # Check Docker Compose version
                    docker-compose --version
                    <span class="hljs-string">''</span><span class="hljs-string">'
                }
            }
        }

        stage('</span>Build Database<span class="hljs-string">') {
            steps {
                script {
                    echo '</span>Starting database containers...<span class="hljs-string">'

                    // Start the database containers without dependencies
                    sh '</span>docker-compose up --build -d --no-deps db_container<span class="hljs-string">'
                    sh '</span>docker-compose up --build -d --no-deps db_replica<span class="hljs-string">'

                    // Wait for both containers to be healthy
                    waitUntil {
                        script {
                            // Check the health status of the db_container
                            def dbContainerStatus = sh(script: '</span>docker inspect -f <span class="hljs-string">"{{.State.Health.Status}}"</span> $(docker-compose ps -q db_container)<span class="hljs-string">', returnStdout: true).trim()
                            echo "db_container health status: ${dbContainerStatus}"

                            // Check the health status of the db_replica
                            def dbReplicaStatus = sh(script: '</span>docker inspect -f <span class="hljs-string">"{{.State.Health.Status}}"</span> $(docker-compose ps -q db_replica)<span class="hljs-string">', returnStdout: true).trim()
                            echo "db_replica health status: ${dbReplicaStatus}"

                            // Return true only when both containers are healthy
                            return dbContainerStatus == '</span>healthy<span class="hljs-string">' &amp;&amp; dbReplicaStatus == '</span>healthy<span class="hljs-string">'
                        }
                    }

                    echo '</span>Both db_container and db_replica are healthy!<span class="hljs-string">'
                }
            }
        }

        stage('</span>Build Backend<span class="hljs-string">') {
            steps {
                script {
                    echo '</span>Starting backend container...<span class="hljs-string">'
                    // Build and start the backend container
                    sh '</span>docker-compose up --build -d --no-deps backend<span class="hljs-string">'
                }
            }
        }

        stage('</span>Build Frontend<span class="hljs-string">') {
            steps {
                script {
                    echo '</span>Starting frontend container...<span class="hljs-string">'
                    // Build and start the frontend container
                    sh '</span>docker-compose up --build -d --no-deps frontend<span class="hljs-string">'
                }
            }
        }

        stage('</span>Test and Deploy<span class="hljs-string">') {
            steps {
                script {
                    echo '</span>Running tests...<span class="hljs-string">'
                    // Placeholder for your test command
                    // Example: sh '</span>docker-compose run --rm test_container<span class="hljs-string">'
                    echo '</span>Tests completed, deploying application...<span class="hljs-string">'
                    // Deploy commands can be added here if needed
                }
            }
        }
    }

    post {
        success {
            script {
                // Send success notification to Slack
                def message = "Deployment succeeded!"
                sh """
                    curl -X POST -H '</span>Authorization: Bearer ${SLACK_CREDENTIALS}<span class="hljs-string">' \
                    -H '</span>Content-Type: application/json; charset=utf-<span class="hljs-number">8</span><span class="hljs-string">' \
                    -d '</span>{<span class="hljs-string">"channel"</span>: <span class="hljs-string">"${SLACK_CHANNEL}"</span>, <span class="hljs-string">"text"</span>: <span class="hljs-string">"${message}"</span>}<span class="hljs-string">' \
                    https://slack.com/api/chat.postMessage
                """
            }
        }
        failure {
            script {
                // Send failure notification to Slack
                def message = "Deployment failed!"
                sh """
                    curl -X POST -H '</span>Authorization: Bearer ${SLACK_CREDENTIALS}<span class="hljs-string">' \
                    -H '</span>Content-Type: application/json; charset=utf-<span class="hljs-number">8</span><span class="hljs-string">' \
                    -d '</span>{<span class="hljs-string">"channel"</span>: <span class="hljs-string">"${SLACK_CHANNEL}"</span>, <span class="hljs-string">"text"</span>: <span class="hljs-string">"${message}"</span>}<span class="hljs-string">' \
                    https://slack.com/api/chat.postMessage
                """
            }
        }
    }
}</span>
</code></pre>
<p>Save the configuration</p>
<p>Also i have added correct payload url :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729834093594/a4ad7fc2-3828-4435-87d8-96225e5a7ab6.png" alt class="image--center mx-auto" /></p>
<p>Now , my jenkins is setup to automate my build process of three tier app. i will create 4 containers from compose file when any changes happen i.e if someone committed or pushed code.</p>
<p>if there’s no any error it will pass all the stages</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729834339781/f24285b2-5346-4bd1-a429-74d157898c2e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-6-monitoring-with-prometheus-grafana-and-cadvisor">6. Monitoring with Prometheus, Grafana, and cAdvisor</h3>
<p>For real-time monitoring and metrics collection, I integrated <strong>Prometheus</strong>, <strong>Grafana</strong>, and <strong>cAdvisor</strong>.</p>
<h4 id="heading-step-1-adding-prometheus-and-cadvisor-to-docker-compose">Step 1: Adding Prometheus and cAdvisor to Docker Compose</h4>
<p>Prometheus collects metrics from cAdvisor, which monitors container resource usage.</p>
<p>Here’s the setup for Prometheus and cAdvisor in <code>docker-compose.yml</code>:</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">cadvisor:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">gcr.io/cadvisor/cadvisor</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">cadvisor</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8082:8080"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/var/run:/var/run:ro</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/sys:/sys:ro</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/var/lib/docker:/var/lib/docker:ro</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>

  <span class="hljs-attr">prometheus:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">prom/prometheus</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">prometheus</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"9090:9090"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./prometheus.yml:/etc/prometheus/prometheus.yml</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>

  <span class="hljs-attr">grafana:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/grafana</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">grafana</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_USER=aditya</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_PASSWORD=aditya</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">grafana_data:/var/lib/grafana</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">app-network</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">prometheus</span>
</code></pre>
<p>I configured Grafana to connect with Prometheus and set up dashboards for real-time monitoring.</p>
<h3 id="heading-7-log-management-with-elkefk-stack">7. Log Management with ELK/EFK Stack</h3>
<p>For centralized logging, I used <strong>Elasticsearch</strong>, <strong>Logstash</strong>, and <strong>Kibana</strong> (ELK) to collect, process, and visualize logs.</p>
<h4 id="heading-step-1-adding-elasticsearch-and-kibana-to-docker-compose">Step 1: Adding Elasticsearch and Kibana to Docker Compose</h4>
<p>Here’s the Elasticsearch and Kibana setup:</p>
<p>Architecture</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729847821683/556be250-3ee4-40c8-9908-6e1d0531bcf7.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Monitoring Docker Logs with Grafana and Loki: Leveraging Docker Logging Driver, Alerts, and Slack Notifications]]></title><description><![CDATA[In my previous blog 👍 here i have monitored logs using promtail as agent but wait we have Loki Logging Driver which will give more option to choose container name and watch logs of it Lets go through this.
I have made few changes here as i don’t use...]]></description><link>https://blog.adityajaishi.com.np/monitoring-docker-logs-with-grafana-and-loki-leveraging-docker-logging-driver-alerts-and-slack-notifications</link><guid isPermaLink="true">https://blog.adityajaishi.com.np/monitoring-docker-logs-with-grafana-and-loki-leveraging-docker-logging-driver-alerts-and-slack-notifications</guid><category><![CDATA[Devops]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[SRE]]></category><category><![CDATA[SRE devops]]></category><dc:creator><![CDATA[Aditya Jaishi]]></dc:creator><pubDate>Thu, 03 Oct 2024 08:42:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727944895175/de8cf21f-51ec-4f03-82d2-95b7a722f79b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my previous blog 👍 <a target="_blank" href="https://hashnode.com/edit/cm1kgsky6000t0alacle9271n">here</a> i have monitored logs using promtail as agent but wait we have Loki Logging Driver which will give more option to choose container name and watch logs of it Lets go through this.</p>
<p>I have made few changes here as i don’t use promtail here instead use <strong>Grafana Loki Docker logging driver plugin</strong> . It is a Docker plugin designed to send container logs directly to a <strong>Loki</strong> instance for centralized log aggregation and monitoring</p>
<p>Compose file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">laravel-app:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">laravel-app</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">laravel-cont</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">/home/aditya/laravel/helloworld</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8555:80"</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

  <span class="hljs-attr">prometheus:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">prom/prometheus</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-prometheus</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./prometheus.yml:/etc/prometheus/prometheus.yml</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8556:9090"</span>
    <span class="hljs-attr">command:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--config.file=/etc/prometheus/prometheus.yml</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

  <span class="hljs-attr">grafana:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/grafana</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-grafana</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8557:3000"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_USER=admin</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_PASSWORD=admin</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">prometheus</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">loki</span>

  <span class="hljs-attr">loki:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/loki</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-loki</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8558:3100"</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">postgres_data:</span>
  <span class="hljs-attr">grafana_data:</span>
  <span class="hljs-attr">loki-data:</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">monitoring:</span>
    <span class="hljs-attr">driver:</span> <span class="hljs-string">bridge</span>
</code></pre>
<p>This is the same compose file i have used in my previous blog but instead of promtail as log agent i used <strong>Grafana Loki Docker logging driver plugin.</strong></p>
<p>So, only change compose-file and follow same step as in previous blog.</p>
<p>Now follow these steps</p>
<h3 id="heading-step-1-install-a-docker-driver-to-send-logs-to-loki">Step 1: Install a docker driver to send logs to Loki</h3>
<p><code>docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions</code></p>
<h3 id="heading-step-2-add-the-following-file-in-etcdocker">Step 2: Add the following file in /etc/docker</h3>
<p>daemon.json</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"debug"</span> : <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"log-driver"</span>: <span class="hljs-string">"loki"</span>,
    <span class="hljs-attr">"log-opts"</span>: {
        <span class="hljs-attr">"loki-url"</span>: <span class="hljs-string">"http://localhost:8558/loki/api/v1/push"</span>,
        <span class="hljs-attr">"loki-batch-size"</span>: <span class="hljs-string">"400"</span>
    }
}
</code></pre>
<p>Now run the containers and access grafana</p>
<p>Access Grafana</p>
<p>Grafana: http://server-ip:8557</p>
<p>Add datasource as Loki:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727432096766/0f53fc3e-5229-4e6c-a2b2-c5b76f82aa6d.png" alt class="image--center mx-auto" /></p>
<p>now look at the option provided here</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727432133255/1f6e3af5-a73e-4898-a626-f9c0bf424d28.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727432245924/80a4d424-b3bf-4002-ae4c-68371e389346.png" alt class="image--center mx-auto" /></p>
<p>Now, i want to setup alerting rules for CPU usage on node .</p>
<h3 id="heading-setting-up-alert-rules">Setting Up Alert rules:</h3>
<p>To get started, navigate to the <strong>New Alert Rule</strong> section in your monitoring system.</p>
<ul>
<li><p><strong>Enter Alert Name</strong>: Choose a descriptive name for your alert rule.</p>
</li>
<li><p><strong>Run the Query</strong>: Input the query that monitors CPU usage. This could be a query that checks for CPU utilization above a specific threshold.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727938610842/d1c2a313-1450-49a2-b527-3d3e9e4609d0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727938764516/fc08e73a-2893-40c4-970b-144d9fd276d0.png" alt class="image--center mx-auto" /></p>
<p>Next, you’ll need to configure the alert condition. Define when the alert should be triggered based on CPU usage metrics. Set parameters such as:</p>
<ul>
<li><p><strong>Condition</strong>: CPU usage percentage.</p>
</li>
<li><p><strong>Threshold</strong>: Define the limit at which the alert should fire.</p>
</li>
</ul>
<p>Once you've set this up, you can visualize if the conditions are met. Below is an example image where the alert condition is triggered because CPU usage exceeded the defined threshold.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727939009175/293484a3-a2d7-46c4-9410-68302d89fce9.png" alt class="image--center mx-auto" /></p>
<p>When the CPU usage condition is not met, no alert is fired as it remains within normal limits.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727939094931/74670f37-3204-43c4-8157-9e78b7f06361.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-set-up-notification-channels">Set Up Notification Channels</h3>
<p>To make sure you're notified when an alert fires, you'll need to set up <strong>Contact Points</strong>. In this blog, I’ll use Slack as the notification channel.</p>
<p><strong>Configure Slack</strong>: Start by setting up a Slack integration with your alerting system. You can do this by creating a <strong>Webhook URL</strong> from Slack. Follow these steps:</p>
<p>In Slack, go to <strong>Apps</strong> and search for "Incoming Webhooks".</p>
<p>Select <strong>Incoming Webhooks</strong>, and click <strong>Add to Slack</strong>.</p>
<p>Choose the desired Slack channel where you want to receive notifications.</p>
<p>After selecting the channel, Slack will generate a <strong>Webhook URL</strong> for you.</p>
<p><strong>Webhook URL</strong>: Copy the Webhook URL provided by Slack and add it to your alerting system’s configuration under the contact points for Slack notifications.</p>
<p><strong>Desired Channel</strong>: While setting up the Webhook, you'll have already selected the specific Slack channel where notifications will be sent. Ensure this channel is actively monitored so your team is instantly informed when an alert is triggered.</p>
<p>With the Webhook properly configured, every time the alert condition is met, you'll receive a message in the specified Slack channel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727939769209/bdf15bd5-98d8-4c6e-a7d6-939012a506b7.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727941324353/4ca81783-5008-4b08-85fd-cfbf5b78a235.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727940491017/c88d4985-0fcd-4a5d-8c88-d8862fe9c37f.png" alt class="image--center mx-auto" /></p>
<p>And that's it! You've successfully set up an alert rule for CPU usage and configured Slack notifications to keep you updated in real-time.</p>
]]></content:encoded></item><item><title><![CDATA[Visualize Your Logs: Integrating Promtail, Loki, Prometheus, and Grafana for Improved Monitoring]]></title><description><![CDATA[In this blog, I built a simple Laravel application that prints "Hello, World." Next, I'll set up containers for this app and then keep an eye on its logs.
Tools
To accomplish this, I utilized several tools and agents:

Promtail: This agent collects l...]]></description><link>https://blog.adityajaishi.com.np/visualize-your-logs-integrating-promtail-loki-prometheus-and-grafana-for-improved-monitoring</link><guid isPermaLink="true">https://blog.adityajaishi.com.np/visualize-your-logs-integrating-promtail-loki-prometheus-and-grafana-for-improved-monitoring</guid><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Aditya Jaishi]]></dc:creator><pubDate>Fri, 27 Sep 2024 08:32:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727418317555/1673d658-c9db-41f1-85e5-1cc784edcedc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog, I built a simple Laravel application that prints "Hello, World." Next, I'll set up containers for this app and then keep an eye on its logs.</p>
<h3 id="heading-tools">Tools</h3>
<p>To accomplish this, I utilized several tools and agents:</p>
<ul>
<li><p><strong>Promtail</strong>: This agent collects logs from various sources, including files and Docker containers, and forwards them to Loki. It's essentially responsible for gathering logs for storage.</p>
</li>
<li><p><strong>Loki</strong>: A log aggregation system designed for efficient log storage and retrieval.</p>
</li>
<li><p><strong>Grafana</strong>: An open-source analytics and monitoring platform that allows users to visualize and analyze data from multiple sources through customizable dashboards. It is commonly used for monitoring metrics, logs, and application performance.</p>
</li>
</ul>
<h3 id="heading-architecture">Architecture</h3>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeGGXdS9-AU84yZPoI09TKZvrK6EL42ppU6dBMt6rA3-LhlFegpeQ-J840ov2apimBCkp8JcnfxGkBK-HrXAeApxxvP8lmFdfRFvqBckjXOo6bWlcXoXMp4WYf_ow28gzfy8Ov9Mtrr1ofCq3e42peOrYk?key=fmoZL4nLyLcUzoWp9r3CJw" alt /></p>
<h3 id="heading-compose-file-for-setting-up-containers">Compose file for Setting up containers</h3>
<p>To set up this task, I pulled Docker images for Promtail, Loki, and Grafana. Then, I created a Compose file to run all the containers within a single network called "monitoring." Let's check out the Compose file together.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">laravel-app:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">laravel-app</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">laravel-cont</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">/home/aditya/laravel/helloworld</span> <span class="hljs-comment">#Add path of dockerfile to make laravel-cont</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8555:80"</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

  <span class="hljs-attr">prometheus:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">prom/prometheus</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-prometheus</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./prometheus.yml:/etc/prometheus/prometheus.yml</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8556:9090"</span>
    <span class="hljs-attr">command:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--config.file=/etc/prometheus/prometheus.yml</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

  <span class="hljs-attr">promtail:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/promtail:2.7.1</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-promtail</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Changed to monitoring</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./promtail-config.yaml:/etc/promtail/config.yaml</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/var/lib/docker/containers:/var/lib/docker/containers:ro</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/var/log:/var/log:ro</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">-config.file=/etc/promtail/config.yaml</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">loki</span>

  <span class="hljs-attr">grafana:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/grafana</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-grafana</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8557:3000"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_USER=admin</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GF_SECURITY_ADMIN_PASSWORD=admin</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">prometheus</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">loki</span>

  <span class="hljs-attr">loki:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">grafana/loki</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">aditya-loki</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./loki-config.yaml:/etc/loki/loki-config.yaml</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">-config.file=/etc/loki/loki-config.yaml</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8558:3100"</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">monitoring</span>  <span class="hljs-comment"># Use the monitoring network</span>

<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">postgres_data:</span>
  <span class="hljs-attr">grafana_data:</span>
  <span class="hljs-attr">loki-data:</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">monitoring:</span>
    <span class="hljs-attr">driver:</span> <span class="hljs-string">bridge</span>
</code></pre>
<p>Here's the Docker file located at /home/aditya/laravel/helloworld</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> php:<span class="hljs-number">8.2</span>-apache

<span class="hljs-comment"># Install dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; \
    apt-get install -y \
    libzip-dev \
    zip</span>

<span class="hljs-comment"># Enable mod_rewrite</span>
<span class="hljs-keyword">RUN</span><span class="bash"> a2enmod rewrite</span>

<span class="hljs-comment"># Install PHP extensions</span>
<span class="hljs-keyword">RUN</span><span class="bash"> docker-php-ext-install pdo_mysql zip</span>

<span class="hljs-keyword">ENV</span> APACHE_DOCUMENT_ROOT=/var/www/html/public
<span class="hljs-keyword">RUN</span><span class="bash"> sed -ri -e <span class="hljs-string">'s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g'</span> /etc/apache2/sites-available/*.conf</span>
<span class="hljs-keyword">RUN</span><span class="bash"> sed -ri -e <span class="hljs-string">'s!/var/www/!${APACHE_DOCUMENT_ROOT}!g'</span> /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf</span>

<span class="hljs-comment"># Copy the application code</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . /var/www/html</span>

<span class="hljs-comment"># Set the working directory</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /var/www/html</span>

<span class="hljs-comment"># Install composer</span>
<span class="hljs-keyword">RUN</span><span class="bash"> curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/<span class="hljs-built_in">local</span>/bin --filename=composer</span>

<span class="hljs-comment"># Install project dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> composer install</span>

<span class="hljs-comment"># Set permissions</span>
<span class="hljs-keyword">RUN</span><span class="bash"> chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache</span>
</code></pre>
<p><em>Note: Make sure you have a laravel-app that contains all necessary files.</em></p>
<p>In the same directory where the Compose file is located, please add the following files:</p>
<p><strong>1. prometheus.yml</strong></p>
<p>Purpose: This file configures Prometheus to scrape metrics from Loki. It defines the scrape interval and specifies the targets for monitoring.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">global:</span>
  <span class="hljs-attr">scrape_interval:</span> <span class="hljs-string">15s</span>

<span class="hljs-attr">scrape_configs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">job_name:</span> <span class="hljs-string">'loki'</span>
    <span class="hljs-attr">static_configs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">targets:</span> [<span class="hljs-string">'loki:3100'</span>]
</code></pre>
<p><strong>2. loki-config.yml</strong></p>
<p>Purpose: This configuration file sets up Loki's parameters, such as the server port, storage configurations, and ingester settings. It determines how logs are stored and indexed.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">auth_enabled:</span> <span class="hljs-literal">false</span>

<span class="hljs-attr">server:</span>
  <span class="hljs-attr">http_listen_port:</span> <span class="hljs-number">3100</span>

<span class="hljs-attr">ingester:</span>
  <span class="hljs-attr">wal:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">dir:</span> <span class="hljs-string">/loki/wal</span>
  <span class="hljs-attr">chunk_idle_period:</span> <span class="hljs-string">1m</span>
  <span class="hljs-attr">max_chunk_age:</span> <span class="hljs-string">1h</span>

<span class="hljs-attr">schema_config:</span>
  <span class="hljs-attr">configs:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">from:</span> <span class="hljs-number">2020-10-01</span>
      <span class="hljs-attr">store:</span> <span class="hljs-string">boltdb-shipper</span>
      <span class="hljs-attr">schema:</span> <span class="hljs-string">v11</span>
      <span class="hljs-attr">index:</span>
        <span class="hljs-attr">prefix:</span> <span class="hljs-string">index_</span>
        <span class="hljs-attr">period:</span> <span class="hljs-string">24h</span>

<span class="hljs-attr">storage_config:</span>
  <span class="hljs-attr">boltdb_shipper:</span>
    <span class="hljs-attr">active_index_directory:</span> <span class="hljs-string">/loki/index</span>
    <span class="hljs-attr">cache_location:</span> <span class="hljs-string">/loki/cache</span>
    <span class="hljs-attr">shared_store:</span> <span class="hljs-string">filesystem</span>
  <span class="hljs-attr">filesystem:</span>
    <span class="hljs-attr">directory:</span> <span class="hljs-string">/loki/chunks</span>

<span class="hljs-attr">limits_config:</span>
  <span class="hljs-attr">max_query_series:</span> <span class="hljs-number">500000</span>
</code></pre>
<p><strong>3. promtail-config.yaml</strong></p>
<p>Purpose: This file configures Promtail to scrape logs from the specified locations (like Docker containers) and send them to Loki. It also sets the server port and the position file to keep track of the last read log positions.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">server:</span>
  <span class="hljs-attr">http_listen_port:</span> <span class="hljs-number">9080</span>

<span class="hljs-attr">positions:</span>
  <span class="hljs-attr">filename:</span> <span class="hljs-string">/tmp/positions.yaml</span>

<span class="hljs-attr">clients:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">http://aditya-loki:3100/loki/api/v1/push</span>


<span class="hljs-attr">scrape_configs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">job_name:</span> <span class="hljs-string">docker</span>
    <span class="hljs-attr">static_configs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">targets:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">localhost</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">job:</span> <span class="hljs-string">docker</span>
          <span class="hljs-attr">__path__:</span> <span class="hljs-string">/var/lib/docker/containers/*/*.log</span>  <span class="hljs-comment"># Path to Docker logs</span>
</code></pre>
<p>Now, set up containers using Docker Compose file.</p>
<p><em>command:</em></p>
<p><code>docker-compose build</code></p>
<p><code>docker-compose up -d</code> (run containers in detached mode)</p>
<h3 id="heading-accessing-the-containers">Accessing the containers:</h3>
<p><strong>Laravel application</strong>: <em>http://server-ip:8555</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727421743988/c213a241-8c33-4c81-8fd4-0caff78eb583.png" alt class="image--center mx-auto" /></p>
<p><strong>Prometheus</strong>: <em>http://server-ip:8556</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727421826782/134e9591-15c3-4a0e-8741-53a2c3e2f1d4.png" alt class="image--center mx-auto" /></p>
<p><strong>Grafana</strong>: <em>http://server-ip:8557</em></p>
<p>Add loki as datasource</p>
<p>In the URL, make sure to enter the right container name and port.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727421853559/34317f81-ba0d-48b1-816a-ad093674450a.png" alt class="image--center mx-auto" /></p>
<p>Visualize logs using the filename and containerID</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727421908517/c88aa805-8865-42ab-b510-22025017bf54.png" alt class="image--center mx-auto" /></p>
<p>Here, in the directory <code>/var/lib/docker/</code>, you'll find the ID for each container, and you can easily forward their logs to Loki.</p>
<p>Oh, wait! In my upcoming blog, I'll dive deeper into this topic and also include a step-by-step guide on setting up alerts. Make sure to check it out!</p>
]]></content:encoded></item><item><title><![CDATA[How to Configure Nginx for Multiple Domains with SSL Certificates: A Step-by-Step Guide]]></title><description><![CDATA[Nginx is a robust and versatile web server capable of managing multiple domains and ensuring secure content delivery through SSL/TLS certificates. In this guide, we will provide a detailed walkthrough on setting up Nginx to handle multiple domains an...]]></description><link>https://blog.adityajaishi.com.np/how-to-configure-nginx-for-multiple-domains-with-ssl-certificates-a-step-by-step-guide</link><guid isPermaLink="true">https://blog.adityajaishi.com.np/how-to-configure-nginx-for-multiple-domains-with-ssl-certificates-a-step-by-step-guide</guid><category><![CDATA[Devops]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[networking]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[nginx]]></category><category><![CDATA[SSL]]></category><dc:creator><![CDATA[Aditya Jaishi]]></dc:creator><pubDate>Thu, 29 Aug 2024 08:29:01 GMT</pubDate><content:encoded><![CDATA[<p>Nginx is a robust and versatile web server capable of managing multiple domains and ensuring secure content delivery through SSL/TLS certificates. In this guide, we will provide a detailed walkthrough on setting up Nginx to handle multiple domains and configuring SSL certificates for secure connections.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites:</strong></h3>
<p><strong>Domain Names and DNS Records</strong></p>
<p>Make sure you have valid domain names, like <a target="_blank" href="http://testaditya.duckdns.org"><code>testaditya.duckdns.org</code></a> and <a target="_blank" href="http://testaditya1.duckdns.org"><code>testaditya1.duckdns.org</code></a> in this example, and that they are correctly registered. You can use DuckDNS for free domain registration.</p>
<p>Ensure the DNS A records for these domains point to your server's public IP address. Use a DNS management tool or service to set up these records.</p>
<p><strong>Ubuntu Server</strong>: This guide assumes you are using an Ubuntu-based server. If you use a different distribution, adjust the commands as needed. Your server should have a public IP address that can be accessed from the internet.</p>
<p><strong>Root or Sudo Access</strong>: You'll need root or sudo access to install software, tweak configuration files, and restart services.</p>
<h3 id="heading-step-1-install-nginx"><strong>Step 1. Install Nginx</strong></h3>
<p>First, you need to have Nginx installed on your server. If you haven't installed Nginx yet, you can do so with the following commands:</p>
<p><code>sudo apt update</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724910107180/29ea5a92-139c-4c02-8364-bdf79485dfe3.png" alt class="image--center mx-auto" /></p>
<p><code>sudo apt install nginx</code></p>
<h3 id="heading-step-2-installing-certbot-for-ssl-certificates"><strong>Step 2: Installing Certbot for SSL Certificates</strong></h3>
<p>Install Certbot and Nginx Plugin:</p>
<p><code>sudo apt install certbot python3-certbot-nginx</code></p>
<h3 id="heading-step-3-configure-nginx"><strong>Step 3: Configure Nginx</strong></h3>
<p>Create a configuration file for your domain. Create one directory for two domains and add <code>index.html</code> with the desired content.</p>
<p><code>sudo mkdir -p /var/www/domain1.com</code></p>
<p><code>echo 'Hello, I am Aditya 1' | sudo tee /var/www/domain1.com/index.html</code></p>
<h3 id="heading-step-3-create-nginx-config-files"><strong>Step 3: Create Nginx Config Files</strong></h3>
<p><code>sudo nano /etc/nginx/sites-available/domain1.com</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724910968314/d0fc4d90-7fb0-44c9-8483-d72605360903.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-3-enable-the-sites"><strong>Step 3: Enable the sites</strong></h3>
<p><code>sudo ln -s /etc/nginx/sites-available/domain1.com /etc/nginx/sites-enabled/</code></p>
<h3 id="heading-step-4-test-nginx-configuration"><strong>Step 4: Test Nginx Configuration</strong></h3>
<p><code>sudo nginx -t</code></p>
<h3 id="heading-step-4-obtain-ssl-certificates-using-certbot"><strong>Step 4: Obtain SSL Certificates Using Certbot</strong></h3>
<p><code>sudo certbot --nginx -d testaditya1.duckdns.org</code></p>
<p><code>sudo certbot --nginx -d testaditya.duckdns.org</code></p>
<h3 id="heading-step-5-obtain-ssl-certificates-using-certbot"><strong>Step 5: Obtain SSL Certificates Using Certbot</strong></h3>
<p><code>sudo certbot certificates</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724912804359/435ab48d-2aa1-4da5-b3c6-4e11e6da7eea.png" alt class="image--center mx-auto" /></p>
<p>Nginx configuration file should look like this at the end.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724916519893/e09cdd26-b9b0-4da4-a431-1b7790b6bf59.png" alt class="image--center mx-auto" /></p>
<p>Now, your server is correctly serving the content for those domains. Enter both domains on browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724919869830/b1531b47-f2bf-4eba-862e-1c3cc9c83b74.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724919895196/ea532a10-a0d1-4f8c-8886-5b6a4f7ac96e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-bash-script-to-automate-this-process">Bash Script to automate this process</h2>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Variables</span>
DOMAINS=<span class="hljs-string">"testaditya.duckdns.org testaditya1.duckdns.org"</span>
WEB_ROOT=<span class="hljs-string">"/var/www/domain1.com"</span>
NGINX_CONF=<span class="hljs-string">"/etc/nginx/sites-available/domain1.com"</span>
CERTBOT_LOG=<span class="hljs-string">"/var/log/letsencrypt/letsencrypt.log"</span>

<span class="hljs-comment"># Update and install necessary packages</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Updating package lists..."</span>
sudo apt update

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing Nginx and Certbot..."</span>
sudo apt install -y nginx certbot python3-certbot-nginx

<span class="hljs-comment"># Create Nginx configuration</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating Nginx configuration..."</span>
cat &lt;&lt;EOF | sudo tee <span class="hljs-variable">$NGINX_CONF</span>
server {
    listen 80;
    listen [::]:80;
    server_name <span class="hljs-variable">$DOMAINS</span>;

    location / {
        try_files \<span class="hljs-variable">$uri</span> \<span class="hljs-variable">$uri</span>/ =404;
    }

    location / {
        <span class="hljs-built_in">return</span> 301 https://\<span class="hljs-variable">$host</span>\<span class="hljs-variable">$request_uri</span>;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name <span class="hljs-variable">$DOMAINS</span>;

    root <span class="hljs-variable">$WEB_ROOT</span>;
    index index.html;

    location / {
        try_files \<span class="hljs-variable">$uri</span> \<span class="hljs-variable">$uri</span>/ =404;
    }

    <span class="hljs-comment"># SSL configuration</span>
    ssl_certificate /etc/letsencrypt/live/testaditya.duckdns.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/testaditya.duckdns.org/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
EOF

<span class="hljs-comment"># Enable the Nginx site</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Enabling Nginx site configuration..."</span>
sudo ln -s <span class="hljs-variable">$NGINX_CONF</span> /etc/nginx/sites-enabled/

<span class="hljs-comment"># Test Nginx configuration</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Testing Nginx configuration..."</span>
sudo nginx -t

<span class="hljs-comment"># Reload Nginx to apply changes</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Reloading Nginx..."</span>
sudo systemctl reload nginx

<span class="hljs-comment"># Obtain SSL certificates using Certbot</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Obtaining SSL certificates with Certbot..."</span>
sudo certbot --nginx -d testaditya.duckdns.org -d testaditya1.duckdns.org

<span class="hljs-comment"># Check Certbot status</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Checking Certbot status..."</span>
sudo certbot certificates

<span class="hljs-built_in">echo</span> <span class="hljs-string">"SSL setup is complete. Please verify your domains."</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[How to Install WordPress on Ubuntu 24.04]]></title><description><![CDATA[Installing Ubuntu on your server can give you greater control and customization for your WordPress site. Let's dive into the process, ensuring your site runs smoothly and efficiently
Here are the steps for Installing WordPress on Ubuntu 24.04
Step 1:...]]></description><link>https://blog.adityajaishi.com.np/how-to-install-wordpress-on-ubuntu-2404</link><guid isPermaLink="true">https://blog.adityajaishi.com.np/how-to-install-wordpress-on-ubuntu-2404</guid><category><![CDATA[WordPress Setup]]></category><dc:creator><![CDATA[Aditya Jaishi]]></dc:creator><pubDate>Mon, 26 Aug 2024 09:26:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727622229535/cc6473e2-e165-4eeb-82e3-44f279841ae0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Installing Ubuntu on your server can give you greater control and customization for your WordPress site. Let's dive into the process, ensuring your site runs smoothly and efficiently</p>
<h3 id="heading-here-are-the-steps-for-installing-wordpress-on-ubuntu-2404"><strong>Here are the steps for Installing WordPress on Ubuntu 24.04</strong></h3>
<p><strong>Step 1: Update the server</strong></p>
<p><code>sudo apt update</code></p>
<p>This command updates the list of available packages and their versions from the Ubuntu repositories.</p>
<p><strong>Step 2: Install nginx server</strong></p>
<p><code>sudo apt install nginx -y</code></p>
<p>Nginx will serve up your WordPress site to users. The -y flag just says "yes" to all prompts, making the installation quicker.</p>
<p><strong>Step 3: Install Mysql</strong></p>
<p><code>sudo apt install mysql-server mysql-client -y</code></p>
<p>Installs the MySQL database server and client.</p>
<p>WordPress requires a database to store content, user information, settings, and more. MySQL is one of the most popular database systems used with WordPress.</p>
<p><strong>Step 4:</strong> <strong>Install PHP and Required Extensions</strong></p>
<p><code>sudo apt install php-fpm php-mysql php-xml php-mbstring php-curl php-zip php-gd php-imagick -y</code></p>
<p>Installs PHP and the necessary PHP extensions for WordPress.</p>
<p>PHP is the scripting language that WordPress uses. The extensions add extra features needed by WordPress, like database interaction (php-mysql), image processing (php-imagick), and handling form data (php-mbstring).</p>
<p><strong>Step 5:</strong> <strong>Create a Database for WordPress</strong></p>
<p><code>sudo mysql -u root -p</code></p>
<p>Creates a new MySQL database and user for WordPress.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724410553677/44b695be-77f3-46ea-b3d4-b1682f20cad0.png" alt class="image--center mx-auto" /></p>
<p>WordPress needs its own database to store content. Creating a separate user for WordPress improves security by limiting access to only the WordPress database.</p>
<p><strong>Step 6:</strong> <strong>Download and extract latest version of WordPress</strong></p>
<p><code>sudo wget</code> <a target="_blank" href="https://wordpress.org/latest.tar.gz"><code>https://wordpress.org/latest.tar.gz</code></a></p>
<p><code>sudo tar -xvzf latest.tar.gz</code></p>
<p>This is the core software needed to run your WordPress website.</p>
<p><strong>Step 7:</strong> <strong>Move WordPress Files</strong></p>
<p><code>sudo mv wordpress /var/www/mywordpresssite</code></p>
<p>Moves the extracted WordPress files to the web root directory.</p>
<p>Nginx needs to know where the website files are. By moving them to /var/www/mywordpresssite, you set the document root where Nginx will find the files to serve.</p>
<p><strong>Step 8:</strong> <strong>Configure WordPress</strong></p>
<p><code>cd /var/www/mywordpresssite</code></p>
<p><code>sudo cp wp-config-sample.php wp-config.php</code></p>
<p>wp-config.php file</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724411062773/ed9c97e7-782f-43e6-869a-7f2c02bb9518.png" alt class="image--center mx-auto" /></p>
<p>Configures the WordPress settings to connect to the MySQL database.</p>
<p>WordPress needs to know the database name, username, password, and host to store and retrieve content.</p>
<p><strong>Step 9: Set Up Correct Permissions</strong></p>
<p><code>sudo chown -R www-data:www-data /var/www/mywordpresssite</code></p>
<p><code>sudo find /var/www/mywordpresssite/ -type d -exec chmod 750 {} \;</code></p>
<p><code>sudo find /var/www/mywordpresssite/ -type f -exec chmod 640 {} \;</code></p>
<p>Sets the appropriate file and directory permissions for WordPress.</p>
<p>Ensures that the web server (Nginx) can read and write files as necessary, while limiting access to other users on the server, enhancing security.</p>
<p><strong>Step 10: Configure Nginx</strong></p>
<p>Configures Nginx to serve your WordPress site.</p>
<p><code>sudo nano /etc/nginx/sites-available/mywordpresssite</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724410954314/2fd3b0c3-aced-4b39-86a1-feda0a2f89cc.png" alt class="image--center mx-auto" /></p>
<p>It tells Nginx where to find your WordPress files and how to handle PHP requests.</p>
<p><strong>Step 11: Enable the Site and Test Nginx Configuration</strong></p>
<p><code>sudo ln -s /etc/nginx/sites-available/mywordpresssite /etc/nginx/sites-enabled/ sudo nginx -t</code></p>
<p>Creates a symbolic link to enable the Nginx site configuration and tests the Nginx configuration for errors.</p>
<p>Activates your site and ensures that Nginx is correctly configured before reloading.</p>
<p><strong>Step 12: Reload Nginx</strong></p>
<p>Reloads Nginx to apply the new configuration.</p>
<p><code>sudo systemctl reload nginx</code></p>
<p><strong>Step 13: Complete the WordPress Installation</strong></p>
<p>Access WordPress: Open your web browser and go to <a target="_blank" href="http://your_public_ip">http://your_public_ip</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724411108544/e11cb5b7-9556-4bc9-be13-466c2d815b61.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724411148185/71a02e50-7fdf-4e33-9721-25818525e071.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724411162881/34d6bfba-daef-439c-a1bf-87f88642a615.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724411378234/be1b81d5-e8b2-440d-b039-b89fc99ef14b.png" alt class="image--center mx-auto" /></p>
<p><strong>Automating the installation using bash script</strong></p>
<p>This script automates the process, including downloading WordPress, setting up the database, configuring Nginx, and adjusting file permissions. You only need to run it, and the setup will be ready for you to complete through the WordPress web interface.</p>
<p><em>./install_</em><a target="_blank" href="http://wordpress.sh"><em>wordpress.sh</em></a></p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># Update package list and install necessary packages</span>
sudo apt update
sudo apt install -y nginx mysql-server mysql-client php-fpm php-mysql php-xml 
php-mbstring php-curl php-zip php-gd php-imagick wget unzip
<span class="hljs-comment"># Secure MySQL installation (Optional)</span>
<span class="hljs-comment"># Uncomment the following line if you want to run the MySQL secure installation </span>
interactively
<span class="hljs-comment"># sudo mysql_secure_installation</span>
<span class="hljs-comment"># Create a MySQL database and user for WordPress</span>
DB_NAME=<span class="hljs-string">"wordpress_db"</span>
DB_USER=<span class="hljs-string">"wp_user"</span>
DB_PASSWORD=<span class="hljs-string">"password123"</span>
sudo mysql -e <span class="hljs-string">"CREATE DATABASE <span class="hljs-variable">${DB_NAME}</span>;"</span>
sudo mysql -e <span class="hljs-string">"CREATE USER '<span class="hljs-variable">${DB_USER}</span>'@'localhost' IDENTIFIED BY 
'<span class="hljs-variable">${DB_PASSWORD}</span>';"</span>
sudo mysql -e <span class="hljs-string">"GRANT ALL PRIVILEGES ON <span class="hljs-variable">${DB_NAME}</span>.* TO 
'<span class="hljs-variable">${DB_USER}</span>'@'localhost';"</span>
sudo mysql -e <span class="hljs-string">"FLUSH PRIVILEGES;"</span>
<span class="hljs-comment"># Download and extract WordPress</span>
<span class="hljs-built_in">cd</span> /var/www/
sudo wget https://wordpress.org/latest.tar.gz
sudo tar -xvzf latest.tar.gz
sudo mv wordpress mywordpresssite
<span class="hljs-comment"># Configure WordPress</span>
<span class="hljs-built_in">cd</span> /var/www/mywordpresssite
sudo cp wp-config-sample.php wp-config.php
sudo sed -i <span class="hljs-string">"s/database_name_here/<span class="hljs-variable">${DB_NAME}</span>/"</span> wp-config.php
sudo sed -i <span class="hljs-string">"s/username_here/<span class="hljs-variable">${DB_USER}</span>/"</span> wp-config.php
sudo sed -i <span class="hljs-string">"s/password_here/<span class="hljs-variable">${DB_PASSWORD}</span>/"</span> wp-config.php
<span class="hljs-comment"># Set correct permissions</span>
sudo chown -R www-data:www-data /var/www/mywordpresssite
sudo find /var/www/mywordpresssite/ -<span class="hljs-built_in">type</span> d -<span class="hljs-built_in">exec</span> chmod 750 {} \;
sudo find /var/www/mywordpresssite/ -<span class="hljs-built_in">type</span> f -<span class="hljs-built_in">exec</span> chmod 640 {} \;
<span class="hljs-comment"># Configure Nginx</span>
NGINX_CONF=<span class="hljs-string">"/etc/nginx/sites-available/mywordpresssite"</span>
sudo bash -c <span class="hljs-string">"cat &gt; <span class="hljs-variable">${NGINX_CONF}</span>"</span> &lt;&lt;EOF
server {
 listen 8080;
 server_name your_public_ip;
 root /var/www/mywordpresssite;
 index index.php index.html index.htm;
 location / {
 try_files \<span class="hljs-variable">$uri</span> \<span class="hljs-variable">$uri</span>/ /index.php?\<span class="hljs-variable">$args</span>;
 }
 location ~ \.php\$ {
 include snippets/fastcgi-php.conf;
 fastcgi_pass unix:/var/run/php/php-fpm.sock;
 fastcgi_param SCRIPT_FILENAME \<span class="hljs-variable">$document_root</span>\<span class="hljs-variable">$fastcgi_script_name</span>;
 include fastcgi_params;
 }
 location ~ /\.ht {
 deny all;
 }
}
EOF
<span class="hljs-comment"># Replace 'your_public_ip' with the server's public IP</span>
PUBLIC_IP=$(curl -s ifconfig.me)
sudo sed -i <span class="hljs-string">"s/your_public_ip/<span class="hljs-variable">${PUBLIC_IP}</span>/"</span> <span class="hljs-variable">${NGINX_CONF}</span>
<span class="hljs-comment"># Enable the Nginx site and reload the configuration</span>
sudo ln -s /etc/nginx/sites-available/mywordpresssite /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
<span class="hljs-comment"># Output completion message</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"WordPress has been installed. Open http://<span class="hljs-variable">${PUBLIC_IP}</span> in your browser 
to complete the setup."</span>
</code></pre>
<p>Follow me here: <a target="_blank" href="http://blog.adityajaishi.com.np">@dity@</a></p>
<p><em>\======================================================================================================================================</em></p>
]]></content:encoded></item></channel></rss>