<?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" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by MHVN on Medium]]></title>
        <description><![CDATA[Stories by MHVN on Medium]]></description>
        <link>https://medium.com/@muhalvin?source=rss-985397abdee6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Q_kZdF8VLZstYm5TAnJvGA.jpeg</url>
            <title>Stories by MHVN on Medium</title>
            <link>https://medium.com/@muhalvin?source=rss-985397abdee6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 20 Apr 2026 06:34:29 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@muhalvin/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Explaining Sessions in PHP Like I’m 5]]></title>
            <link>https://towardsdev.com/explaining-sessions-in-php-like-im-5-4d4c777433b1?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d4c777433b1</guid>
            <category><![CDATA[php]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Wed, 16 Jul 2025 05:13:26 GMT</pubDate>
            <atom:updated>2025-07-18T12:40:45.001Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="https://www.freepik.com/free-vector/stock-exchange-data-concept_8850059.htm" src="https://cdn-images-1.medium.com/max/1024/1*zkdcNXudFAEXPtnFrvxqrQ.jpeg" /><figcaption>Image by Freepik</figcaption></figure><p>You know, when you go to a pizza place, they give you a little number on a stand so the waiter knows which table ordered what? That number doesn’t <em>store</em> your pizza — it just tells the kitchen, “Hey, Table 7 wants a large pepperoni.”</p><p>That’s kind of how sessions work in PHP.</p><p>When you visit a website, PHP gives you a unique session ID (like your table number). This ID helps the server remember stuff about <em>you</em> — like your login status, shopping cart, or form inputs — without mixing you up with someone else.</p><p>The actual data (your “pizza”) gets stored on the server, and PHP uses the session ID to match it with you every time you visit a new page. That way, the site doesn’t forget who you are after every click.</p><h3>So, How Does It Work in PHP?</h3><p>Okay, so that’s the pizza place version — but how does this actually work in PHP? Let’s break it down with a real example.</p><p>To start a session, use this line at the very top of your PHP file (before any output):</p><pre>&lt;?php<br>session_start();<br>?&gt;</pre><p>This tells PHP:</p><ul><li>“Hey, check if this user already has a session,” or</li><li>“If not, create a new one.”</li></ul><p>Once that’s done, you can store data like this:</p><pre>$_SESSION[&#39;username&#39;] = &#39;muhalvin&#39;;<br>$_SESSION[&#39;logged_in&#39;] = true;</pre><p>And later, on another page:</p><pre>echo $_SESSION[&#39;username&#39;]; // outputs &#39;muhalvin&#39;</pre><p>That data is stored on the server, and the user’s browser holds a session ID (usually in a cookie called PHPSESSID) so PHP can match the request with the right session data.</p><h3>Common Mistakes I Made (and How to Avoid Them)</h3><p>When I first used sessions, I ran into a few problems — here are the big ones:</p><h4>I forgot session_start();</h4><p>Without this, $_SESSION just won’t work. It always needs to be the first thing in your script — before <em>any</em> output, even a blank space.</p><h4>I had output before the session started</h4><p>If you echo something or accidentally leave a space before &lt;?php, you’ll get a “headers already sent” error. Sessions modify headers, so they must be started before anything gets sent to the browser.</p><h4>I thought sessions were automatically secure</h4><p>Sessions help store data, but they’re not a security system on their own. Always use HTTPS, validate user input, and regenerate session IDs on login with:</p><pre>session_regenerate_id(true);</pre><p>This helps prevent session hijacking.</p><h3>Logging Out (Destroying the Session)</h3><p>To end a session — like logging a user out — you can use:</p><pre>session_start();<br>session_unset();     // Clear session variables<br>session_destroy();   // End the session completely</pre><p>This deletes the data and removes the session ID, so the user is no longer recognized.</p><p>Hope this explanation made sessions feel a little less scary! If you’ve got questions or want me to break down another PHP concept, let me know — I’m still learning too.</p><p>And if your session data suddenly disappears, don’t worry — it’s probably not PHP being mean. It’s just you forgetting session_start(); (again). Happens to the best of us.</p><blockquote><em>“If sessions were a friend, they’d be that one guy who wants to remember your name, but only if you start the conversation properly.”</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d4c777433b1" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/explaining-sessions-in-php-like-im-5-4d4c777433b1">Explaining Sessions in PHP Like I’m 5</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[File vs Database Sessions: My Experience Choosing the Right Session Storage for Web Apps]]></title>
            <link>https://muhalvin.medium.com/file-vs-database-sessions-my-experience-choosing-the-right-session-storage-for-web-apps-a390f2cfe308?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/a390f2cfe308</guid>
            <category><![CDATA[sessions]]></category>
            <category><![CDATA[authentication]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Fri, 25 Apr 2025 02:48:32 GMT</pubDate>
            <atom:updated>2025-07-19T01:53:28.110Z</atom:updated>
            <content:encoded><![CDATA[<h3>My Experience Choosing the Right Session Storage for Web Apps</h3><p>As a web developer, I am always looking for ways to write clean, well-structured, and scalable code. One topic that often comes up in web application development is how to store session data. Sessions are a crucial element in web applications, especially in authentication systems and session management. The decision on how to store sessions can significantly impact the performance, security, and scalability of the applications we build.</p><figure><img alt="Session Storage, image by freepik." src="https://cdn-images-1.medium.com/max/1024/1*zkdcNXudFAEXPtnFrvxqrQ.jpeg" /><figcaption>Image by freepik</figcaption></figure><p>In this article, I will discuss two main approaches to session storage in web applications: <strong>file-based sessions</strong> and <strong>database-based sessions</strong>. We will explore their advantages, disadvantages, and use cases based on my experience as a PHP developer. Hopefully, after reading this article, you can make a more informed decision when choosing the right session driver for your project.</p><h3>Introduction: The Importance of Session Storage in Web Applications</h3><p>Before diving deeper into the comparison between file sessions and database sessions, let’s first understand why sessions are important. In web applications, sessions are used to store temporary data related to active users. Typically, sessions store authentication information, user preferences, or other states that need to persist during a session.</p><p>For example, when a user logs into an application, we want to store data such as the user ID or login status in the session. This way, the user doesn’t have to log in again every time they load a new page. However, to make this session system work effectively, we need to carefully consider how and where this session data will be stored. This decision affects application performance, security, and ease of session data management.</p><h3>Technical Explanation: File Session vs. Database Session</h3><h3>File Session</h3><p>File-based sessions are the traditional approach where session data is stored in files on the server. Typically, these files are stored in a specific directory accessible by the server. For instance, in PHP, session files are stored in /tmp or a directory configured in the php.ini file.</p><p>Each session is usually stored in a separate file with a unique name (e.g., based on the session ID). When a user accesses the application, the server reads the corresponding session file to retrieve the stored data.</p><p><strong>How File Sessions Work:</strong></p><ol><li>The PHP server generates a file with a unique ID for each session.</li><li>Session data is stored in this file.</li><li>When an HTTP request comes in, the session ID is sent via a cookie or URL parameter.</li><li>The server opens the session file based on the ID and loads the stored data.</li></ol><h3>Database Session</h3><p>In contrast, database sessions store session data in a database table rather than in files. This is a more modern approach and is often used in applications requiring greater scalability. Session data is stored as rows in a database table, with columns recording information such as the session ID, user ID, last activity time, and other session data.</p><p><strong>How Database Sessions Work:</strong></p><ol><li>The PHP server generates a session ID, similar to file sessions.</li><li>Session data is stored in a database table.</li><li>When a request comes in, the session ID is used to look up the corresponding data in the database.</li><li>Database sessions can include validation mechanisms such as expiration time or last activity time.</li></ol><h3>Comparison / Evaluation</h3><p>Now, let’s dive into the technical aspects: how these two approaches compare in several key areas.</p><h4>1. Performance</h4><p><strong>File Sessions:</strong> File sessions tend to be faster in small applications or on servers with only a few users. Since the data is stored in local files, there is no additional overhead from database queries. This makes session data access very fast.</p><p>However, issues arise as the application grows. If the number of users increases, the number of files to manage also grows, which can slow down the server-especially on shared hosting or servers handling many concurrent requests.</p><p><strong>Database Sessions:</strong> On the other hand, database sessions offer more stable performance in large applications with many users. Databases are designed to handle numerous queries and can be optimized for indexing, caching, and complex queries.</p><p>However, there is additional overhead because every time session data needs to be accessed, the server must query the database. For applications with extremely high request volumes, this can be slightly slower than file sessions.</p><h4>2. Security</h4><p><strong>File Sessions:</strong> One challenge with file sessions is managing these files securely. If session files are not properly protected, there is a risk of unauthorized access. This is especially true for applications hosted on shared servers, where access to session files can become a security concern.</p><p><strong>Database Sessions:</strong> Database sessions are generally more secure because session data is stored in a database with stricter access controls. Additionally, session data can be encrypted in the database for an extra layer of security.</p><p>However, it’s important to note that storing sessions in a database is not entirely risk-free. The database must also be well-secured, and session encryption is crucial for protecting sensitive data.</p><h4>3. Scalability</h4><p><strong>File Sessions:</strong> File sessions have limited scalability, especially in large applications or those running on multiple servers. If an application runs on several servers, each server needs equal access to the session files. One solution is to use a distributed storage system like NFS (Network File System), but this can get complicated.</p><p><strong>Database Sessions:</strong> Database sessions excel in scalability, particularly when an application spans multiple servers. By storing sessions in a database, we can easily share sessions across servers without worrying about file synchronization.</p><h4>4. Maintenance</h4><p><strong>File Sessions:</strong> Maintaining file sessions is relatively simple since it only involves managing files. However, if there are a large number of session files, cleaning up expired sessions can become challenging. PHP has a garbage collector to help, but sometimes additional configuration is needed.</p><p><strong>Database Sessions:</strong> Maintaining database sessions is more complex because it requires managing tables and queries. However, this approach offers greater flexibility in session data management, such as adding columns for extra information, querying active sessions, and more.</p><h3>Case Study from Personal Experience</h3><p>When developing the authentication system, I initially used file sessions. This worked well during development and for applications with a limited number of users. However, as the application grew, I encountered performance issues when the number of users increased and the server had to handle more requests.</p><p>Eventually, I switched to <strong>database sessions</strong>. I created a sessions table in the database and stored session data there. This greatly helped in managing sessions across servers and provided more flexibility in session data management. Additionally, I could implement validation mechanisms such as expiration time and last activity time, which were very useful for keeping sessions secure.</p><h3>Conclusion and Best Practices</h3><p>So, when should you use file sessions, and when should you use database sessions? Here are some tips based on my experience:</p><ul><li><strong>Use file sessions</strong> if your application is small and doesn’t require server distribution or if you’re not overly concerned about long-term scalability. File sessions are suitable for applications with a limited number of users that don’t require highly secure or distributed session storage.</li><li><strong>Use database sessions</strong> if your application requires greater scalability and flexibility. Database sessions are more secure, easier to maintain, and more efficient for larger applications or those hosted on multiple servers.</li></ul><p>Some implementation tips:</p><ul><li>Always encrypt sensitive session data.</li><li>Consider using sessions with expiration times to reduce database or file system load.</li><li>Ensure garbage collection works properly, whether for file sessions or database sessions.</li></ul><p>I hope this article provides valuable insights and helps you make the right decision for your application’s session system!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a390f2cfe308" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Install Virtualmin on Ubuntu 24.04 VPS (Beginner-Friendly Guide)]]></title>
            <link>https://towardsdev.com/how-to-install-virtualmin-on-ubuntu-24-04-vps-beginner-friendly-guide-b8e7369475ef?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/b8e7369475ef</guid>
            <category><![CDATA[virtualmin]]></category>
            <category><![CDATA[servers]]></category>
            <category><![CDATA[control-panel]]></category>
            <category><![CDATA[vps]]></category>
            <category><![CDATA[ubuntu]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Sat, 22 Mar 2025 07:24:11 GMT</pubDate>
            <atom:updated>2025-03-24T18:03:17.575Z</atom:updated>
            <content:encoded><![CDATA[<p>Setting up and managing a web server manually can be time-consuming and complicated, especially for those unfamiliar with Linux commands. Virtualmin simplifies this process by providing an easy-to-use web-based control panel for managing domains, databases, email accounts, and server configurations.</p><p>This guide will walk you through the complete installation of Virtualmin on an Ubuntu 24.04 VPS. No advanced technical knowledge is required — just follow each step carefully.</p><h3>Step 1: Prepare the Server</h3><p>Before starting the installation, make sure your server meets the following requirements:</p><ul><li>A fresh installation of Ubuntu 24.04 without additional software.</li><li>Root access or a user with sudo privileges.</li><li>At least 1GB of RAM (2GB or more is recommended for better performance).</li><li>A fully qualified domain name (FQDN), such as server.example.com.</li></ul><h4>Setting the Hostname</h4><p>Virtualmin requires a properly configured hostname for smooth operation. To set it, run the following command:</p><pre>sudo hostnamectl set-hostname server.yourdomain.com</pre><p>Replace server.yourdomain.com with your actual domain or subdomain.</p><h3>Step 2: Update the System</h3><p>To ensure system stability, update all existing packages before proceeding with the installation. Run:</p><pre>sudo apt update &amp;&amp; sudo apt upgrade -y</pre><p>This step may take a few minutes depending on the server’s performance and internet speed.</p><h3>Step 3: Install Virtualmin</h3><p>The easiest way to install Virtualmin is by using the official install script.</p><h4>Download and Run the Installer</h4><p>Run the following command:</p><pre>sudo sh -c &quot;$(curl -fsSL https://software.virtualmin.com/gpl/scripts/virtualmin-install.sh)&quot; -- --bundle LAMP</pre><p>This script will:</p><ul><li>Install <strong>Webmin &amp; Virtualmin</strong></li><li>Set up <strong>Apache, MySQL/MariaDB, PHP, and Postfix</strong></li><li>Optimize your server for <strong>web hosting</strong></li></ul><h4>Alternative Installation (Using Nginx Instead of Apache)</h4><p>If you prefer Nginx instead of Apache, use this command instead:</p><pre>sudo sh -c &quot;$(curl -fsSL https://software.virtualmin.com/gpl/scripts/virtualmin-install.sh)&quot; -- --bundle LEMP</pre><h4>Wait for the Installation to Complete</h4><p>The installation process usually takes between 10 to 20 minutes. If prompted, confirm the process by typing Y and pressing Enter.</p><h3>Step 4: Access Virtualmin Web Interface</h3><p>Once installed, you can access Virtualmin through your web browser.</p><h4>Open Virtualmin in Your Browser</h4><pre>https://YOUR-SERVER-IP:10000</pre><p><em>(Replace </em><em>YOUR-SERVER-IP with your actual server&#39;s IP address.)</em></p><h4>Login Details</h4><ul><li><strong>Username:</strong> root</li><li><strong>Password:</strong> <em>(Your root password for the server)</em></li></ul><p><strong>SSL Warning:</strong> Your browser might show a security warning because Virtualmin uses a self-signed SSL certificate. Click <strong>“Advanced”</strong> and then <strong>“Proceed”</strong> to continue.</p><h3>Step 5: Complete Virtualmin Setup</h3><p>After logging in, you’ll see the <strong>Post-Installation Wizard</strong>. Follow these steps:</p><p><strong>Memory Usage Optimization</strong></p><ul><li>If your VPS has <strong>less than 2GB RAM</strong>, enable memory optimizations.</li><li>Otherwise, select “No” and continue.</li></ul><p><strong>Database Selection</strong></p><ul><li>Keep <strong>MySQL/MariaDB</strong> as the default option.</li></ul><p><strong>DNS and Email Configuration</strong></p><ul><li>If you plan to use <strong>email hosting</strong>, enable it.</li><li>Otherwise, disable mail processing to save server resources.</li></ul><p>4️⃣ <strong>Click “Re-Check and Refresh Configuration”</strong></p><ul><li>This will verify that your server is correctly set up.</li></ul><h3>Step 6: Create Your First Website (Optional)</h3><p>If you want to <strong>host a website</strong>, follow these steps:</p><ol><li>In Virtualmin, go to <strong>“Create Virtual Server”</strong>.</li><li>Enter your <strong>domain name</strong> (e.g., example.com).</li><li>Set an <strong>Admin Password</strong> for the website.</li><li>Click <strong>“Create Server”</strong> — your website is now ready! 🎉</li></ol><h3>Step 7: Secure Virtualmin (Recommended)</h3><p>To enhance security, follow these steps:</p><p><strong>Change the Default Webmin Port (10000)</strong></p><ul><li>Go to <strong>Webmin &gt; Webmin Configuration &gt; Ports and Addresses</strong></li><li>Change <strong>10000</strong> to a custom port (e.g., <strong>2345</strong>)</li></ul><p><strong>Enable a Firewall</strong></p><ul><li>Go to <strong>Networking &gt; Linux Firewall</strong></li><li>Allow only necessary ports (<strong>22, 80, 443, and your custom Webmin port</strong>)</li></ul><p><strong>Enable SSL with Let’s Encrypt</strong></p><ul><li>Go to <strong>Server Configuration &gt; Manage SSL Certificate</strong></li><li>Request a free SSL certificate for your domain</li></ul><h3>Conclusion</h3><p>Virtualmin simplifies server management by providing a web-based control panel for website hosting, database management, and email services. By following this guide, you have successfully installed and configured Virtualmin on Ubuntu 24.04.</p><p>Now, you can:</p><ul><li>Host and manage multiple websites.</li><li>Set up and configure databases easily.</li><li>Manage email accounts and DNS settings.</li></ul><p>For additional configuration and optimization, explore the Virtualmin documentation or community forums.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8e7369475ef" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/how-to-install-virtualmin-on-ubuntu-24-04-vps-beginner-friendly-guide-b8e7369475ef">How to Install Virtualmin on Ubuntu 24.04 VPS (Beginner-Friendly Guide)</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automating Deployment with GitLab CI/CD and Deployer for Laravel Applications: A Simple Approach]]></title>
            <link>https://towardsdev.com/automating-deployment-with-gitlab-ci-cd-and-deployer-for-laravel-applications-a-simple-approach-a79cf8f84ea8?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/a79cf8f84ea8</guid>
            <category><![CDATA[gitlab-ci]]></category>
            <category><![CDATA[vps]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[gitlab]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Sat, 15 Mar 2025 08:12:03 GMT</pubDate>
            <atom:updated>2025-03-24T18:03:06.985Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Automating Deployment with GitLab CI/CD and Deployer for Laravel Applications: A Simple Approach" src="https://cdn-images-1.medium.com/max/1024/1*W4OWTqaOdsueUxzpjrgd3A.jpeg" /><figcaption>Image by <a href="https://www.freepik.com/free-vector/gradient-devops-illustration_25225456.htm#fromView=search&amp;page=1&amp;position=2&amp;uuid=48c35d88-8caa-4e1d-b329-fb1cff152e9c&amp;query=devops">freepik</a></figcaption></figure><p>In modern software development, Continuous Integration and Continuous Deployment (CI/CD) are essential practices to ensure that code changes are automatically tested, built, and deployed to production environments. In this article, we’ll explore how to set up a <strong>simple</strong> GitLab CI/CD pipeline using <strong>Deployer</strong>, a deployment tool for PHP applications, to automate the deployment of a Laravel application.</p><p>While this setup provides a straightforward and effective way to deploy your application, it’s important to note that <strong>additional optimizations are required for enhanced security</strong> in production environments. Let’s dive in!</p><h4>Why Use Deployer with GitLab CI/CD?</h4><p>Deployer is a popular PHP deployment tool that simplifies the process of deploying applications to remote servers. It supports various frameworks, including Laravel, and provides a clean and easy-to-use interface for managing deployments. By integrating Deployer with GitLab CI/CD, we can automate the entire deployment process, ensuring that our application is always up-to-date and running smoothly.</p><p>This guide focuses on a <strong>simple setup</strong> to get you started quickly. However, for production-grade security, you should consider additional optimizations, such as stricter SSH configurations, secret management, and access controls.</p><h4>Prerequisites</h4><p>Before we dive into the setup, ensure you have the following:</p><ol><li>A Laravel application hosted on GitLab.</li><li>A production server (e.g., a VPS) with SSH access.</li><li>GitLab CI/CD enabled for your repository.</li><li>SSH keys configured for secure communication between GitLab and your production server.</li></ol><h4>Step 1: Installing deployer</h4><p>Deployer will prompt you with a series of questions. After completing them, you’ll have a deploy.php or deploy.yaml file — your deployment recipe. This file defines hosts, tasks, and dependencies on other recipes. Framework-specific recipes provided by Deployer are based on the common recipe.</p><p>For <strong>recipe language</strong>, type 0 for PHP:</p><pre>Choose recipe language (0 for PHP, 1 for YAML) [0]:</pre><p>And for <strong>project template</strong>, type 12 for Laravel:</p><pre>Choose your project type [0]:<br>...<br>12 - Laravel</pre><p>This will generate a deploy.php file tailored for Laravel applications.</p><h4>Step 2: Setting Up Deployer</h4><p>First, we need to configure Deployer for our Laravel application in the root of your project with the following configuration:</p><pre>&lt;?php<br><br>namespace Deployer;<br><br>require &#39;recipe/laravel.php&#39;;<br>require &#39;recipe/deploy/writable.php&#39;;<br><br>// General configuration<br>set(&#39;application&#39;, &#39;Laravel&#39;);<br>set(&#39;repository&#39;, &#39;git@gitlab.com:username/repo.git&#39;); // Replace with your Git repository URL<br>set(&#39;keep_releases&#39;, 3);<br><br>// Shared files and directories<br>add(&#39;shared_files&#39;, [&#39;.env&#39;]);<br>add(&#39;shared_dirs&#39;, [&#39;storage&#39;]);<br>add(&#39;writable_dirs&#39;, [<br>    &quot;bootstrap/cache&quot;,<br>    &quot;storage&quot;,<br>    &quot;storage/app&quot;,<br>    &quot;storage/framework&quot;,<br>    &quot;storage/logs&quot;,<br>]);<br><br>// Use chmod as an alternative to ACL<br>set(&#39;writable_mode&#39;, &#39;chmod&#39;);<br><br>// Composer options<br>set(&#39;composer_options&#39;, &#39;--verbose --prefer-dist --no-progress --no-interaction --no-dev --optimize-autoloader&#39;);<br><br>// Host for production (main branch)<br>host(&#39;192.168.1.1&#39;) // Replace with your production server IP<br>    -&gt;set(&#39;remote_user&#39;, &#39;root&#39;)<br>    -&gt;set(&#39;branch&#39;, &#39;main&#39;) // Only deploy from the main branch<br>    -&gt;set(&#39;deploy_path&#39;, &#39;/home/username/public_html&#39;); // Replace with your production deployment path<br><br>// Hooks<br>task(&#39;deploy:secrets&#39;, function () {<br>    // Copy .env.example to .env if .env does not exist<br>    if (!file_exists(__DIR__ . &#39;/.env&#39;)) {<br>        copy(__DIR__ . &#39;/.env.example&#39;, __DIR__ . &#39;/.env&#39;);<br>    }<br><br>    upload(&#39;.env&#39;, get(&#39;deploy_path&#39;) . &#39;/shared&#39;);<br>})-&gt;desc(&#39;Upload .env file&#39;);<br><br><br>// Define npm:install task<br>task(&#39;npm:install&#39;, function () {<br>    run(&#39;cd {{release_path}} &amp;&amp; npm install&#39;);<br>})-&gt;desc(&#39;Install npm dependencies&#39;);<br><br>// Define npm:build task<br>task(&#39;npm:build&#39;, function () {<br>    run(&#39;cd {{release_path}} &amp;&amp; npm run build&#39;);<br>})-&gt;desc(&#39;Run npm build&#39;);<br><br>task(&#39;deploy:build&#39;, [<br>    &#39;npm:install&#39;,<br>    &#39;npm:build&#39;,<br>])-&gt;desc(&#39;Build assets&#39;);<br><br>task(&#39;deploy&#39;, [<br>    &#39;deploy:prepare&#39;,<br>    &#39;deploy:secrets&#39;,<br>    &#39;deploy:vendors&#39;,<br>    &#39;deploy:shared&#39;,<br>    &#39;artisan:storage:link&#39;,<br>    &#39;artisan:view:cache&#39;,<br>    &#39;artisan:config:cache&#39;,<br>    &#39;artisan:route:cache&#39;,<br>    &#39;artisan:migrate&#39;,<br>    &#39;artisan:queue:restart&#39;,<br>    &#39;deploy:build&#39;,<br>    &#39;deploy:publish&#39;,<br>    &#39;deploy:unlock&#39;,<br>])-&gt;desc(&#39;Deploy your project&#39;);<br><br>// [Optional] Automatically unlock if deployment fails<br>after(&#39;deploy:failed&#39;, &#39;deploy:unlock&#39;);<br><br>// Rollback task<br>task(&#39;rollback&#39;, function () {<br>    $releases = get(&#39;releases_list&#39;);<br>    if (isset($releases[1])) {<br>        $releaseDir = &quot;{{deploy_path}}/releases/{$releases[1]}&quot;;<br>        run(&quot;ln -nfs $releaseDir {{deploy_path}}/current&quot;);<br>        run(&quot;rm -rf {{deploy_path}}/releases/{$releases[0]}&quot;);<br>        writeln(&quot;Rollback to `{$releases[1]}` release was successful.&quot;);<br>    } else {<br>        writeln(&quot;No more releases to rollback to.&quot;);<br>    }<br>})-&gt;desc(&#39;Rollback to previous release&#39;);</pre><p>Key Points in deploy.php:</p><ol><li><strong>Shared Files and Directories</strong>: The .env file and storage directory are shared across releases to maintain configuration and data consistency.</li><li><strong>Production Host Configuration</strong>: Replace 123.456.789.0 and /home/username/public_html with your server’s IP and deployment path.</li><li><strong>Environment Secrets</strong>: The deploy:secrets task handles the .env file securely by uploading it to the shared directory.</li></ol><h4>Step 3: Configuring GitLab CI/CD</h4><p>Next, we’ll set up the GitLab CI/CD pipeline to automate the build and deployment process. Create a .gitlab-ci.yml file in the root of your project:</p><pre>stages:<br>  - build<br>  - deploy<br><br># Cache node_modules to speed up builds<br>cache:<br>  key: ${CI_COMMIT_REF_SLUG}<br>  paths:<br>    - node_modules/<br><br># Build stage to compile assets (JavaScript/CSS)<br>build_assets:<br>  stage: build<br>  image: node:latest<br>  script:<br>    - npm install<br>    - npm run build<br>  artifacts:<br>    paths:<br>      - public/  # Save build results in the public folder<br>    expire_in: 3 days  # Delete artifacts after 3 days<br>  only:<br>    - main  # Only run for the main branch<br><br># Deploy stage to production<br>deploy_production:<br>  stage: deploy<br>  image: php:8.3-cli<br>  before_script:<br>    - apt-get update &amp;&amp; apt-get install -y git unzip openssh-client rsync<br>    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer<br>    - composer global require deployer/deployer --no-progress --no-interaction<br>    - mkdir -p ~/.ssh<br>    - echo &quot;$SSH_PRIVATE_KEY&quot; | tr -d &#39;\r&#39; &gt; ~/.ssh/id_rsa<br>    - chmod 600 ~/.ssh/id_rsa<br>    - echo &quot;$SSH_KNOWN_HOSTS&quot; &gt; ~/.ssh/known_hosts<br>    - chmod 644 ~/.ssh/known_hosts<br>  script:<br>    - export PATH=&quot;$PATH:$HOME/.composer/vendor/bin&quot;<br>    - dep deploy --branch=main<br>  only:<br>    - main<br>  environment:<br>    name: production<br>    url: https://yourproduction.url  # Replace with your production URL<br>  cache: {}  # Disable cache for the deploy stage</pre><p>Key Points in .gitlab-ci.yml:</p><ol><li><strong>Build Stage</strong>: The build_assets job compiles JavaScript and CSS assets using Node.js. The artifacts are stored in the public folder and expire after one week.</li><li><strong>Deploy Stage</strong>: The deploy_production job installs dependencies, sets up SSH keys, and runs the dep deploy command to deploy the application to the production server.</li><li><strong>Environment Variables</strong>: Ensure you set the SSH_PRIVATE_KEY and SSH_KNOWN_HOSTS variables in GitLab’s CI/CD settings for secure SSH communication.</li></ol><h4>How to Add SSH_PRIVATE_KEY to GitLab CI/CD</h4><p>To allow GitLab to connect to the server via SSH for deployment using Deployer, you need to add the private key (SSH_PRIVATE_KEY) to GitLab CI/CD. Follow these steps:</p><p>1. Generate an SSH Key Locally</p><p>If you don’t already have an SSH key, generate a new one on your local machine or deployment server:</p><pre>ssh-keygen -t rsa -b 4096 -C &quot;gitlab-deployer&quot;</pre><ul><li><strong>-t rsa</strong>: Uses the RSA algorithm.</li><li><strong>-b 4096</strong>: Generates a 4096-bit key for higher security.</li><li><strong>-C &quot;gitlab-deployer&quot;</strong>: Adds a comment for identification.</li></ul><p>When prompted for the file location, press Enter to use the default (~/.ssh/id_rsa). If you prefer a different name, specify it when prompted.</p><p>2. Copy the Private Key</p><p>After generating the key, display the private key:</p><pre>cat ~/.ssh/id_rsa</pre><p>Copy the output (starting with -----BEGIN OPENSSH PRIVATE KEY----- and ending with -----END OPENSSH PRIVATE KEY-----).</p><p>3. Add the Private Key to GitLab CI/CD</p><ol><li>Open your <strong>GitLab repository</strong>.</li><li>Navigate to <strong>Settings</strong> → <strong>CI/CD</strong>.</li><li>Expand the <strong>Variables</strong> section.</li><li>Click <strong>Add variable</strong> and fill in the details:</li></ol><ul><li><strong>Key</strong>: SSH_PRIVATE_KEY</li><li><strong>Value</strong>: Paste the copied private key.</li><li><strong>Type</strong>: <strong>Variable</strong></li><li><strong>Masked</strong>: <strong>Enable</strong> (to hide it from logs)</li><li><strong>Protected</strong>: <strong>Enable</strong> (so it can only be accessed in protected branches, like main)</li></ul><p>4. Add the Public Key to the Server</p><p>Copy the public key so the server recognizes GitLab as a trusted source:</p><pre>cat ~/.ssh/id_rsa.pub</pre><p>Copy the output and add it to the ~/.ssh/authorized_keys file on your target server</p><pre>echo &quot;your_public_key_here&quot; &gt;&gt; ~/.ssh/authorized_keys<br>chmod 600 ~/.ssh/authorized_keys</pre><p>5. Test SSH Connection from GitLab Runner</p><p>To verify that GitLab can connect to the server, run the following command from the GitLab CI/CD Runner:</p><pre>ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no user@your.server.ip</pre><p>If you can log in without entering a password, the SSH configuration is correct.</p><h4>How to Get SSH_KNOWN_HOSTS</h4><p>To securely connect to your server, you need to add the server’s SSH fingerprint to the SSH_KNOWN_HOSTS variable. Here&#39;s how to get it:</p><p>Run the following command on your local machine or CI/CD environment:</p><pre>ssh-keyscan -t rsa your.server.ip</pre><p>Copy the output and add it as the value of the SSH_KNOWN_HOSTS variable in GitLab’s CI/CD settings.</p><h4>Step 4: Securing Your Deployment</h4><p>This setup provides a simple and effective way to deploy your application. However, <strong>additional optimizations are required for enhanced security</strong> in production environments. Here are some recommendations:</p><ol><li><strong>SSH Key Management</strong>:</li></ol><ul><li>Use a dedicated deployment user with limited permissions instead of the root user.</li><li>Restrict SSH access to specific IP addresses using firewall rules (e.g., ufw).</li><li>Use SSH certificates or multi-factor authentication (MFA) for added security.</li></ul><p><strong>2. Environment Variables</strong>:</p><ul><li>Avoid hardcoding sensitive data in your .env file. Use GitLab’s CI/CD variables or a secrets management tool like HashiCorp Vault.</li><li>Encrypt sensitive data before storing it in version control.</li></ul><p><strong>3. Deployer Configuration</strong>:</p><ul><li>Use writable_mode with acl if your server supports it, as it provides better permission handling than chmod.</li><li>Implement rollback mechanisms in case of deployment failures.</li></ul><p><strong>4. CI/CD Pipeline Security</strong>:</p><ul><li>Restrict access to the GitLab CI/CD settings to authorized personel only.</li><li>Regularly review and update your pipeline configuration to address new security vulnerabilities.</li></ul><h4>Step 5: Running the Pipeline</h4><p>Once everything is set up, push your changes to the main branch. GitLab will automatically trigger the CI/CD pipeline:</p><ol><li>The build_assets job will compile your assets.</li><li>The deploy_production job will deploy your application to the production server.</li></ol><p>You can monitor the pipeline’s progress in GitLab’s CI/CD section.</p><h4>Conclusion</h4><p>By combining GitLab CI/CD with Deployer, we’ve created a <strong>simple and effective</strong> deployment pipeline for our Laravel application. This setup ensures that every change pushed to the main branch is automatically tested, built, and deployed to production, saving time and reducing the risk of human error.</p><p>However, it’s important to remember that <strong>this is a basic setup</strong>. For production environments, additional security optimizations are necessary to protect your application and infrastructure. Always follow best practices for SSH key management, secret handling, and access control.</p><p>Feel free to customize the deployer.php and .gitlab-ci.yml files to suit your specific needs. If you found this article helpful, don’t forget to share it with your team and follow me on <a href="https://medium.com/@muhalvin">Medium</a> for more tutorials.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a79cf8f84ea8" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/automating-deployment-with-gitlab-ci-cd-and-deployer-for-laravel-applications-a-simple-approach-a79cf8f84ea8">Automating Deployment with GitLab CI/CD and Deployer for Laravel Applications: A Simple Approach</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Choosing the Right Off-White Colors for a Comfortable Website Background]]></title>
            <link>https://towardsdev.com/choosing-the-right-off-white-colors-for-a-comfortable-website-background-4d3a24070db6?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d3a24070db6</guid>
            <category><![CDATA[web-design]]></category>
            <category><![CDATA[colors]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Wed, 05 Mar 2025 03:58:10 GMT</pubDate>
            <atom:updated>2025-03-05T14:46:14.919Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Photo by &lt;a href=”https://unsplash.com/@der_maik_?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Maik Jonietz&lt;/a&gt; on &lt;a href=”https://unsplash.com/photos/program-script-digital-wallpaper-_yMciiStJyY?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;" src="https://cdn-images-1.medium.com/max/1024/1*_qnTNNArr9FgOgey9P-RzQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@der_maik_?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Maik Jonietz</a> on <a href="https://unsplash.com/photos/program-script-digital-wallpaper-_yMciiStJyY?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><p>In web design, choosing the right background color is crucial for user comfort. While pure white (#FFFFFF) is often used for its clean and minimalist appearance, it can be too bright and cause eye strain, especially during prolonged screen exposure. To address this issue, softer white alternatives — often called <strong>off-white</strong> or <strong>soft white</strong> — can be a better choice.</p><h3>Why Not Use Pure White?</h3><p>Pure white has the highest brightness level, which can create excessive contrast when paired with black or dark-colored text. This strong contrast may lead to discomfort and fatigue, particularly when reading long-form content or browsing a website for an extended period.</p><p>Instead, <strong>off-white shades</strong> provide a gentler, more visually pleasant alternative while maintaining a clean and professional look.</p><h3>Best Off-White Colors for Web Design</h3><p>Here are some soft white colors that are more comfortable for the eyes compared to pure white:</p><ul><li><strong>Snow (#FAFAFA)</strong> — A very soft white that is almost indistinguishable from pure white but appears less harsh. It provides a clean and minimalist look while being easier on the eyes.</li><li><strong>Ivory (#FFFFF0)</strong> — A slightly warm white with a hint of yellow, giving it a natural and cozy feel. This color works well in designs that aim for warmth and elegance.</li><li><strong>Seashell (#FFF5EE)</strong> — A soft white with subtle pink undertones, making it look warm and inviting. This shade is great for websites that want to create a welcoming atmosphere.</li><li><strong>Ghost White (#F8F8FF)</strong> — A white with a cool blue tint that gives an airy and refreshing feel. It’s an excellent choice for modern, professional, or technology-focused designs.</li><li><strong>Alabaster (#F2F2F2)</strong> — A very light grayish-white that appears softer than pure white. This shade is ideal for reducing contrast and improving readability, especially on text-heavy websites.</li></ul><h3>Recommended Background Colors for Websites</h3><p>When designing a website, the goal is to find a background color that reduces eye strain while keeping a modern and clean aesthetic. The following two shades work exceptionally well for web backgrounds:</p><ol><li><strong>#FAFAFA (Snow)</strong> — This color is very close to pure white but appears softer and less glaring. It’s ideal for <strong>minimalist designs</strong> that still want a crisp look without excessive brightness.</li><li><strong>#F2F2F2 (Alabaster)</strong> — This is a very light gray that resembles white but is much gentler on the eyes. It helps reduce contrast while maintaining readability, making it perfect for text-heavy websites.</li></ol><p>Both of these colors offer a balance between readability and comfort, making them excellent choices for blog backgrounds, content-heavy pages, and user interfaces that require prolonged engagement.</p><h3>How to Apply Off-White Colors in Web Design</h3><h3>1. Using CSS to Set Background Colors</h3><p>To apply an off-white background color in your website, you can modify your CSS styles like this:</p><pre>body {<br>    background-color: #FAFAFA; /* Soft white background */<br>    color: #333; /* Dark gray text for better readability */<br>    font-family: Arial, sans-serif;<br>}</pre><p>If you prefer a slightly darker but still soft background, use:</p><pre>body {<br>    background-color: #F2F2F2; /* Alabaster background */<br>    color: #222; /* Slightly darker text for contrast */<br>}</pre><h3>2. Combining with Other Colors</h3><p>Off-white shades work well with a variety of accent colors. Here are some pairing recommendations:</p><ul><li><strong>For a modern look</strong>: Combine <strong>#FAFAFA</strong> with black or dark gray text and blue accent colors.</li><li><strong>For a warm aesthetic</strong>: Use <strong>#FFFFF0 (Ivory)</strong> with brown or gold elements.</li><li><strong>For a clean, professional feel</strong>: Pair <strong>#F8F8FF (Ghost White)</strong> with navy blue or dark green.</li></ul><h3>3. Creating a Light Mode/Dark Mode Toggle</h3><p>For a better user experience, consider offering both <strong>light mode and dark mode</strong> options. Here’s a simple way to toggle between an off-white and dark background using JavaScript:</p><pre>&lt;button id=&quot;toggleTheme&quot;&gt;Toggle Dark Mode&lt;/button&gt;<br><br>&lt;script&gt;<br>document.getElementById(&#39;toggleTheme&#39;).addEventListener(&#39;click&#39;, function() {<br>    document.body.classList.toggle(&#39;dark-mode&#39;);<br>});<br>&lt;/script&gt;<br><br>&lt;style&gt;<br>body {<br>    background-color: #FAFAFA;<br>    color: #333;<br>    transition: background 0.3s ease, color 0.3s ease;<br>}<br><br>.dark-mode {<br>    background-color: #222;<br>    color: #FAFAFA;<br>}<br>&lt;/style&gt;</pre><p>This allows users to switch between a light and dark background based on their preference, making your website more user-friendly.</p><h3>Conclusion</h3><p>Selecting the right background color is a critical aspect of web design that directly impacts user experience. While pure white may seem like a default choice, it can be too bright and cause eye fatigue. By using <strong>off-white shades like #FAFAFA (Snow) or #F2F2F2 (Alabaster)</strong>, you can create a more <strong>comfortable, readable, and visually appealing</strong> website.</p><p>If you’re designing a website with readability and user comfort in mind, consider switching to a <strong>soft white background</strong> for a better overall experience. Whether you’re working on a personal blog, an e-commerce site, or a corporate webpage, the right color choices can make a significant difference in user engagement and satisfaction.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d3a24070db6" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/choosing-the-right-off-white-colors-for-a-comfortable-website-background-4d3a24070db6">Choosing the Right Off-White Colors for a Comfortable Website Background</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CORS: Why Browsers Block Requests and How to Fix it]]></title>
            <link>https://towardsdev.com/cccors-why-browsers-block-requests-and-how-to-fix-it-6eaad7fcb301?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/6eaad7fcb301</guid>
            <category><![CDATA[cors]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[backend]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Tue, 24 Dec 2024 13:40:25 GMT</pubDate>
            <atom:updated>2024-12-24T17:43:57.344Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>CORS: Why Browsers Block Requests and How to Fix it.</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*onfdajD2JhFcKjiCHWhKew.png" /></figure><p>Imagine this: you run a coffee shop called <strong>BrewCafe</strong>, and you need some ingredients from a supplier called <strong>CoffeeBeansInc</strong>. You send a request for beans, but they don’t respond. Why? Because the supplier doesn’t recognize you and won’t share their beans without permission.</p><p>This is the basic idea behind <strong>CORS</strong> (Cross-Origin Resource Sharing). Let’s break it down step by step!</p><h4>What is CORS?</h4><p>CORS is a security rule built into browsers. It ensures that one website cannot access data from another website without permission.</p><p>The browser will block a request if:</p><ol><li>The origin of the request (e.g., brewcafe.com) is different from the origin of the server receiving the request (e.g., api.coffeebeansinc.com).</li><li>The server hasn’t granted permission to share the data.</li></ol><p>The browser acts as a gatekeeper, making sure that only authorized requests can go through.</p><h4>Example Problem</h4><ol><li><strong>BrewCafe</strong> is hosted at <a href="https://brewcafe.com.">https://brewcafe.com.</a></li><li>They try to fetch ingredient data from their supplier’s API at <a href="https://api.coffeebeansinc.com.">https://api.coffeebeansinc.com.</a></li><li>The browser notices that the origins (the domain names) are different.</li></ol><p>As a result, the browser blocks the request with an error like this:</p><blockquote><em>Access to fetch at ‘https://api.coffeebeansinc.com’ from origin ‘https://brewcafe.com’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present.</em></blockquote><p>This means the server at <strong>CoffeeBeansInc</strong> didn’t provide the necessary permission for <strong>BrewCafe</strong> to access the data.</p><h4>Why is CORS Important?</h4><p>CORS is a safety feature. Without it, malicious websites could abuse a browser’s ability to make requests.</p><p>For example, imagine you’re logged into your online banking account (banking.com). Without CORS, a harmful website could potentially send requests to banking.com using your credentials, accessing sensitive information or transferring money without your permission.</p><p>CORS helps protect users from this kind of threat by enforcing a rule called the <strong>Same-Origin Policy</strong>. This rule says:</p><ul><li>Only websites from the “same house” (same domain, protocol, and port) can exchange data.</li></ul><h4>How Does CORS Work?</h4><p>For <strong>BrewCafe</strong> to successfully access data from <strong>CoffeeBeansInc</strong>, the server at <strong>CoffeeBeansInc</strong> needs to say, <strong>“Yes, it’s okay for you to fetch this data.”</strong></p><p>The server grants permission by sending a special note called a <strong>CORS header</strong>.</p><h4>How to Fix a CORS Error</h4><p>When you encounter a CORS issue, it means the server isn’t sending the necessary permissions. Here’s how to fix it:</p><p>1. Add the Right Headers on the Server</p><p>The server needs to send headers to grant permission:</p><p>Allow any origin:</p><pre>Access-Control-Allow-Origin: *</pre><p>This allows requests from any website.</p><p>Allow only specific origins:</p><pre>Access-Control-Allow-Origin: https://brewcafe.com</pre><p>This is more secure, as it only allows a specific website to access the data.</p><h4>2. Handle Preflight Requests</h4><p>When making more complex requests (such as POST, PUT, or custom headers), the browser sends a <strong>preflight request</strong> before the actual request. This is done using the OPTIONS method. It’s like asking the server, <strong>“Hey, are you okay with this request?”</strong></p><p>For example, if <strong>BrewCafe</strong> tries to send a POST request with custom headers, the browser first sends an OPTIONS request to <strong>CoffeeBeansInc</strong> to check if the server allows such requests.</p><p>The server needs to respond with the following headers to indicate it’s okay to proceed:</p><pre>Access-Control-Allow-Methods: GET, POST, OPTIONS<br>Access-Control-Allow-Headers: Content-Type, Authorization</pre><p>This tells the browser that the server is okay with the methods (GET, POST, OPTIONS) and headers (Content-Type, Authorization) the frontend intends to use.</p><h4>3. Use a Proxy for Local Development</h4><p>During local development, if the backend server isn’t yet set up to handle CORS, you can use a <strong>proxy</strong>. This acts as a middleman to forward requests from your frontend to the backend, making it appear as though they are from the same origin.</p><h4>CORS Can’t Be Bypassed</h4><p>While you might be tempted to use browser extensions or modify browser settings to bypass CORS during development, these are not solutions for production environments.</p><p>The proper way to fix CORS issues is to configure the server correctly to handle the requests.</p><h4>Conclusion</h4><p>CORS is a mechanism that protects your data while making sure that only authorized websites can interact with your server.</p><p>If you encounter a CORS error:</p><ol><li>Don’t panic — this is not a bug in your browser.</li><li>Fix it by adding the correct headers on the server.</li><li>Understand that CORS is an important security measure for protecting users online.</li></ol><p>With the right setup, communication between <strong>BrewCafe</strong> and <strong>CoffeeBeansInc</strong> will run smoothly, and you can get the ingredients you need without any issues! ☕️</p><h4>Additional Notes</h4><p>Be cautious when using Access-Control-Allow-Origin: * in production environments. Allowing all origins to access your server can be risky, as it opens the door to any website making requests to your server, potentially leading to security vulnerabilities. It’s generally safer to specify trusted domains that are allowed to make requests.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6eaad7fcb301" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/cccors-why-browsers-block-requests-and-how-to-fix-it-6eaad7fcb301">CORS: Why Browsers Block Requests and How to Fix it</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Setting Up a Laravel 11 with Docker]]></title>
            <link>https://towardsdev.com/setting-up-a-laravel-11-with-docker-522eebbef82d?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/522eebbef82d</guid>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[docker-compose]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Sun, 22 Dec 2024 05:07:25 GMT</pubDate>
            <atom:updated>2025-01-04T15:03:16.530Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Docker logo" src="https://cdn-images-1.medium.com/max/1024/1*krkTwOsazw1wNQgM1TOjNw.png" /></figure><p>In this guide, we’ll walk through the steps to create a Dockerized Laravel 11 application with a MySQL database. We’ll use docker-compose to set up the application and database services, and configure Apache with PHP to serve the Laravel application.</p><h3>Step 1: Create the Dockerfile</h3><p>The Dockerfile defines the steps needed to set up the environment for our Laravel application. It installs the necessary PHP extensions, configures Apache, and installs Composer to manage dependencies.</p><p><strong>Dockerfile</strong></p><pre># Use PHP image with Apache<br>FROM php:8.2-apache<br><br># Copy customized Apache configuration<br>COPY 000-default.conf /etc/apache2/sites-available/000-default.conf<br><br># Install required system dependencies<br>RUN apt-get update &amp;&amp; apt-get install -y \<br>    libpng-dev \<br>    libjpeg-dev \<br>    libfreetype6-dev \<br>    zip \<br>    unzip \<br>    git \<br>    curl \<br>    libzip-dev \<br>    libicu-dev \<br>    ca-certificates \<br>    lsb-release \<br>    gnupg \<br>    &amp;&amp; docker-php-ext-configure gd --with-freetype --with-jpeg \<br>    &amp;&amp; docker-php-ext-install gd pdo pdo_mysql intl zip<br><br># Install Node.js and npm<br>RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - \<br>    &amp;&amp; apt-get install -y nodejs<br><br># Enable Apache mod_rewrite<br>RUN a2enmod rewrite<br><br># Copy application into the image<br>COPY . /var/www/html<br><br># Set working directory<br>WORKDIR /var/www/html<br><br># Install Composer<br>COPY --from=composer:latest /usr/bin/composer /usr/bin/composer<br><br># Install Composer dependencies<br>RUN git config --global --add safe.directory /var/www/html<br>RUN composer install --no-interaction --no-plugins --no-scripts --prefer-dist<br><br># Set file ownership for Apache<br>RUN chown -R www-data:www-data /var/www/html<br>RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache<br>RUN chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache<br><br># Expose port 80<br>EXPOSE 80</pre><p>Explanation of the Dockerfile:</p><ol><li>PHP 8.3 with Apache: We start from the official PHP 8.3 Apache image.</li><li>Install PHP Extensions: We install common PHP extensions needed by Laravel, such as GD, PDO, and MySQL.</li><li>Enable mod_rewrite: This allows us to use Laravel’s route handling.</li><li>Install Composer: We copy the latest Composer binary into the image to manage Laravel’s dependencies.</li><li>File Permissions: Ensure the correct file permissions for Laravel’s storage and cache directories.</li><li>Expose Port 80: Expose the default HTTP port for the web server.</li></ol><h3>Step 2: Create the docker-compose.yml</h3><p>Next, we’ll configure docker-compose.yml to define the application and database services. docker-compose allows us to easily manage multi-container applications.</p><p><strong>docker-compose.yml</strong></p><pre>services:<br>    app:<br>        build: .<br>        ports:<br>            - &quot;9000:80&quot; # Port to access the application from the browser<br>        volumes:<br>            - .:/var/www/html # Mount local application folder to container<br>            - /var/www/html/storage # Storage for Laravel&#39;s storage folder<br>            - /var/www/html/bootstrap/cache # Storage for Laravel&#39;s cache<br>        networks:<br>            - app_network<br>        mem_limit: &quot;2G&quot;<br>        cpus: &quot;1&quot;<br>        environment:<br>            - VIRTUAL_HOST=localhost # Use localhost for local development<br><br>    db:<br>        image: mysql:8.0<br>        environment:<br>            MYSQL_DATABASE: database<br>            MYSQL_ROOT_PASSWORD: password<br>        ports:<br>            - &quot;3307:3306&quot; # Port to access MySQL<br>        volumes:<br>            - db_data:/var/lib/mysql # MySQL data storage<br>        networks:<br>            - app_network<br>        mem_limit: &quot;2G&quot;<br>        cpus: &quot;1&quot;<br><br>volumes:<br>    db_data:<br><br>networks:<br>    app_network:<br>        driver: bridge</pre><p><strong>Explanation of </strong><strong>docker-compose.yml:</strong></p><p>1. App Service:</p><ul><li>build: . tells Docker to build the image using the current directory&#39;s Dockerfile.</li><li>The app will be available on localhost:9000, as we map port 9000 on the host to port 80 in the container.</li><li>We mount the application directory and the vendor directory to persist the Composer dependencies.</li></ul><p>2. Database Service:</p><ul><li>We’re using the official mysql:8.0 image.</li><li>The database will have a user, password and database from laravel .env.</li><li>We map MySQL’s default port 3307 from the container to the host.</li><li>We store the MySQL data in a named volume (db_data) to persist the database.</li></ul><p>3. Networks:</p><p>We create a bridge network app_network to ensure that the app and database services can communicate with each other.</p><h3>Step 3: Create Apache Virtual Host Configuration (000-default.conf)</h3><p>In this step, we configure Apache to serve the Laravel application. The configuration will ensure that requests are routed correctly and that the .htaccess file works for URL rewriting.</p><p>000-default.conf</p><pre>&lt;VirtualHost *:80&gt;<br>    DocumentRoot /var/www/html/public<br><br>    &lt;Directory /var/www/html&gt;<br>        AllowOverride All<br>        Order Allow,Deny<br>        Allow from All<br>    &lt;/Directory&gt;<br><br>    ErrorLog ${APACHE_LOG_DIR}/error.log<br>    CustomLog ${APACHE_LOG_DIR}/access.log combined<br>&lt;/VirtualHost&gt;</pre><p><strong>Explanation:</strong></p><ul><li><strong>DocumentRoot</strong>: We set the document root to /var/www/html/public because that’s where Laravel&#39;s index.php file is located.</li><li><strong>AllowOverride All</strong>: This allows the .htaccess file to be used for URL rewriting, which is important for Laravel&#39;s routing.</li></ul><h3>Step 4: Build and Start the Docker Containers</h3><p>Now, let’s build and start the containers. In your terminal, run the following commands:</p><ul><li><strong>Build the Docker containers</strong>:</li></ul><pre>docker-compose build</pre><ul><li><strong>Start the containers in the background</strong>:</li></ul><pre>docker-compose up -d</pre><ul><li>The application will now be accessible at http://127.0.0.1:9000, and the MySQL database will be running on port 3307.</li></ul><h3>Step 5: Stopping the Containers</h3><p>To stop the containers and remove the volumes (which contain the database data), use the following command:</p><pre>docker-compose down</pre><p>This will stop and remove all the containers, networks, and volumes defined in the docker-compose.yml file. You can also use docker-compose down --volumes if you want to remove the volumes (like the database data).</p><h3>Step 6: Accessing the Database</h3><p>To connect to the MySQL database, you can use a database management tool like HeidiSQL. Use the following credentials as defined in the docker-compose.yml file:</p><ul><li><strong>Host</strong>: db</li><li><strong>Port</strong>: 3307</li><li><strong>Username</strong>: root</li><li><strong>Password</strong>: password</li><li><strong>Database</strong>: database</li></ul><h4>Cleaning Up Unused Docker Resources</h4><p>To clear unused Docker resources, such as stopped containers, unused networks, and dangling images, you can run:</p><pre>docker system prune -f</pre><p>This will:</p><ul><li>Remove all stopped containers.</li><li>Remove unused networks.</li><li>Remove dangling images (images that are not tagged and not used by any container).</li><li>It will <strong>not</strong> remove volumes unless you specify --volumes.</li></ul><p><strong>Note:</strong> Use docker system prune with caution, as it will remove resources that are no longer being used, potentially freeing up disk space. Make sure you don&#39;t need those resources before running this command.</p><h4><strong>Rebuild the containers</strong></h4><pre>docker-compose up --build -d</pre><p>This will rebuild the images, recreate the containers, and start them again in the background.</p><h4>Alternative Approach (If you only want to rebuild a specific service):</h4><p>If you only want to rebuild a specific service (for example, just the app container), you can specify the service name:</p><pre>docker-compose up --build -d app</pre><p>This command will rebuild and restart the app service only, without affecting the database container.</p><h4>Access the container using docker-compose</h4><p>To access the Docker container running your application, you can use the docker exec or docker-compose exec command, depending on whether you&#39;re using Docker Compose or Docker directly.</p><p><strong>Check if the container is running:</strong> To verify if your container is running, use:</p><pre>docker-compose ps</pre><p>If the app container is listed, proceed to the next step.</p><p><strong>Enter the container:</strong> To enter the app container, use the following command:</p><pre>docker-compose exec -it app bash</pre><p>This will open a terminal session inside the container, where you can run commands as needed.</p><p>or check this <a href="https://github.com/muhalvin/laravel-docker-compose">github repo</a> for example.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=522eebbef82d" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/setting-up-a-laravel-11-with-docker-522eebbef82d">Setting Up a Laravel 11 with Docker</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Enable PHP Extensions in Webmin]]></title>
            <link>https://towardsdev.com/webcomplete-guide-to-enabling-php-extensions-in-webmin-for-php-8-3-2dff69327ad9?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/2dff69327ad9</guid>
            <category><![CDATA[php]]></category>
            <category><![CDATA[vps]]></category>
            <category><![CDATA[webmin]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Fri, 13 Dec 2024 12:15:38 GMT</pubDate>
            <atom:updated>2025-01-04T02:51:17.390Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Webmin Dashboard" src="https://cdn-images-1.medium.com/max/1024/1*QmVireV8F82e5X_DlBGtrQ.png" /><figcaption>Webmin Dashboard</figcaption></figure><p>Webmin is a powerful web-based interface that allows you to manage various system configurations on a Linux server. If you’re using PHP 8.3 on your server and need to enable PHP extensions, this detailed guide will walk you through the steps to activate them, check which php.ini is active (for CGI, CLI, or FPM), and restart necessary services using Webmin.</p><h3>Prerequisites</h3><ul><li>Webmin is installed and accessible on your server.</li><li>PHP 8.3 is installed on your server. (You can use any php version)</li><li>You have the required root or sudo permissions to configure PHP and Webmin.</li></ul><p>In this tutorial, I’m using Webmin 2.202 on Ubuntu Linux 20.04.6. Please note that different versions of Webmin or other operating systems may result in slightly different interfaces or steps.</p><h3>Step 1: Log in to Webmin</h3><p><strong>Access Webmin:</strong> Open your browser and go to your Webmin login page. Typically, the URL will be</p><pre>https://your-server-ip:10000</pre><p><strong>Login</strong>: Enter your username and password for Webmin. This is usually the root user or a user with sudo privileges.</p><h3>Step 2: Access PHP Configuration in Webmin</h3><h4><strong>Navigate to PHP Configuration:</strong></h4><p>Once you are logged in, from the <strong>Webmin</strong> dashboard, click on <strong>Tools </strong>&gt; <strong>PHP Configuration</strong> under the <strong>Servers</strong> section. This will take you to the PHP configuration page where you can manage different PHP versions.</p><figure><img alt="Webmin menu" src="https://cdn-images-1.medium.com/max/262/1*k0u-TqxYPnY1B2yDCADm_Q.png" /><figcaption>Tools &gt; PHP Configuration</figcaption></figure><p>On the PHP Configuration page, you will see a list of PHP versions installed on your system.</p><figure><img alt="PHP List Version" src="https://cdn-images-1.medium.com/max/1024/1*zJYKLdk7bStxk4yk6C0eqw.png" /><figcaption>PHP List</figcaption></figure><h3>Step 3: Enable PHP Extensions</h3><h4><strong>Edit the PHP Configuration:</strong></h4><p>After selecting <strong>PHP 8.3</strong>, click on <strong>Edit Manualy</strong>. This will open the configuration file (php.ini) used by PHP 8.3.</p><h4><strong>Search for the Extension:</strong></h4><p>In the php.ini file, look for the line corresponding to the extension you want to enable. For example, to enable the intl extension, search for:</p><pre>;extension=intl</pre><h4><strong>Uncomment the Extension:</strong></h4><p>If the extension is commented out (with a semicolon ;), remove the semicolon at the beginning of the line to uncomment it:</p><pre>extension=intl</pre><h4>Install the Extension (if needed):</h4><p>If the extension is not installed on your server, you will need to install it manually. Open a terminal or use SSH to connect to your server and run the following command:</p><pre>sudo apt install php8.3-intl</pre><p>This will install the intl extension for PHP 8.3. You can replace intl with the name of any other extension you wish to enable (e.g., mbstring, xml, etc.).</p><h3>Step 4: Restart PHP and Web Server</h3><ul><li><strong>Restart PHP Using Webmin:</strong> After enabling the extension, go back to the Webmin PHP Configuration page. At the top, click <strong>Restart</strong> or <strong>Apply Changes</strong> to apply the configuration changes to PHP 8.3.</li><li><strong>Restart the Web Server:</strong> To ensure the new configuration is loaded, restart the web server. Depending on your server setup, the following options are available:</li><li><strong>For Apache:</strong> If you are using Apache, you can restart it directly from Webmin by navigating to <strong>Webmin</strong> &gt; <strong>Dashboard </strong>&gt; <strong>Servers Status </strong>and clicking <strong>Restart Apache</strong>.</li></ul><figure><img alt="Restart apache" src="https://cdn-images-1.medium.com/max/1024/1*jWGCqa-TP7MRvpyWjVUkYg.png" /><figcaption>Restart apache</figcaption></figure><ul><li><strong>For PHP-FPM:</strong> If you’re using PHP-FPM for Apache or Nginx, you can restart the PHP-FPM service:</li></ul><pre>sudo systemctl restart php8.3-fpm</pre><h3>Step 5: Verify the PHP Extension</h3><ul><li><strong>Create a PHP Info File:</strong> To confirm that the extension has been enabled, you can create a PHP info file. Create a new PHP file (e.g., info.php) and place the following code in it:</li></ul><pre>&lt;?php phpinfo(); ?&gt;</pre><ul><li><strong>Access the PHP Info File:</strong> Upload or place the info.php file in your web server&#39;s document root. Then, open your web browser and navigate to http://your-server-ip/info.php (replace your-server-ip with the IP address of your server).</li><li><strong>Check for the Extension:</strong> In the phpinfo() page, search for the enabled extension (e.g., intl). If it appears in the list, it means the extension has been successfully enabled.</li></ul><h3>Check Which php.ini Is Active (CLI, CGI, FPM)</h3><p>If you’re using multiple PHP configurations (CGI, CLI, or FPM), you may want to check which php.ini file is being used by each PHP handler. Here’s how to check for each:</p><h4>1. Check PHP CLI (php.ini)</h4><p>To see which php.ini is being used for PHP CLI (Command Line Interface), run the following command:</p><pre>php8.3 --ini</pre><p>This will return output like:</p><pre>Configuration File (php.ini) Path: /etc/php/8.3/cli<br>Loaded Configuration File: /etc/php/8.3/cli/php.ini</pre><h4>2. Check PHP FPM (php.ini)</h4><p>For PHP running with PHP-FPM, use this command to check the php.ini being loaded:</p><pre>php-fpm8.3 -i | grep &quot;Loaded Configuration File&quot;</pre><p>This will output something like:</p><pre>Loaded Configuration File =&gt; /etc/php/8.3/fpm/php.ini</pre><h4>3. Check PHP CGI (php.ini)</h4><p>For PHP running as CGI, use the following command:</p><pre>php-cgi8.3 -i | grep &quot;Loaded Configuration File&quot;</pre><p>This will return the path to the php.ini for PHP CGI:</p><pre>Loaded Configuration File =&gt; /etc/php/8.3/cgi/php.ini</pre><p>Once you have verified that the extension is enabled and the correct php.ini file is active, remember to delete or secure the info.php file to prevent unauthorized access to your PHP configuration details.</p><p>This guide should help you enable PHP extensions and check your PHP configuration in Webmin. If you have any questions or need further assistance, feel free to ask! 😊</p><p>For more details about Webmin, check out this <a href="https://webmin.com/">link</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2dff69327ad9" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/webcomplete-guide-to-enabling-php-extensions-in-webmin-for-php-8-3-2dff69327ad9">How to Enable PHP Extensions in Webmin</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Laravel 11 Sanctum: Secure Your API with Token-Based Authentication]]></title>
            <link>https://towardsdev.com/laravel-11-sanctum-secure-your-api-with-token-based-authentication-6ba617930c44?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/6ba617930c44</guid>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[junior-developer]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[authentication]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Mon, 11 Nov 2024 03:09:57 GMT</pubDate>
            <atom:updated>2024-12-09T18:33:48.298Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*3qMnJppU6XZk_7FKdxX12A.png" /></figure><h4>What is Laravel Sanctum?</h4><p>API authentication is essential for controlling access to your application’s resources. <strong>Laravel Sanctum</strong> is a simple, lightweight authentication package perfect for Single Page Applications (SPAs) and mobile apps that need token-based authentication without the complexity of OAuth. In this article, we’ll walk through setting up user registration, login, and logout using Laravel 11 and Sanctum.</p><h4>Getting started</h4><p>First, open Terminal and run the following command to create a fresh laravel project:</p><pre>laravel new sanctum</pre><p>After done creating new laravel project, go inside <strong>sanctum-auth</strong> directory and run the app</p><pre>cd sanctum<br>php artisan serve</pre><p>This command will start the server, usually available at http://127.0.0.1:8000. Verify that the application loads correctly in your browser.</p><h4><strong>Configure Database</strong></h4><p>In the .env file, set up your database credentials:</p><pre>DB_CONNECTION=pgsql<br>DB_HOST=127.0.0.1<br>DB_PORT=5432<br>DB_DATABASE=sanctum<br>DB_USERNAME=postgres<br>DB_PASSWORD=pwapp</pre><h4>Installation and Setup</h4><p>Next, install <strong>Laravel Sanctum</strong> using Composer:</p><pre>php artisan install:api</pre><p>To allow users to create API tokens, add the HasApiTokens trait to the User model.</p><p>Open app/Models/User.php and modify it as follows:</p><pre>&lt;?php<br><br>namespace App\Models;<br><br>use Illuminate\Database\Eloquent\Factories\HasFactory;<br>use Illuminate\Foundation\Auth\User as Authenticatable;<br>use Illuminate\Notifications\Notifiable;<br>use Laravel\Sanctum\HasApiTokens;<br><br>class User extends Authenticatable<br>{<br>    use HasFactory, Notifiable, HasApiTokens;<br>}</pre><p>Adding the HasApiTokens trait enables token-based authentication for this model, allowing users to generate personal access tokens.</p><blockquote>For more detailed information about sanctum, kindly check this <a href="https://laravel.com/docs/11.x/sanctum#installation">documentation</a>.</blockquote><h4>Set Up Authentication Routes</h4><p>Define authentication routes in routes/api.php. These routes will handle user registration, login, and logout.</p><pre>&lt;?php<br><br>use Illuminate\Support\Facades\Route;<br><br>Route::prefix(&#39;auth&#39;)-&gt;name(&#39;auth.&#39;)-&gt;group(function () {<br>    Route::middleware(&#39;throttle:5,1&#39;)-&gt;group(function () {<br>        Route::post(&#39;register&#39;, [App\Http\Controllers\AuthController::class, &#39;register&#39;])-&gt;name(&#39;register&#39;);<br>        Route::post(&#39;login&#39;, [App\Http\Controllers\AuthController::class, &#39;login&#39;])-&gt;name(&#39;login&#39;);<br>    });<br><br>    Route::middleware(&#39;auth:sanctum&#39;)-&gt;group(function () {<br>        Route::post(&#39;logout&#39;, [App\Http\Controllers\AuthController::class, &#39;logout&#39;])-&gt;name(&#39;logout&#39;);<br>    });<br>});</pre><h4>Create the AuthController</h4><p>Now, create an AuthController to handle registration, login, and logout logic:</p><pre>php artisan make:controller AuthController</pre><p>In app/Http/Controllers/AuthController.php, implement the methods as follows:</p><pre>&lt;?php<br><br>namespace App\Http\Controllers;<br><br>use App\Models\User;<br>use Illuminate\Http\JsonResponse;<br>use Illuminate\Http\Request;<br>use Illuminate\Support\Facades\Auth;<br>use Illuminate\Support\Facades\Hash;<br><br>class AuthController extends Controller<br>{<br>    public function register(Request $request): JsonResponse<br>    {<br>        $data = $request-&gt;validate([<br>            &#39;name&#39;      =&gt; &#39;required|string&#39;,<br>            &#39;email&#39;     =&gt; &#39;required|string|email|unique:users,email&#39;,<br>            &#39;password&#39;  =&gt; &#39;required|string|min:8|confirmed|regex:/[a-z]/|regex:/[A-Z]/|regex:/[0-9]/&#39;,<br>        ]);<br><br>        $user = User::create([<br>            &#39;name&#39;      =&gt; $data[&#39;name&#39;],<br>            &#39;email&#39;     =&gt; $data[&#39;email&#39;],<br>            &#39;password&#39;  =&gt; Hash::make($data[&#39;password&#39;])<br>        ]);<br><br>        $token = $user-&gt;createToken(&#39;user-token&#39;)-&gt;plainTextToken;<br><br>        $response = [<br>            &#39;user&#39;  =&gt; $user-&gt;makeHidden([&#39;password&#39;, &#39;remember_token&#39;]),<br>            &#39;token&#39; =&gt; $token<br>        ];<br><br>        return response()-&gt;json($response, 201);<br>    }<br><br>    public function login(Request $request): JsonResponse<br>    {<br>        $request-&gt;validate([<br>            &#39;email&#39;     =&gt; &#39;required|string|email&#39;,<br>            &#39;password&#39;  =&gt; &#39;required|string|min:8&#39;<br>        ]);<br><br>        $user = User::where(&#39;email&#39;, $request-&gt;email)-&gt;first();<br><br>        if (!$user || !Hash::check($request-&gt;password, $user-&gt;password)) {<br>            return response()-&gt;json([<br>                &#39;message&#39; =&gt; &#39;These credentials do not match our records.&#39;<br>            ], 401);<br>        }<br><br>        $token = $user-&gt;createToken(&#39;user-token&#39;)-&gt;plainTextToken;<br><br>        $response = [<br>            &#39;user&#39;  =&gt; $user-&gt;makeHidden([&#39;password&#39;, &#39;remember_token&#39;]),<br>            &#39;token&#39; =&gt; $token<br>        ];<br><br>        return response()-&gt;json($response, 200);<br>    }<br><br>    public function logout()<br>    {<br>        Auth::user()-&gt;tokens-&gt;each(function ($token) {<br>            $token-&gt;forceDelete();<br>        });<br><br>        return response()-&gt;json([<br>            &#39;message&#39; =&gt; &#39;Logged out successfully&#39;,<br>        ], 200);<br>    }<br>}</pre><h4>Test the Authentication API</h4><p>You can test the API endpoints with a tool like Postman or cURL.</p><p><strong>1. Register a New User</strong></p><ul><li><strong>Endpoint</strong>: POST /api/auth/register</li><li><strong>Body</strong>: name, email, password, password_confirmation</li></ul><figure><img alt="Register request on postman" src="https://cdn-images-1.medium.com/max/713/1*dBQv2EOGnInsIn2RD2_Bmw.png" /></figure><p><strong>2. Log In to Get an Access Token</strong></p><ul><li><strong>Endpoint</strong>: POST /api/auth/login</li><li><strong>Body</strong>: email, password</li></ul><figure><img alt="login request in postman" src="https://cdn-images-1.medium.com/max/632/1*Mz0MdFYq935pBXV9fOj4Ug.png" /></figure><p><strong>3. Log Out</strong></p><ul><li><strong>Endpoint</strong>: POST /api/auth/logout</li><li><strong>Header</strong>: Authorization: Bearer your_generated_token</li><li>This will invalidate the token, logging the user out.</li></ul><figure><img alt="Logout request in postman" src="https://cdn-images-1.medium.com/max/1024/1*dRoWYfRCUjeKGX0SUIvAmg.png" /></figure><blockquote>See the postman api docs <a href="https://web.postman.co/workspace/Medium~dcb46c0e-4b4e-485d-9dc1-c11d5c8f0bed/collection/38344669-0d1f1689-c3a7-47c2-a4a3-3d6358cdfbba">here</a></blockquote><h4>Conclusion</h4><p>With this setup, you have a secure, token-based authentication system for your Laravel 11 API using Sanctum. This foundation allows you to build APIs that only authenticated users can access, making it ideal for SPAs, mobile apps, and even basic server-to-server communication.</p><p>Sanctum’s simplicity makes it a great choice for applications where you want to avoid the complexity of OAuth, while still providing strong security and flexibility. You can further extend this setup to add roles, permissions, and additional features as needed.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ba617930c44" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/laravel-11-sanctum-secure-your-api-with-token-based-authentication-6ba617930c44">Laravel 11 Sanctum: Secure Your API with Token-Based Authentication</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Add PostgreSQL to Laragon]]></title>
            <link>https://towardsdev.com/how-to-add-postgresql-to-laragon-de16910edde5?source=rss-985397abdee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/de16910edde5</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[postgresql]]></category>
            <category><![CDATA[laragon]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[MHVN]]></dc:creator>
            <pubDate>Wed, 06 Nov 2024 13:23:57 GMT</pubDate>
            <atom:updated>2024-11-18T18:23:34.330Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Laragon" src="https://cdn-images-1.medium.com/max/1024/1*5JBNHPl4A10JsimGEsCkXg.png" /><figcaption>Laragon</figcaption></figure><p>Laragon is a powerful and lightweight local development environment that supports various databases, including MySQL, MariaDB, and PostgreSQL. This guide will walk you through the process of adding PostgreSQL to your Laragon setup, allowing you to build projects that require a PostgreSQL database.</p><h3>What You’ll Need:</h3><ul><li><strong>Laragon installed:</strong> If you haven’t installed Laragon yet, you can download it from the <a href="https://laragon.org/">official website</a>.</li><li><strong>PostgreSQL binaries:</strong> You’ll need to download the PostgreSQL installer for Windows.</li></ul><h3>Steps to Add PostgreSQL to Laragon:</h3><h4>1. Download PostgreSQL Binaries</h4><ul><li>Visit the <a href="https://www.enterprisedb.com/download-postgresql-binaries">PostgreSQL Binaries download page</a>.</li><li>Choose the appropriate version (e.g., postgresql-17.0-1-windows-x64-binaries.zip) and download it to your computer.</li></ul><h4>2. Extract PostgreSQL Binaries to Laragon’s bin Folder</h4><ul><li>Navigate to your Laragon installation directory (usually C:\laragon).</li><li>Inside the Laragon directory, open the bin folder.</li><li>Create a new folder named PostgreSQL if it doesn’t already exist.</li><li>Extract the downloaded zip file into the PostgreSQL folder.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/481/1*Cwbg2B2Aso8RZmD2mvu7zA.png" /><figcaption>postgresql</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/514/1*F5phDvfH9ygqhViJ7m3zXQ.png" /><figcaption>postgresql-17.0.1</figcaption></figure><h4>3. Select PostgreSQL Version</h4><ul><li>Right-click on the Laragon icon in the taskbar.</li><li>From the context menu, hover over <strong>PostgreSQL</strong>.</li><li>Point your cursor to <strong>Version</strong> and select the version of PostgreSQL you want to use.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/671/1*Ecf20aR6HKBGc8NcF1fEZw.png" /><figcaption>Select postgresql version</figcaption></figure><h4>4. Start PostgreSQL</h4><ul><li>In Laragon, click <strong>Start All</strong> to start all services.</li><li>You should see <strong>PostgreSQL</strong> listed among the services. Click <strong>Start</strong> next to PostgreSQL to activate it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/667/1*6Uyr1eGcU0aL66eGOwkANw.png" /></figure><h4>5. Test PostgreSQL</h4><ul><li>To check if PostgreSQL is running correctly, open Laragon’s <strong>Terminal</strong> and type the following command:</li></ul><pre>psql -U postgres</pre><ul><li>If the PostgreSQL command-line interface opens and allows you to interact with the database, PostgreSQL has been successfully set up.</li></ul><h4>6. Connect PostgreSQL to Your Projects</h4><ul><li>To use PostgreSQL in your Laravel project, update your .env file to configure the database connection:</li></ul><pre>DB_CONNECTION=pgsql<br>DB_HOST=127.0.0.1<br>DB_PORT=5432<br>DB_DATABASE=your_database_name<br>DB_USERNAME=postgres<br>DB_PASSWORD=your_password</pre><h3>Conclusion</h3><p>By following these steps, you’ll have PostgreSQL up and running in Laragon. Whether you’re working on a Laravel project or another application that requires PostgreSQL, Laragon’s simple setup and PostgreSQL support make it an ideal tool for local development.</p><p>Happy coding, and enjoy working with PostgreSQL in Laragon!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=de16910edde5" width="1" height="1" alt=""><hr><p><a href="https://towardsdev.com/how-to-add-postgresql-to-laragon-de16910edde5">How to Add PostgreSQL to Laragon</a> was originally published in <a href="https://towardsdev.com">Towards Dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>