<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Youssef Ahmed</title>
    <description>The latest articles on DEV Community by Youssef Ahmed (@youssefahmedcs).</description>
    <link>https://dev.to/youssefahmedcs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3479891%2F97507363-dd7f-432c-ba22-54135691d668.png</url>
      <title>DEV Community: Youssef Ahmed</title>
      <link>https://dev.to/youssefahmedcs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/youssefahmedcs"/>
    <language>en</language>
    <item>
      <title>How I Automated My Laravel Deployments to a VPS with GitHub Actions and SSH</title>
      <dc:creator>Youssef Ahmed</dc:creator>
      <pubDate>Wed, 23 Sep 2026 15:17:26 +0000</pubDate>
      <link>https://dev.to/youssefahmedcs/simple-continuous-deployment-for-laravel-with-github-actions-and-a-vps-58ok</link>
      <guid>https://dev.to/youssefahmedcs/simple-continuous-deployment-for-laravel-with-github-actions-and-a-vps-58ok</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftig9n1p597slzh3skjlg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftig9n1p597slzh3skjlg.jpg" alt="Cover Image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running a Laravel application on a VPS usually means repeating the same routine: connecting via SSH, pulling latest changes, running composer updates, migrating the database, and clearing caches manually.&lt;/p&gt;

&lt;p&gt;It works, but it's repetitive and prone to human error.&lt;/p&gt;

&lt;p&gt;So I automated the boring part.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk through setting up a lightweight Continuous Deployment (CD) pipeline using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub &amp;amp; GitHub Actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSH Key Authentication&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Linux VPS&lt;/strong&gt; (Ubuntu)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Laravel &amp;amp; Composer&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Core Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push origin main
        ↓
     GitHub
        ↓
 GitHub Actions Runner
        ↓ (SSH)
       VPS
        ↓
 Pull Code &amp;amp; Run Artisan Commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time code is pushed or merged into &lt;code&gt;main&lt;/code&gt;, GitHub Actions connects to the VPS and deploys the latest version automatically.&lt;/p&gt;

&lt;p&gt;This isn't a replacement for a complex multi-stage CI/CD system, but it is a dependable, lightweight pipeline that works great for small to medium VPS-hosted applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Setup &amp;amp; Prerequisites
&lt;/h2&gt;

&lt;p&gt;My Laravel project lives on the VPS at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/www/html/paltform-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source code is stored on GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/youssef-ahmed-cs/laracast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment branch is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before touching GitHub Actions, make sure the local project is linked to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@github.com:youssef-ahmed-cs/laracast.git (fetch)&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@github.com:youssef-ahmed-cs/laracast.git (push)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And verify the standard Laravel folder structure on the server (&lt;code&gt;app&lt;/code&gt;, &lt;code&gt;bootstrap&lt;/code&gt;, &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;routes&lt;/code&gt;, &lt;code&gt;storage&lt;/code&gt;, etc.):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkx1rbugry7difnjcfyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkx1rbugry7difnjcfyo.png" alt="Laravel Project Structure" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Solving Git's "Dubious Ownership" Error
&lt;/h2&gt;

&lt;p&gt;While setting up automated deployments, Git can throw a security error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fatal: detected dubious ownership in repository at '/var/www/html/paltform-api'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This happens when the user running the Git commands (your SSH user) doesn't match the user who owns the repository directory (often &lt;code&gt;www-data&lt;/code&gt; or &lt;code&gt;root&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To allow Git to safely run inside the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--add&lt;/span&gt; safe.directory /var/www/html/paltform-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it by checking the status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html/paltform-api
git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Configure GitHub Secrets for SSH
&lt;/h2&gt;

