<?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: Aboozar Ghaffari</title>
    <description>The latest articles on DEV Community by Aboozar Ghaffari (@aboozar).</description>
    <link>https://dev.to/aboozar</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F729613%2F1118aed1-81ae-48f6-905f-ff6c46047186.jpeg</url>
      <title>DEV Community: Aboozar Ghaffari</title>
      <link>https://dev.to/aboozar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aboozar"/>
    <language>en</language>
    <item>
      <title>How to Prevent Disasters in Laravel (A Critical Tip for Professional Developers)</title>
      <dc:creator>Aboozar Ghaffari</dc:creator>
      <pubDate>Tue, 20 May 2025 17:16:14 +0000</pubDate>
      <link>https://dev.to/aboozar/how-to-prevent-disasters-in-laravel-a-critical-tip-for-professional-developers-3f24</link>
      <guid>https://dev.to/aboozar/how-to-prevent-disasters-in-laravel-a-critical-tip-for-professional-developers-3f24</guid>
      <description>&lt;p&gt;Running powerful Artisan commands like &lt;code&gt;php artisan migrate:fresh&lt;/code&gt; or &lt;code&gt;migrate:wipe&lt;/code&gt; in the wrong environment—especially production—can completely wipe your database in seconds. To prevent such accidents, Laravel (&lt;strong&gt;starting from version 11.9&lt;/strong&gt;) offers a built-in protection mechanism using the Prohibitable trait. In this tutorial, you’ll learn how to lock down destructive commands in production and avoid unintentional data loss with just a few lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prohibitable Trait: Smart Protection Against Destructive Commands
&lt;/h2&gt;

&lt;p&gt;As of Laravel 11.9, you can easily lock dangerous commands in production environments. This simple safeguard can save you from catastrophic errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;By adding a few lines of code to your Service Provider, you can disable certain Artisan commands based on the environment.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&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;boot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;FreshCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;RefreshCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;ResetCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;RollbackCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;WipeCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&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;p&gt;Here’s why it’s crucial:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;migrate:wipe&lt;/code&gt; – Completely deletes all database tables (WipeCommand)&lt;br&gt;
&lt;code&gt;migrate:fresh&lt;/code&gt; – Resets the entire database (FreshCommand)&lt;br&gt;
&lt;code&gt;migrate:reset&lt;/code&gt; – Rolls back all migrations (ResetCommand)&lt;br&gt;
&lt;code&gt;migrate:refresh&lt;/code&gt; – Resets and reruns all migrations (RefreshCommand)&lt;br&gt;
&lt;code&gt;migrate:rollback&lt;/code&gt; – Reverts the last batch of migrations (RollbackCommand)&lt;/p&gt;

&lt;p&gt;The key line is:&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="nc"&gt;WipeCommand&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line accepts a boolean. If it returns true, the command is prohibited from running.&lt;/p&gt;

&lt;p&gt;The expression &lt;code&gt;app()-&amp;gt;isProduction()&lt;/code&gt; checks your app’s environment—based on the &lt;strong&gt;APP_ENV&lt;/strong&gt; value in your .env file.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simpler Solution
&lt;/h2&gt;

&lt;p&gt;Want to handle all dangerous commands in one place? Just add the second code snippet to your Service Provider, and you’ll be protected across the board.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&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;boot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prohibitDestructiveCommands&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&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;isProduction&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;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;If you’re a professional Laravel developer—or even just getting started—this small tip can save you from a major disaster. Don’t wait for a close call to make this part of your standard setup.&lt;/p&gt;

&lt;p&gt;Stay safe. Write smart code.&lt;br&gt;
Laravel has your back—you just need to use the tools it offers.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
    <item>
      <title>FrankenPHP: The Modern PHP App Server, written in Go</title>
      <dc:creator>Aboozar Ghaffari</dc:creator>
      <pubDate>Thu, 12 Sep 2024 20:31:01 +0000</pubDate>
      <link>https://dev.to/aboozar/frankenphp-the-modern-php-app-serverwritten-in-go-1oj7</link>
      <guid>https://dev.to/aboozar/frankenphp-the-modern-php-app-serverwritten-in-go-1oj7</guid>
      <description>&lt;p&gt;&lt;strong&gt;FrankenPHP&lt;/strong&gt; is a modern PHP application server built on the &lt;strong&gt;Caddy&lt;/strong&gt; web server, offering developers a powerful alternative to traditional setups like PHP-FPM and Nginx. In this article, I'll explore how FrankenPHP improves performance, simplifies deployment, and enhances security with cutting-edge features like worker mode, real-time event support, and automatic HTTPS. Whether you're working with Laravel, Symfony, WordPress, or other PHP frameworks, discover why FrankenPHP is quickly becoming the go-to solution for developers seeking to optimize their production environments.&lt;/p&gt;