&lt;p&gt;Instead of hardcoding server credentials into workflow files, store them securely in GitHub under &lt;strong&gt;Settings &amp;gt; Secrets and variables &amp;gt; Actions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Add the following repository secrets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SSH_HOST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your server's public IP address or domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SSH_USERNAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The SSH user account on your VPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SSH_PORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The SSH port (typically &lt;code&gt;22&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SSH_PRIVATE_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The private SSH key matching the public key in &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ik6yay748mm2le36o2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ik6yay748mm2le36o2h.png" alt="GitHub Secrets Configuration" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Create the GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;Create the deployment workflow file at &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH into VPS and deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-24.04&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy over SSH&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy project over SSH&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v1.2.0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_HOST }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_USERNAME }}&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_PRIVATE_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_PORT }}&lt;/span&gt;

          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;set -e&lt;/span&gt;

            &lt;span class="s"&gt;# 1. Trust repository directory&lt;/span&gt;
            &lt;span class="s"&gt;git config --global --add safe.directory /var/www/html/paltform-api&lt;/span&gt;

            &lt;span class="s"&gt;cd /var/www/html/paltform-api&lt;/span&gt;

            &lt;span class="s"&gt;# 2. Put application into maintenance mode&lt;/span&gt;
            &lt;span class="s"&gt;php artisan down || true&lt;/span&gt;

            &lt;span class="s"&gt;# 3. Pull latest changes from main&lt;/span&gt;
            &lt;span class="s"&gt;git fetch origin main&lt;/span&gt;
            &lt;span class="s"&gt;git reset --hard origin/main&lt;/span&gt;
            &lt;span class="s"&gt;git clean -fd&lt;/span&gt;

            &lt;span class="s"&gt;# 4. Install production dependencies&lt;/span&gt;
            &lt;span class="s"&gt;composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction&lt;/span&gt;

            &lt;span class="s"&gt;# 5. Run database migrations&lt;/span&gt;
            &lt;span class="s"&gt;php artisan migrate --force&lt;/span&gt;

            &lt;span class="s"&gt;# 6. Clear and cache configuration, routes, and views&lt;/span&gt;
            &lt;span class="s"&gt;php artisan optimize:clear&lt;/span&gt;
            &lt;span class="s"&gt;php artisan optimize&lt;/span&gt;
            &lt;span class="s"&gt;php artisan view:cache&lt;/span&gt;

            &lt;span class="s"&gt;# 7. Bring application back online&lt;/span&gt;
            &lt;span class="s"&gt;php artisan up&lt;/span&gt;

            &lt;span class="s"&gt;echo "Deployment completed successfully."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhnbqh1o1odua16yuhieh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhnbqh1o1odua16yuhieh.png" alt="GitHub Actions Workflow View" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Deconstructing the Deployment Commands
&lt;/h2&gt;

&lt;p&gt;Here is what happens during the deployment step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;set -e&lt;/code&gt;&lt;/strong&gt;: Instructs Bash to exit immediately if any command encounters an error, preventing broken or partial deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;php artisan down&lt;/code&gt;&lt;/strong&gt;: Puts the app in maintenance mode so users do not hit 500 errors while files, composer packages, and database tables are updating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;git fetch origin main&lt;/code&gt; &amp;amp; &lt;code&gt;git reset --hard origin/main&lt;/code&gt;&lt;/strong&gt;: Rather than a standard &lt;code&gt;git pull&lt;/code&gt; (which can fail with merge conflicts), this ensures the VPS working tree strictly mirrors the GitHub &lt;code&gt;main&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;git clean -fd&lt;/code&gt;&lt;/strong&gt;: Removes any untracked files or directories. &lt;em&gt;(Make sure &lt;code&gt;.env&lt;/code&gt; and user uploads are defined in &lt;code&gt;.gitignore&lt;/code&gt; so they are not deleted).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;composer install --no-dev --optimize-autoloader&lt;/code&gt;&lt;/strong&gt;: Installs production dependencies without dev tools (like PHPUnit or Faker) and builds an optimized autoloader map.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;php artisan migrate --force&lt;/code&gt;&lt;/strong&gt;: Executes any pending database migrations in production without prompting for manual confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;php artisan optimize&lt;/code&gt;&lt;/strong&gt;: Generates cached files for configuration, events, and routes in a single optimized command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;php artisan up&lt;/code&gt;&lt;/strong&gt;: Disables maintenance mode and restores user traffic.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. Pushing Changes and Verifying Deployment
&lt;/h2&gt;

&lt;p&gt;Trigger the pipeline with a push from your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Update application"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Actions will pick up the push, start the runner, and execute the remote script over SSH:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyane4n0gh7tq8fn77mt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyane4n0gh7tq8fn77mt1.png" alt="Action Running" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once finished, check the action logs. The step will output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment completed successfully.