&lt;p&gt;If you're a &lt;strong&gt;PHP developer&lt;/strong&gt; looking to improve your application’s performance, security, and deployment process, it's time to consider switching to FrankenPHP as your production web server. Built on the robust Caddy web server, FrankenPHP brings modern innovations that traditional setups like PHP-FPM and Nginx can’t match.&lt;/p&gt;

&lt;p&gt;With features like worker mode, which keeps your app in memory for faster performance, and real-time event capabilities that allow seamless communication between your app and the browser, FrankenPHP can significantly boost your app's responsiveness and user experience. It also supports automatic HTTPS, HTTP/2, and HTTP/3, ensuring your app is secure and uses the latest web protocols without any additional configuration.&lt;/p&gt;

&lt;p&gt;FrankenPHP also simplifies your deployment by &lt;strong&gt;packaging your app&lt;/strong&gt; as a &lt;strong&gt;standalone binary&lt;/strong&gt;, eliminating the need for managing multiple processes like PHP-FPM and Nginx. Whether you work with Laravel, Symfony, WordPress, or any other PHP framework, FrankenPHP will make your app faster, more efficient, and easier to manage.&lt;/p&gt;

&lt;p&gt;For developers looking to streamline their workflow and deliver better performance to end users, &lt;strong&gt;switching to FrankenPHP is a smart move&lt;/strong&gt;. Start exploring today and elevate your PHP projects to the next level.&lt;/p&gt;

&lt;h2&gt;
  
  
  FrankenPHP at a glance:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Caddy Webserver:&lt;/strong&gt; Uses the official PHP executor embedded in a state-of-the-art web server: Caddy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible:&lt;/strong&gt; Compatible with PHP 8.2+, most PHP extensions and all Caddy modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only one service:&lt;/strong&gt; Designed with simplicity in mind: only one service, only one binary! FrankenPHP doesn’t need PHP-FPM, it uses its own SAPI specially handcrafted for Go web servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy deploy:&lt;/strong&gt; Cloud Native app shipped as a Docker image. Compatible with Kubernetes, and all modern cloud platforms. It’s also possible to package your PHP app as a standalone, self-executable static binary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker mode:&lt;/strong&gt; Boot your application once and keep it in memory! It is ready to handle incoming requests in a few milliseconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;103 Early Hints:&lt;/strong&gt; Early Hints are a brand new feature of the web platform that can improve website load times by 30%. FrankenPHP is the only PHP SAPI with Early Hints support!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time:&lt;/strong&gt; Built-in Mercure hub. Send events from your PHP apps to all connected browsers, they instantly receive the payload as a JavaScript event!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brotli, Zstandard and Gzip compression:&lt;/strong&gt; Modern compression formats are supported out-of-the-box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured logging:&lt;/strong&gt; Bring a more defined format and details to your logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus metrics and tracing:&lt;/strong&gt; Built-in Prometheus support!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2 &amp;amp; HTTP/3:&lt;/strong&gt; Native support for HTTPS, HTTP/2 and HTTP/3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS Automation:&lt;/strong&gt; Automatic HTTPS certificate generation, renewal and revocation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful reload:&lt;/strong&gt; Deploy your apps with zero downtime thanks to graceful reloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supports PHP extension:&lt;/strong&gt; FrankenPHP supports the most popular PHP extensions, including OPcache and XDebug.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rbhri12vk1ri7zdffj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rbhri12vk1ri7zdffj2.png" alt="Modern Webserver For PHP" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One command to run them all&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Docker
docker run -v $PWD:/app -p 443:443 dunglas/frankenphp

# Static binary
./frankenphp php-server

# Command-line script
./frankenphp php-cli /path/to/your/script.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of using FrankenPHP
&lt;/h2&gt;