Process exited with status 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwpsqmg92lzk1ipbcscb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwpsqmg92lzk1ipbcscb.png" alt="Process Exited with Status 0" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The deployment pipeline is fully automated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Local Machine
                   │
                   │ git push origin main
                   ▼
                GitHub
                   │
                   ▼
            GitHub Actions
                   │
                   │ SSH
                   ▼
                  VPS
                   │
                   ▼
       /var/www/html/paltform-api
                   │
          ┌────────┴────────┐
          ▼                 ▼
     Update Git      Install Composer
          │                 │
          └────────┬────────┘
                   ▼
            Migrate Database
                   │
                   ▼
            Optimize Laravel
                   │
                   ▼
          Deployment Complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of logging into the server every time a feature is ready, a simple &lt;code&gt;git push origin main&lt;/code&gt; handles code retrieval, dependency installation, database migration, and cache re-generation automatically.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>laravel</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to connection between laravel and Azure Blob ?</title>
      <dc:creator>Youssef Ahmed</dc:creator>
      <pubDate>Fri, 24 Jul 2026 14:35:42 +0000</pubDate>
      <link>https://dev.to/youssefahmedcs/how-to-connection-between-laravel-and-azure-blob--i81</link>
      <guid>https://dev.to/youssefahmedcs/how-to-connection-between-laravel-and-azure-blob--i81</guid>
      <description>&lt;p&gt;Integrating &lt;strong&gt;Azure Blob Storage&lt;/strong&gt; with Laravel allows you to store files in Microsoft's scalable cloud storage instead of your local server. This approach improves reliability, scalability, and storage management for production applications.&lt;/p&gt;

&lt;p&gt;In this guide, you'll learn how to connect &lt;strong&gt;Laravel 11, 12, and 13&lt;/strong&gt; to Azure Blob Storage and upload files with just a few steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before getting started, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Laravel 11, 12, or 13 application.&lt;/li&gt;
&lt;li&gt;An Azure account.&lt;/li&gt;
&lt;li&gt;An Azure Storage Account with a Blob Container created.&lt;/li&gt;
&lt;li&gt;Composer installed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step 1: Install the Azure Storage Package
&lt;/h1&gt;

&lt;p&gt;Install the Laravel Azure Storage package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require matthewbdaly/laravel-azure-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, add a new disk inside &lt;code&gt;config/filesystems.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'azure'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'driver'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'azure'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_STORAGE_NAME'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'key'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_STORAGE_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'container'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_STORAGE_CONTAINER_NAME'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'url'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_STORAGE_URL'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'prefix'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'connection_string'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_STORAGE_CONNECTION_STRING'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Configure your &lt;code&gt;.env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Although several variables are available, &lt;strong&gt;the connection string alone is enough&lt;/strong&gt; to establish the connection.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AZURE_STORAGE_CONNECTION_STRING="your-azure-storage-connection-string"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can find the connection string in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Storage Account =&amp;gt; Security + networking =&amp;gt; Access keys&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feib4mmabi6g980kib0zw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feib4mmabi6g980kib0zw.jpg" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Step 2: Create an Azure Blob Storage Service
&lt;/h1&gt;

&lt;p&gt;Generate a service class or controller:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-app-location

&lt;span class="nb"&gt;sudo mkdir &lt;/span&gt;Services

&lt;span class="nb"&gt;sudo touch &lt;/span&gt;AzureBlobStorageService.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create the following service:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AzureBlobStorageService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;uploadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;uniqid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;
            &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getClientOriginalExtension&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$contentType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getClientMimeType&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$contentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'azure'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;putFileAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$options&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'azure'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$fileName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 3: Upload Files
&lt;/h1&gt;

&lt;p&gt;Now you can inject the service into a controller or simply test it with a route.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Services\AzureBlobStorageService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/upload-on-azure'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;AzureBlobStorageService&lt;/span&gt; &lt;span class="nv"&gt;$azureService&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'file'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'No file provided'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$azureService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'devhub'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Failed to upload file.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'File uploaded successfully!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'file_path'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4: Test the API
&lt;/h1&gt;

&lt;p&gt;Use any API client to upload a file.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Postman&lt;/li&gt;
&lt;li&gt;HTTPie&lt;/li&gt;
&lt;li&gt;cURL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example using Postman:&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9pe6e6ycmaaxe77cktca.png" alt=" " width="800" height="448"&gt;
&lt;/h2&gt;
&lt;h1&gt;
  
  
  Common Issue: 404 Resource Not Found
&lt;/h1&gt;

&lt;p&gt;If the returned URL opens a &lt;strong&gt;404&lt;/strong&gt; page or shows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PublicAccessNotPermitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;don't worry this is expected.&lt;/p&gt;

&lt;p&gt;Azure Storage blocks anonymous public access by default.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Your storage account or blob container doesn't allow public blob access.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 1 (Development)
&lt;/h2&gt;

&lt;p&gt;Enable public access for your Blob Container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is acceptable for testing, but &lt;strong&gt;not recommended for production&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Solution 2 (Recommended)
&lt;/h2&gt;

&lt;p&gt;Generate &lt;strong&gt;Shared Access Signature (SAS)&lt;/strong&gt; URLs instead of exposing blobs publicly.&lt;/p&gt;

&lt;p&gt;This provides temporary, secure access to your files while keeping your storage account private.&lt;/p&gt;

&lt;p&gt;Example error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkjwm1afgrvltv5qgg3mf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkjwm1afgrvltv5qgg3mf.png" alt=" " width="799" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Azure Portal settings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvoan6cfkknyvvgi8jhy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvoan6cfkknyvvgi8jhy7.png" alt=" " width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vgtleck34wfgvydkrzg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vgtleck34wfgvydkrzg.jpg" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  That's It!! &lt;a href="https://devhubblobs.blob.core.windows.net/devhub/spain-header-img.jpg" rel="noopener noreferrer"&gt;Can open image!&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Congratulations!&lt;/p&gt;

&lt;p&gt;Your Laravel application is now connected to Azure Blob Storage, and you can start uploading files to the cloud.&lt;/p&gt;

&lt;p&gt;Azure Blob Storage is an excellent choice for production applications because it offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High availability&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Secure storage&lt;/li&gt;
&lt;li&gt;Low maintenance&lt;/li&gt;
&lt;li&gt;Integration with other Azure services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding! ❤️&lt;/p&gt;

&lt;p&gt;If this article helped you, consider giving it a ❤️ and following me for more Laravel and Azure content.&lt;/p&gt;


&lt;h2&gt;
  
  
  Video Tutorial
&lt;/h2&gt;

&lt;p&gt;Prefer watching a complete walkthrough?&lt;/p&gt;

&lt;p&gt;I created a step-by-step video that covers the entire process, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating an Azure Storage Account&lt;/li&gt;
&lt;li&gt;Creating a Blob Container&lt;/li&gt;
&lt;li&gt;Getting the Storage Connection String&lt;/li&gt;
&lt;li&gt;Configuring Laravel&lt;/li&gt;
&lt;li&gt;Uploading files to Azure Blob Storage&lt;/li&gt;
&lt;li&gt;Solving the &lt;code&gt;PublicAccessNotPermitted&lt;/code&gt; issue&lt;/li&gt;
&lt;li&gt;Testing the upload API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Watch the full tutorial here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/5XQP4Y4ZfRA?si=fMNLSfd2ViePO7i4" rel="noopener noreferrer"&gt;https://youtu.be/5XQP4Y4ZfRA?si=fMNLSfd2ViePO7i4&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview?wt.mc_id=studentamb_518873" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview?wt.mc_id=studentamb_518873" rel="noopener noreferrer" class="c-link"&gt;
            Storage Account Overview - Azure Storage | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn about the types of storage accounts in Azure Storage. Review account naming, tiers, redundancy, encryption, endpoints, and more.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;






&lt;h2&gt;
  
  
  Connect With Me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/YoussefAhmedCs" rel="noopener noreferrer"&gt;https://github.com/YoussefAhmedCs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://linkedin.com/in/youssef-ahmed-cs" rel="noopener noreferrer"&gt;https://linkedin.com/in/youssef-ahmed-cs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>azure</category>
      <category>cloud</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploying Laravel App to Ubuntu or Debian Server VM Azure</title>
      <dc:creator>Youssef Ahmed</dc:creator>
      <pubDate>Sat, 18 Jul 2026 14:13:36 +0000</pubDate>
      <link>https://dev.to/youssefahmedcs/deploy-laravel-app-on-an-azure-linux-vm-or-any-server-4jc8</link>
      <guid>https://dev.to/youssefahmedcs/deploy-laravel-app-on-an-azure-linux-vm-or-any-server-4jc8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5h8ecpw5osokxk06mud5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5h8ecpw5osokxk06mud5.jpeg" alt="Cover Image" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deploying a Laravel application doesn't have to cost money. If you already have a VPS or an Azure Virtual Machine, you can deploy your Laravel project manually without paying for services like Laravel Forge or Laravel Cloud.&lt;/p&gt;