&lt;p&gt;There are many benefits to using FrankenPHP, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved performance:&lt;/strong&gt; FrankenPHP can significantly improve the performance of your PHP app, especially in worker mode.
Reduced complexity: FrankenPHP simplifies your deployment process by eliminating the need for separate PHP-FPM and Nginx processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased security:&lt;/strong&gt; FrankenPHP automatically supports HTTPS, HTTP/2, and HTTP/3, which helps to keep your app secure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More features:&lt;/strong&gt; FrankenPHP offers several features that are not available in traditional PHP application servers, such as early hints and real-time capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who should use FrankenPHP?
&lt;/h2&gt;

&lt;p&gt;FrankenPHP is an excellent option for developers looking to enhance the performance, security, and simplicity of deploying their PHP applications. It is particularly well-suited for projects built with Symfony, Laravel, and WordPress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with FrankenPHP
&lt;/h2&gt;

&lt;p&gt;Starting with FrankenPHP is simple. Download the FrankenPHP binary from the website and follow the steps provided in the documentation. Additionally, there are numerous tutorials and blog posts available online to guide you through the process.&lt;/p&gt;

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

&lt;p&gt;FrankenPHP is a robust and user-friendly application server designed for PHP. It enhances the performance, and security, and simplifies the deployment process of PHP applications. If you're seeking a cutting-edge solution to streamline your PHP development workflow, FrankenPHP is an excellent choice that offers both efficiency and modern features.&lt;/p&gt;

&lt;p&gt;Additional resources&lt;br&gt;
FrankenPHP website: &lt;a href="https://frankenphp.dev/" rel="noopener noreferrer"&gt;https://frankenphp.dev/&lt;/a&gt;&lt;br&gt;
FrankenPHP documentation: &lt;a href="https://frankenphp.dev/docs/" rel="noopener noreferrer"&gt;https://frankenphp.dev/docs/&lt;/a&gt;&lt;br&gt;
FrankenPHP on GitHub: &lt;a href="https://github.com/dunglas/frankenphp" rel="noopener noreferrer"&gt;https://github.com/dunglas/frankenphp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>frankenphp</category>
      <category>laravel</category>
      <category>symfony</category>
    </item>
    <item>
      <title>Build DOCKER multi-platform image using buildx REMOTE builder NODE</title>
      <dc:creator>Aboozar Ghaffari</dc:creator>
      <pubDate>Wed, 02 Aug 2023 21:37:43 +0000</pubDate>
      <link>https://dev.to/aboozar/build-docker-multi-platform-image-using-buildx-remote-builder-node-5631</link>
      <guid>https://dev.to/aboozar/build-docker-multi-platform-image-using-buildx-remote-builder-node-5631</guid>
      <description>&lt;p&gt;Running applications on different operating systems and processor architectures is a common scenario, so it is a common practice to build separate distributions for different platforms. This is not easy to achieve when the platform we use to develop the application is different from the target platform for deployment. For example, developing an application on an x86 architecture and deploying it to a machine on an ARM platform usually requires preparing the ARM platform infrastructure for development and compilation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I recently purchased the new Apple M1 Pro MacBook, which is a high-performance laptop. The M1 Pro (aarch64) processor is very fast and very friendly on the battery, but as I mentioned there are also some - not so small - issues associated with working on a new chip architecture.&lt;/p&gt;

&lt;p&gt;I’ve tried to create a few multi-platform docker images with buildx and some are just not correctly emulated on the M1.&lt;br&gt;
The parallelism of buildx was also an issue but the emulation gave me the most trouble.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Use buildx remote node(s) to build the image on a native architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More than one docker-enabled device in your network or on the internet like:

&lt;ul&gt;
&lt;li&gt;Virtual Machine / Server&lt;/li&gt;
&lt;li&gt;Raspberry Pi&lt;/li&gt;
&lt;li&gt;Laptop &lt;/li&gt;
&lt;li&gt;Desktop&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;ssh access to these devices&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In my case I have a CX11 VM on &lt;a href="https://hetzner.cloud/?ref=fpAL7qHPphtl" rel="noopener noreferrer"&gt;HETZNER&lt;/a&gt; that is &lt;code&gt;**amd64/x86_64**&lt;/code&gt; based and my own M1 Pro that is &lt;code&gt;**arm64/aarch64**&lt;/code&gt; based. Since Hetzner now offers arm64 machines, you can also do it the other way around too.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I did do this?
&lt;/h2&gt;




&lt;h2&gt;
  
  
  Step 1: Installation
&lt;/h2&gt;

&lt;p&gt;Since the newer versions of Docker, Buildx (Buildkit) is a built-in function, to check its availability, use the following command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

❯ docker buildx version
github.com/docker/buildx v0.11.1 b4df08551fb12eb2ed17d3d9c3977ca0a903415a


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 2: Setup ssh access for your remote node
&lt;/h2&gt;

&lt;p&gt;The remote host where we also want to run Docker needs to be configured with a password-less SSH connection. This post will not explain how to do that as there are many articles explaining how to set up public/private key access to a device.&lt;/p&gt;

&lt;p&gt;If you already have the keys you can copy them to your target device like so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ssh-copy-id USERNAME@TARGET_VM_HOST


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To run a command with the &lt;strong&gt;user environment available&lt;/strong&gt; you need to make sure your sshd service allows it.&lt;br&gt;
When running a command through ssh you will have a limited environment and that needs to be adjusted.&lt;/p&gt;

&lt;p&gt;To have a correct environment where docker is known you need to set the &lt;code&gt;#PermitUserEnvironment no&lt;/code&gt; property to &lt;code&gt;PermitUserEnvironment yes&lt;/code&gt; in the &lt;code&gt;/etc/ssh/sshd_conf&lt;/code&gt; file on your VM. &lt;br&gt;
When this is adjusted you need to restart the sshd service. On my CX11 VM with the Ubuntu server, I used this command. It might be different for your device:&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 sshd


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you have to set the environment for ssh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;login to your VM through the terminal (ssh USER_HERE@TARGET_VM_HOST)&lt;/li&gt;
&lt;li&gt;cd ~/.ssh
create a file called &lt;strong&gt;environment&lt;/strong&gt; with the following value in it&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;the last &lt;code&gt;/usr/local/bin&lt;/code&gt; is where the docker command lives. So now it will be available.&lt;/p&gt;

&lt;p&gt;Check if you can run docker with the command below from local machine/laptop. It should work:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker &lt;span class="nt"&gt;-H&lt;/span&gt; ssh://USERNAME_HERE@TARGET_VM_HOST info


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Do not forget to change the command's values to appropriate ones for your situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create a buildx local node
&lt;/h2&gt;

&lt;p&gt;Let’s first create the local platform. In my case that is the Apple M1 Pro node. It should build all the arm64/aarch64 targets.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker buildx create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; local_remote_builder &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node&lt;/span&gt; local_remote_builder &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/mips64le,linux/mips64,linux/arm/v8,linux/arm/v7,linux/arm/v6 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--driver-opt&lt;/span&gt; env.BUILDKIT_STEP_LOG_MAX_SIZE&lt;span class="o"&gt;=&lt;/span&gt;10000000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--driver-opt&lt;/span&gt; env.BUILDKIT_STEP_LOG_MAX_SPEED&lt;span class="o"&gt;=&lt;/span&gt;10000000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I’ve played a bit with the settings but this seems to work best for me. I will update as needed or if I find settings that work even better.&lt;/p&gt;

&lt;p&gt;Now we have a local config for a builder called local_remote_builder.&lt;/p&gt;

&lt;p&gt;You can check if you have it by running &lt;code&gt;docker buildx ls&lt;/code&gt; command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

NAME/NODE   DRIVER/ENDPOINT     STATUS PLATFORMS
local_remote_builder &lt;span class="k"&gt;*&lt;/span&gt; docker-container
    local_remote_builder unix:///var/run/docker.sock running linux/arm64&lt;span class="k"&gt;*&lt;/span&gt;, linux/riscv64&lt;span class="k"&gt;*&lt;/span&gt;, linux/ppc64le&lt;span class="k"&gt;*&lt;/span&gt;, linux/s390x&lt;span class="k"&gt;*&lt;/span&gt;, linux/mips64le&lt;span class="k"&gt;*&lt;/span&gt;, linux/mips64&lt;span class="k"&gt;*&lt;/span&gt;, linux/arm/v7&lt;span class="k"&gt;*&lt;/span&gt;, linux/arm/v6&lt;span class="k"&gt;*&lt;/span&gt;, linux/amd64, linux/amd64/v2, linux/386



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 4: Create a target buildx remote node
&lt;/h2&gt;

&lt;p&gt;In my case, this will be the amd64/x86_64 builder node. The platforms corresponding to that architecture should be sent there.&lt;br&gt;
We have already configured the SSH access and the environment and tested that docker can access it.&lt;/p&gt;