&lt;p&gt;In this guide, I'll show you how to deploy a Laravel application step by step using &lt;strong&gt;Nginx&lt;/strong&gt;, &lt;strong&gt;PHP&lt;/strong&gt;, &lt;strong&gt;MySQL&lt;/strong&gt;, and &lt;strong&gt;Composer&lt;/strong&gt; on an &lt;strong&gt;Ubuntu VM&lt;/strong&gt;. I'll also explain what each command does so you understand what's happening behind the scenes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't have an &lt;a href="https://learn.microsoft.com/en-us/azure/virtual-machines/overview?wt.mc_id=studentamb_518873" rel="noopener noreferrer"&gt;Azure Virtual Machine&lt;/a&gt; yet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Watch this video first:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/Io34SbaYZmQ?si=a4btxewV0nFo0x_N" rel="noopener noreferrer"&gt;https://youtu.be/Io34SbaYZmQ?si=a4btxewV0nFo0x_N&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before getting started, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Ubuntu or Debian server (this guide uses Ubuntu on Azure)&lt;/li&gt;
&lt;li&gt;A GitHub repository containing your Laravel project&lt;/li&gt;
&lt;li&gt;SSH access (or password access) to your server&lt;/li&gt;
&lt;li&gt;Root or sudo privileges&lt;/li&gt;
&lt;li&gt;A public IP address assigned to your VM&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Update the Server
&lt;/h2&gt;

&lt;p&gt;Before installing any packages, update your package index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, upgrade installed packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Install Nginx
&lt;/h2&gt;

&lt;p&gt;Nginx is a high-performance web server used to serve websites efficiently. It can also act as a reverse proxy and load balancer.&lt;/p&gt;

&lt;p&gt;Think of Nginx as a highly efficient post office. It receives incoming requests, processes them, and forwards them to the correct destination.&lt;/p&gt;

&lt;p&gt;Install Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that it is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Install MySQL
&lt;/h2&gt;

&lt;p&gt;Laravel needs a database to store application data.&lt;/p&gt;

&lt;p&gt;Install MySQL Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;mysql-server &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Install PHP
&lt;/h2&gt;

&lt;p&gt;Nginx doesn't execute PHP files directly. Instead, it communicates with &lt;strong&gt;PHP-FPM (FastCGI Process Manager)&lt;/strong&gt;, which processes PHP requests.&lt;/p&gt;

&lt;p&gt;Install PHP and the required extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
php &lt;span class="se"&gt;\&lt;/span&gt;
php-fpm &lt;span class="se"&gt;\&lt;/span&gt;
php-cli &lt;span class="se"&gt;\&lt;/span&gt;
php-common &lt;span class="se"&gt;\&lt;/span&gt;
php-curl &lt;span class="se"&gt;\&lt;/span&gt;
php-mbstring &lt;span class="se"&gt;\&lt;/span&gt;
php-xml &lt;span class="se"&gt;\&lt;/span&gt;
php-soap &lt;span class="se"&gt;\&lt;/span&gt;
php-gd &lt;span class="se"&gt;\&lt;/span&gt;
php-bcmath &lt;span class="se"&gt;\&lt;/span&gt;
php-zip &lt;span class="se"&gt;\&lt;/span&gt;
php-mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're using a specific PHP version (for example PHP 8.4), install the matching packages instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Check your PHP version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Install Composer
&lt;/h2&gt;

&lt;p&gt;Composer is the dependency manager for PHP.&lt;/p&gt;

&lt;p&gt;Download and install Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://getcomposer.org/installer | php

&lt;span class="nb"&gt;sudo mv &lt;/span&gt;composer.phar /usr/local/bin/composer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Install Node.js &amp;amp; NPM
&lt;/h2&gt;

&lt;p&gt;Laravel uses Node.js for compiling frontend assets with Vite.&lt;/p&gt;

&lt;p&gt;Install Node.js and NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs npm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Clone Your GitHub Repository
&lt;/h2&gt;

&lt;p&gt;Move to the web directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone YOUR_GITHUB_SSH_URL learn-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move into the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;learn-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Install Project Dependencies
&lt;/h2&gt;

&lt;p&gt;Install Composer packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-dev&lt;/span&gt; &lt;span class="nt"&gt;--optimize-autoloader&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Node packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build frontend assets if use front:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. Configure Environment Variables
&lt;/h2&gt;

&lt;p&gt;Copy the environment file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate the application key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan key:generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  10. Create the MySQL Database
&lt;/h2&gt;

&lt;p&gt;Open MySQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;learnvm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="s1"&gt;'learnuser'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;
&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'YOUR_PASSWORD'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;learnvm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="s1"&gt;'learnuser'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;FLUSH&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;EXIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11. Configure Laravel
&lt;/h2&gt;

&lt;p&gt;Open the &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update your database credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=learnvm
DB_USERNAME=learnuser
DB_PASSWORD=YOUR_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  12. Run Database Migrations
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your project includes seeders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan db:seed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  13. Set File Permissions
&lt;/h2&gt;

&lt;p&gt;Laravel needs write access to the &lt;code&gt;storage&lt;/code&gt; and &lt;code&gt;bootstrap/cache&lt;/code&gt; directories.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:www-data storage bootstrap/cache

&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 storage bootstrap/cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  14. Configure Nginx
&lt;/h2&gt;

&lt;p&gt;Create a new virtual host configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/learn-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;YOUR_VM_PUBLIC_IP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/html/learn-vm/public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.php?&lt;/span&gt;&lt;span class="nv"&gt;$query_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;\.php$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;snippets/fastcgi-php&lt;/span&gt;&lt;span class="s"&gt;.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="s"&gt;unix:/run/php/php8.3-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.ht&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;YOUR_VM_PUBLIC_IP&lt;/code&gt; with your server's public IP address.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  15. Enable the Site
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/learn-vm /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  16. Stop Apache (If Installed)
&lt;/h2&gt;

&lt;p&gt;If Apache is already using port &lt;strong&gt;80&lt;/strong&gt;, stop it first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  17. Test the Nginx Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything looks good, reload Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart PHP-FPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart php8.3-fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  18. Open Your Application
&lt;/h2&gt;

&lt;p&gt;Visit your server's public IP address in your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://YOUR_VM_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Laravel application should now be running successfully.&lt;/p&gt;




&lt;h2&gt;
  
  
  Azure Networking
&lt;/h2&gt;

&lt;p&gt;If your application isn't accessible, make sure the required ports are open.&lt;/p&gt;

&lt;p&gt;Go to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Portal → Virtual Machine → Networking → Add Inbound Port Rule&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allow the following ports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP (80)&lt;/li&gt;
&lt;li&gt;HTTPS (443)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After saving the rules, refresh your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fve2si3x37sl5u89g3ocd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fve2si3x37sl5u89g3ocd.png" alt="Azure Networking" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;If your application doesn't load, check the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx is running.&lt;/li&gt;
&lt;li&gt;PHP-FPM is running.&lt;/li&gt;
&lt;li&gt;MySQL is running.&lt;/li&gt;
&lt;li&gt;Port &lt;strong&gt;80&lt;/strong&gt; is open.&lt;/li&gt;
&lt;li&gt;Port &lt;strong&gt;443&lt;/strong&gt; is open (if using HTTPS).&lt;/li&gt;
&lt;li&gt;Laravel has the correct file permissions.&lt;/li&gt;
&lt;li&gt;Your &lt;code&gt;.env&lt;/code&gt; file contains the correct database credentials.&lt;/li&gt;
&lt;li&gt;The Nginx configuration points to the correct &lt;code&gt;public&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;php artisan config:cache&lt;/code&gt; after updating your &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Congratulations! Your Laravel application is now deployed successfully.&lt;/p&gt;

&lt;p&gt;To make your server production ready, consider adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a custom domain name and point its DNS records to your server's public IP address.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live Demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://51.107.72.82/" rel="noopener noreferrer"&gt;http://51.107.72.82/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All Commands&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://user-cdn.hackclub-assets.com/019f68cc-736b-7627-b4cf-82f958d84b93/README.md" rel="noopener noreferrer"&gt;https://user-cdn.hackclub-assets.com/019f68cc-736b-7627-b4cf-82f958d84b93/README.md&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If this guide helped you, consider leaving a ❤️ on DEV and sharing it with other Laravel developers. Happy coding!!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the River to the Sea, Palestine Will Be Free!🇵🇸&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>laravel</category>
      <category>azure</category>
      <category>devops</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>GitHub Campus Experts</title>
      <dc:creator>Youssef Ahmed</dc:creator>
      <pubDate>Sat, 20 Jun 2026 05:27:40 +0000</pubDate>
      <link>https://dev.to/youssefahmedcs/github-campus-experts-3jem</link>
      <guid>https://dev.to/youssefahmedcs/github-campus-experts-3jem</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>git</title>
      <dc:creator>Youssef Ahmed</dc:creator>
      <pubDate>Wed, 24 Dec 2025 23:14:06 +0000</pubDate>
      <link>https://dev.to/youssefahmedcs/git-e3a</link>
      <guid>https://dev.to/youssefahmedcs/git-e3a</guid>
      <description>&lt;p&gt;git tool box&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