&lt;p&gt;Now we need to add it to the buildx target&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker buildx create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; local_remote_builder &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--append&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--node&lt;/span&gt; intelarch &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/386 &lt;span class="se"&gt;\&lt;/span&gt;
    ssh://USERNAME@TARGET_VM_HOST &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--driver-opt&lt;/span&gt; env.BUILDKIT_STEP_LOG_MAX_SIZE&lt;span class="o"&gt;=&lt;/span&gt;10000000 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--driver-opt&lt;/span&gt; env.BUILDKIT_STEP_LOG_MAX_SPEED&lt;span class="o"&gt;=&lt;/span&gt;10000000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not forget to change the command's values to appropriate ones for your situation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command will append the remote node to the local_remote_builder and call the node intelarch. You can check it again by running &lt;code&gt;docker buildx ls&lt;/code&gt; command again:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

NAME/NODE              DRIVER/ENDPOINT        STATUS  BUILDKIT             PLATFORMS
local_remote_builder &lt;span class="k"&gt;*&lt;/span&gt; docker-container                                    
  local_remote_builder orbstack               running v0.11.6              linux/arm64&lt;span class="k"&gt;*&lt;/span&gt;, linux/riscv64&lt;span class="k"&gt;*&lt;/span&gt;, linux/ppc64le&lt;span class="k"&gt;*&lt;/span&gt;, linux/s390x&lt;span class="k"&gt;*&lt;/span&gt;, linux/mips64le&lt;span class="k"&gt;*&lt;/span&gt;, linux/mips64&lt;span class="k"&gt;*&lt;/span&gt;, linux/arm/v7&lt;span class="k"&gt;*&lt;/span&gt;, linux/arm/v6&lt;span class="k"&gt;*&lt;/span&gt;, linux/amd64, linux/amd64/v2, linux/386
  intelarch            ssh://aboozar@167.21.183.24 running v0.11.6              linux/amd64&lt;span class="k"&gt;*&lt;/span&gt;, linux/386&lt;span class="k"&gt;*&lt;/span&gt;, linux/amd64/v2, linux/amd64/v3


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 5: buildx use and bootstrap
&lt;/h2&gt;

&lt;p&gt;In order to start using this builder setup we need to tell buildx to start using it and we need to bootstrap it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker buildx use local_remote_builder
docker buildx inspect &lt;span class="nt"&gt;--bootstrap&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;output:&lt;/p&gt;

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

#1 [intelarch internal] booting buildkit
#1 starting container buildx_buildkit_intelarch
#1 ...

#2 [localremote_builder internal] booting buildkit
#2 pulling image moby/buildkit:buildx-stable-1 1.6s done
#2 creating container buildx_buildkit_local_remote_builder 0.6s done
#2 DONE 2.3s

#1 [intelarch internal] booting buildkit
#1 starting container buildx_buildkit_intelarch 3.6s done
#1 DONE 3.6s
Name:   localremote_builder
Driver: docker-container

Nodes:
Name:      local_remote_builder
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64*, linux/riscv64*, linux/ppc64le*, linux/s390x*, linux/mips64le*, linux/mips64*, linux/arm/v7*, linux/arm/v6*, linux/amd64, linux/amd64/v2, linux/386

Name:      intelarch
Endpoint:  ssh://aboozar@167.21.183.24
Status:    running
Platforms: linux/amd64*, linux/386*, linux/amd64/v2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 6: Build a multi-platform image
&lt;/h2&gt;

&lt;p&gt;The command below will build for amd64 and arm64 but will direct the amd64 build to the remote node and the arm64 build will be done on the local machine.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker buildx build &lt;span class="nt"&gt;--platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux/amd64,linux/arm64/v8 &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; name/target:tag &lt;span class="nb"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will result in something like this on the docker hub:&lt;/p&gt;

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




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

&lt;p&gt;The most obvious issue in this setup is that I can only build for multiple platforms when within my own network.&lt;br&gt;
That is not necessarily true if you used a remote ssh accessible host or IP. I did not do that and that limits me to these builds when I have my remote node available in the network. For now, that is not a real issue for me.&lt;/p&gt;

&lt;p&gt;It solved my concurrency problem. I had one build where I had to start the server, in order to configure it, during the docker build. Buildx does this in parallel and that gave me a port conflict as one was a bit faster but not ready when the other also tried to start. That was a problem when I tried to build all on only my local node. When I added the remote node this problem went away as the port was used on a completely different machine.&lt;/p&gt;

&lt;p&gt;Overall, I am currently content with this solution.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>cicd</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
