<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Adam Craig Johnston | Software Developer</title>
	<atom:link href="https://adamjohnston.me/feed/" rel="self" type="application/rss+xml" />
	<link>https://adamjohnston.me</link>
	<description>Software Developer, Technology Enthusiast, Retro and Husband and Dad based in Melbourne.</description>
	<lastBuildDate>Mon, 03 Aug 2026 12:31:11 +0000</lastBuildDate>
	<language>en-AU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.12</generator>
<site xmlns="com-wordpress:feed-additions:1">140396600</site>	<item>
		<title>Securing WordPress with Docker and AWS Lightsail</title>
		<link>https://adamjohnston.me/securing-wordpress-with-docker-and-aws-lightsail/</link>
					<comments>https://adamjohnston.me/securing-wordpress-with-docker-and-aws-lightsail/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Mon, 03 Aug 2026 12:31:11 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1336</guid>

					<description><![CDATA[Summary In this chapter, we will improve the security of our WordPress stack by moving the database passwords out of the main docker-compose.yml file. Instead of storing passwords directly inside the Compose file, we will use Docker Secrets in conjunction with Docker Swarm. This allows the mysql, wordpress, and wpcli services to read password values [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Summary</h2>
<p>In this chapter, we will improve the security of our WordPress stack by moving the database passwords out of the main <code>docker-compose.yml</code> file.</p>
<p>Instead of storing passwords directly inside the Compose file, we will use Docker Secrets in conjunction with Docker Swarm. This allows the <code>mysql</code>, <code>wordpress</code>, and <code>wpcli</code> services to read password values from files mounted inside the running containers.</p>
<p>Sample folder for this chapter:</p>
<pre><code class="language-bash">cd wordpressawslightsailsamples/Securing_WordPress_with_Docker_and_AWS_Lightsail
</code></pre>
<p>This folder contains the <code>docker-compose.yml</code> file used throughout this chapter:</p>
<h2>Understanding WordPress Security with Docker Compose</h2>
<h3>What Are Docker Secrets?</h3>
<p>We will use Docker Secrets to improve the security of our WordPress stack.</p>
<p>Docker Secrets provide a secure and reliable way to manage sensitive information required by containers at runtime. This includes database passwords, usernames, and other credentials that should not be stored directly inside a <code>docker-compose.yml</code> file.</p>
<pre><code class="language-yml">
services:
  mysql:
    image: mysql:latest
    
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
    ports:
      - "3306:3306"
    secrets:
      - mysql_password
      - mysql_root_password
      
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - wp-network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  wordpress:
    depends_on:
       - mysql
    image: wordpress:latest
    environment:
       WORDPRESS_DB_HOST: mysql:3306
       WORDPRESS_DB_NAME: wordpress
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
     
       WORDPRESS_DEBUG: 1
      
    secrets:
      - mysql_password
    ports:
      - "80:80"
    volumes:
      - wp_html:/var/www/html
    networks:
      - wp-network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  wpcli:
    image: wordpress:cli
    entrypoint: wp
    working_dir: /var/www/html
    volumes:
      - wp_html:/var/www/html
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
    secrets:
      - mysql_password
    networks:
      - wp-network
    deploy:
      replicas: 0

volumes:
  wp_html:
    external: true
  mysql_data:
    external: true

networks:
  wp-network:
   driver: overlay

secrets:
  mysql_root_password:
    external: true
  mysql_password:
    external: true
</code></pre>
<p>Docker Secrets require Docker Swarm when deploying services with <code>docker stack deploy</code>. Before we can use secrets in our WordPress stack, we need to make sure Swarm mode is enabled on our Docker server, whether it is running on Lightsail or Docker Desktop.</p>
<p>Docker Swarm is Docker’s built-in tool for managing and running containers as services, making it suitable for deploying and managing our WordPress stack.</p>
<h3>1. Check Whether Docker Swarm Is Already Enabled</h3>
<p>To determine whether the Docker host <code>MyUbuntuInstance</code> is already part of a Docker Swarm, run:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance node ls
</code></pre>
<p>If Swarm mode has not yet been initialised, you may encounter an error similar to the following:</p>
<pre><code class="language-text">Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
</code></pre>
<p>This indicates that Docker is running, but the server has not yet been configured as a Swarm manager.</p>
<h3>2. Initialise Docker Swarm</h3>
<p>To initialise Docker Swarm on the remote Docker host <code>MyUbuntuInstance</code>, run:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance swarm init
</code></pre>
<p>Docker should return output similar to the following:</p>
<pre><code class="language-text">Swarm initialized: current node (nyj0pha0ecxkwqd7eld75tv0v) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-60tdhafh6cak85ol8n5lx4okr9fhfoc3kloncihy4hmdlyf2gw-0nxhnq8gpdau3su0g36ybasu8 172.26.2.42:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
</code></pre>
<p>This indicates that Swarm mode has been successfully enabled and that the current server is now functioning as the Swarm manager.</p>
<h3>3. Check the Swarm Node List Again</h3>
<p>Run the following command again to confirm that the node is now part of the Swarm:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance node ls
</code></pre>
<p>You should see output similar to the following:</p>
<pre><code class="language-text">ID                            HOSTNAME         STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
nyj0pha0ecxkwqd7eld75tv0v *   ip-172-26-2-42   Ready     Active         Leader           28.4.0
</code></pre>
<h3>4. Why Use Docker Secrets?</h3>
<p>In the previous chapter, <code>Docker Compose and WordPress</code>, we stored the passwords directly inside the sample <code>docker-compose.yml</code> file:</p>
<pre><code class="language-yaml">MYSQL_ROOT_PASSWORD: wordpress
MYSQL_PASSWORD: wordpress
WORDPRESS_DB_PASSWORD: wordpress
</code></pre>
<p>While this approach is suitable for a simple example, storing passwords directly in the Compose file is not considered a best practice for secure configurations.</p>
<p>In this chapter, we will move these password values to Docker Secrets. Instead of including the passwords directly in <code>docker-compose.yml</code>, the services will retrieve them from secret files at runtime:</p>
<pre><code class="language-yaml">MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
</code></pre>
<h3>5. Set Up the Docker Secrets</h3>
<p>Before deploying the WordPress stack, we need to create the Docker Secrets that will be used by the MySQL and WordPress services.</p>
<p>We will use the <code>docker secret create</code> command to create each secret.</p>
<h2>Create the Secrets in Docker</h2>
<h4>1. Create the <code>mysql_password</code> and <code>mysql_root_password</code> Secrets</h4>
<p>When creating a password file for a MySQL Docker Secret, make sure the file does not contain a trailing carriage return or line-feed character. An extra newline becomes part of the password and can cause MySQL authentication errors when the secret is read.</p>
<p>Reference: <a href="https://github.com/docker-library/mysql/issues/501#issuecomment-427443301">Docker MySQL newline issue</a></p>
<h4><code>mysql_password</code></h4>
<h5>Windows</h5>
<pre><code class="language-powershell">Set-Content -Path .\mysql_password.txt -Value "wordpress" -NoNewline:$true
docker -H ssh://MyUbuntuInstance secret create mysql_password .\mysql_password.txt
</code></pre>
<h5>macOS / Linux</h5>
<pre><code class="language-bash">printf '%s' 'wordpress' &gt; mysql_password.txt
docker -H ssh://MyUbuntuInstance secret create mysql_password ./mysql_password.txt
</code></pre>
<h4><code>mysql_root_password</code></h4>
<h5>Windows</h5>
<pre><code class="language-powershell">Set-Content -Path .\mysql_root_password.txt -Value "wordpress" -NoNewline:$true
docker -H ssh://MyUbuntuInstance secret create mysql_root_password .\mysql_root_password.txt
</code></pre>
<h5>macOS / Linux</h5>
<pre><code class="language-bash">printf '%s' 'wordpress' &gt; mysql_root_password.txt
docker -H ssh://MyUbuntuInstance secret create mysql_root_password ./mysql_root_password.txt
</code></pre>
<h4>2. List the Secrets</h4>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance secret ls
</code></pre>
<pre><code class="language-text">ID                          NAME                  DRIVER    CREATED       UPDATED
z7w3jg9l8mascak2h46i073g0   mysql_password                  4 weeks ago   4 weeks ago
ucu7gnnsaw41wdrt8n2dcdpgd   mysql_root_password             4 weeks ago   4 weeks ago
</code></pre>
<h4>3. Stop the Docker Compose Stack from <code>Docker Compose and WordPress</code></h4>
<p>Before deploying the updated WordPress stack that uses Docker Secrets, stop the Docker Compose stack created in the previous chapter, <code>Docker Compose and WordPress</code>.</p>
<p>Change to the sample directory containing the previous <code>docker-compose.yml</code> file:</p>
<pre><code class="language-bash">cd wordpressawslightsailsamples/Docker_Compose_and_Wordpress
</code></pre>
<p>Shut down and remove the containers and networks created by that Compose project:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance compose down
</code></pre>
<p>The named volumes remain in place, so your WordPress files and MySQL database data can be used again when you deploy the updated stack.</p>
<h4>4. Deploy the New WordPress Stack</h4>
<p>Change to the sample directory that contains the new <code>docker-compose.yml</code> file:</p>
<pre><code class="language-bash">cd wordpressawslightsailsamples/Securing_WordPress_with_Docker_and_Lightsail
</code></pre>
<p>Deploy the stack:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance stack deploy -c docker-compose.yml wordpress-stack
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker</code></strong> runs the Docker command-line interface.</li>
<li><strong><code>-H ssh://MyUbuntuInstance</code></strong> connects Docker to the remote Lightsail instance over SSH.</li>
<li><strong><code>stack deploy</code></strong> creates a new Docker Swarm stack or updates an existing stack.</li>
<li><strong><code>-c docker-compose.yml</code></strong> specifies the Docker Compose file that defines the WordPress services, networks, volumes, and secrets.</li>
<li><strong><code>wordpress-stack</code></strong> specifies the Docker stack name used as a prefix for services, networks, and other deployment resources.</li>
</ul>
<h4>5. Verify the WordPress Stack Services</h4>
<p>List the services deployed as part of <code>wordpress-stack</code>:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance stack services wordpress-stack
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker</code></strong> runs the Docker command-line interface.</li>
<li><strong><code>-H ssh://MyUbuntuInstance</code></strong> connects Docker to the remote Lightsail instance over SSH.</li>
<li><strong><code>stack services</code></strong> lists the services deployed within the specified stack.</li>
<li><strong><code>wordpress-stack</code></strong> specifies the name of the stack.</li>
</ul>
<p>The command shows details for each service, including its name, replica status, container image, and published ports.</p>
<pre><code class="language-text">ID             NAME                        MODE         REPLICAS   IMAGE              PORTS
17zb0ywotjss   wordpress-stack_mysql       replicated   1/1        mysql:latest       *:3306-&gt;3306/tcp
v0v2ameyqd2x   wordpress-stack_wordpress   replicated   1/1        wordpress:latest   *:80-&gt;80/tcp
f0jxrzcv873r   wordpress-stack_wpcli       replicated   0/0        wordpress:cli
</code></pre>
<h4>6. Retrieve the Lightsail Static IP Address</h4>
<p>Using the AWS CLI, you can retrieve the current static IP address assigned to the Lightsail instance <code>MyUbuntuInstance</code>:</p>
<pre><code class="language-bash">aws lightsail get-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h4>Access WordPress Remotely</h4>
<p>Once the containers are running, open a web browser and go to:</p>
<pre><code class="language-url">http://ipAddress
</code></pre>
<p>Replace <code>ipAddress</code> with the static IP address returned by the AWS CLI command.</p>
<h4>7. Stopping the WordPress Stack with Docker Stack</h4>
<p>To gracefully remove the WordPress stack from the remote Lightsail instance, including its associated services and containers, run:</p>
<pre><code class="language-powershell">docker -H ssh://MyUbuntuInstance stack rm wordpress-stack
</code></pre>
<h2>Further Reading</h2>
<ul>
<li><a href="https://docs.docker.com/compose/how-tos/use-secrets/">Manage secrets securely in Docker Compose</a></li>
<li><a href="https://docs.docker.com/engine/swarm/secrets/">Manage sensitive data with Docker secrets</a></li>
<li><a href="https://docs.docker.com/reference/cli/docker/stack/services/">Docker stack services</a></li>
</ul>
<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/securing-wordpress-with-docker-and-aws-lightsail/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1336</post-id>	</item>
		<item>
		<title>Docker Compose and WordPress</title>
		<link>https://adamjohnston.me/docker-compose-and-wordpress/</link>
					<comments>https://adamjohnston.me/docker-compose-and-wordpress/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sat, 25 Jul 2026 13:28:35 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1325</guid>

					<description><![CDATA[Summary This chapter walks through building and deploying a WordPress stack with Docker. It begins with a local development environment using Docker Desktop, then moves the same stack to AWS Lightsail using Docker’s remote SSH connection support. The stack includes three main components: WordPress for the website application. MySQL for the database. WP-CLI for managing [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Summary</h2>
<p>This chapter walks through building and deploying a WordPress stack with Docker. It begins with a local development environment using Docker Desktop, then moves the same stack to AWS Lightsail using Docker’s remote SSH connection support.</p>
<p>The stack includes three main components:</p>
<ul>
<li><strong>WordPress</strong> for the website application.</li>
<li><strong>MySQL</strong> for the database.</li>
<li><strong>WP-CLI</strong> for managing WordPress from the command line.</li>
</ul>
<p>These services are managed together using Docker Compose.</p>
<h2>WordPress Docker Compose Stack</h2>
<h3>Clone the Sample Project</h3>
<p>Before starting the WordPress stack, clone the sample project from GitHub:</p>
<pre><code class="language-bash">git clone https://github.com/acj1971/wordpressawslightsailsamples
</code></pre>
<p>Then move into the sample folder for this chapter:</p>
<pre><code class="language-bash">cd wordpressawslightsailsamples/Docker_Compose_and_Wordpress
</code></pre>
<p>This folder contains the <code>docker-compose.yml</code> file used throughout this chapter:</p>
<pre><code class="language-yaml">
services:
  mysql:
    image: mysql:latest
    container_name: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    ports:
      - "3306:3306"
    volumes:
      -  mysql_data:/var/lib/mysql
    networks:
      - wp-network

  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
    ports:
      - "80:80"
    volumes:
      - wp_html:/var/www/html
    depends_on:
      - mysql
    networks:
      - wp-network

  wpcli:
    image: wordpress:cli
    container_name: wpcli
    depends_on:
      - wordpress
    entrypoint: wp
    working_dir: /var/www/html
    volumes:
      - wp_html:/var/www/html
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
    networks:
      - wp-network

volumes:
  wp_html:
    external: true
  mysql_data:
    external: true

networks:
  wp-network:

</code></pre>
<h3>Understanding a Docker Compose File for WordPress</h3>
<h3>Services</h3>
<pre><code class="language-yaml">services:
</code></pre>
<p>The Docker Compose file defines a basic WordPress environment made up of three services. Each service runs in its own container and communicates with the other services through the same Docker network.</p>
<h4>MySQL Service</h4>
<pre><code class="language-yaml">mysql:
</code></pre>
<p>The <strong><code>mysql</code></strong> service runs the MySQL database container. It sets the root password, creates the WordPress database, and creates a WordPress database user. The database files are stored in the external <code>mysql_data</code> volume so they can be retained even if the container is recreated.</p>
<h5>Image</h5>
<pre><code class="language-yaml">image: mysql:latest
</code></pre>
<p>Using <code>mysql:latest</code> tells Docker to pull the most recent MySQL image rather than a fixed version. This can help keep the setup current, but the underlying version may change over time.</p>
<p>For a more predictable production setup, it is usually safer to pin the image to a specific version, such as <code>8.4</code>. Upgrading between major versions or LTS releases can introduce compatibility or upgrade issues, so version changes should be planned carefully.</p>
<h5>Container Name</h5>
<pre><code class="language-yaml">container_name: mysql
</code></pre>
<p>This assigns the container the fixed name <code>mysql</code>, making it easier to identify and manage when using Docker commands, logs, and other administration tasks.</p>
<h5>Restart</h5>
<pre><code class="language-yaml">restart: always
</code></pre>
<p>This tells Docker to automatically restart the container if it stops or if the server is restarted. For a database service such as MySQL, this helps keep the WordPress stack available after a restart.</p>
<h5>Environment</h5>
<pre><code class="language-yaml">environment:
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
</code></pre>
<p>This section configures the initial MySQL setup. It sets the root password, creates the WordPress database, and creates a WordPress database user with a password. These values are then used by the WordPress container when connecting to MySQL.</p>
<p>In this example, the values are written directly in the Compose file for clarity. In a later chapter, these values will be managed using Docker Secrets for improved security.</p>
<h5>Options Explained</h5>
<ul>
<li><strong><code>MYSQL_ROOT_PASSWORD</code></strong> sets the password for the MySQL root user. In a later step, this value should be managed using Docker Secrets for improved security.</li>
<li><strong><code>MYSQL_DATABASE</code></strong> defines the database that MySQL creates when the container starts for the first time.</li>
<li><strong><code>MYSQL_USER</code></strong> creates a database user account when the container starts.</li>
<li><strong><code>MYSQL_PASSWORD</code></strong> sets the password for the database user account. In a later step, this value should be managed using Docker Secrets for improved security.</li>
</ul>
<h5>Ports</h5>
<pre><code class="language-yaml">ports:
      - "3306:3306"
</code></pre>
<p>This maps port <code>3306</code> on the host to port <code>3306</code> inside the MySQL container. Port <code>3306</code> is the standard MySQL port, and this mapping allows external access to the database if required.</p>
<p>WordPress does not require this host port mapping when both containers are connected to the same Docker network. In that case, WordPress connects internally using <code>mysql:3306</code>.</p>
<h5>Volumes</h5>
<pre><code class="language-yaml">volumes:
      - mysql_data:/var/lib/mysql
</code></pre>
<p>This volume mapping connects the Docker volume <code>mysql_data</code> to <code>/var/lib/mysql</code> inside the container. This directory is where MySQL stores its database files.</p>
<h5>Networks</h5>
<pre><code class="language-yaml">networks:
      - wp-network
</code></pre>
<p>Docker Compose networks allow containers to communicate without relying on fixed IP addresses. When services are connected to the same network, they can find and connect to each other by service name.</p>
<p>In this setup, <code>wp-network</code> provides communication between WordPress, MySQL, and WP-CLI.</p>
<h4>WordPress Service</h4>
<pre><code class="language-yaml">wordpress:
</code></pre>
<p>The <strong><code>wordpress</code></strong> service runs the main WordPress website using the selected WordPress image. It connects to the MySQL database using the settings provided in the environment variables. Port <code>80</code> is mapped so the site can be opened in a web browser, and the WordPress files are stored in the external <code>wp_html</code> volume.</p>
<p>The WordPress service also depends on the MySQL service, so Docker Compose starts the database container before starting WordPress.</p>
<h5>Image</h5>
<pre><code class="language-yaml">image: wordpress:latest
</code></pre>
<p>Using <code>wordpress:latest</code> tells Docker to use the most recent WordPress image available. This can include the latest bug fixes, security updates, and feature improvements.</p>
<p>For production environments, consider using a specific image tag so that updates can be tested before being applied.</p>
<h5>Container Name</h5>
<pre><code class="language-yaml">container_name: wordpress
</code></pre>
<p>This assigns the container the fixed name <code>wordpress</code>, making it easier to identify and manage when using Docker commands.</p>
<h5>Restart</h5>
<pre><code class="language-yaml">restart: always
</code></pre>
<p>This tells Docker to automatically restart the WordPress container if it stops or if the server is restarted. For a web service such as WordPress, this helps keep the site available when the stack restarts.</p>
<h5>Environment</h5>
<pre><code class="language-yaml">environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
</code></pre>
<p>This section configures how the WordPress container connects to the MySQL database. It defines the database host, database name, username, and password used by WordPress.</p>
<p>These values must match the MySQL service settings so WordPress can communicate with the database correctly. In this example, the values are written directly in the Compose file for clarity, although Docker Secrets should be used for improved security.</p>
<h5>Options Explained</h5>
<ul>
<li><strong><code>WORDPRESS_DB_HOST</code></strong> tells WordPress how to connect to the database service. In this setup, <code>mysql:3306</code> points to the MySQL service on the Docker network.</li>
<li><strong><code>WORDPRESS_DB_NAME</code></strong> defines the name of the database WordPress will use.</li>
<li><strong><code>WORDPRESS_DB_USER</code></strong> defines the username WordPress uses when connecting to the database service.</li>
<li><strong><code>WORDPRESS_DB_PASSWORD</code></strong> defines the password WordPress uses when authenticating with the database service.</li>
</ul>
<p>For improved security, sensitive credentials such as the database password should be managed using Docker Secrets.</p>
<h5>Ports</h5>
<pre><code class="language-yaml">ports:
      - "80:80"
</code></pre>
<p>This maps port <code>80</code> on the host to port <code>80</code> inside the WordPress container, allowing the site to be accessed in a web browser. Port <code>443</code> can be added in a later chapter to support HTTPS.</p>
<h5>Volumes</h5>
<pre><code class="language-yaml">volumes:
      - wp_html:/var/www/html
</code></pre>
<p>This volume mapping connects the Docker volume <code>wp_html</code> to <code>/var/www/html</code> inside the container. This is where WordPress stores its site files, including the <code>wp-content</code> folder.</p>
<h5>Depends On</h5>
<pre><code class="language-yaml">depends_on:
      - mysql
</code></pre>
<p>The <code>depends_on</code> setting tells Docker Compose to start the <code>mysql</code> service before the <code>wordpress</code> service. This helps ensure that the database container starts first, so WordPress can connect to it during startup.</p>
<h5>Networks</h5>
<pre><code class="language-yaml">networks:
      - wp-network
</code></pre>
<p>For the WordPress service, the Docker network allows it to communicate with MySQL and WP-CLI using service names instead of fixed IP addresses. In this setup, <code>wp-network</code> provides that internal connection.</p>
<h4>WP-CLI Service</h4>
<pre><code class="language-yaml">wpcli:
</code></pre>
<p>The <strong><code>wpcli</code></strong> service runs the WordPress CLI image, which allows you to manage the WordPress site from the command line. It uses <code>wp</code> as its entry point, works from <code>/var/www/html</code>, and shares the same <code>wp_html</code> volume as the WordPress service so it can access the same site files.</p>
<p>It also uses the same database connection settings as the WordPress service, ensuring WP-CLI commands operate against the same WordPress installation.</p>
<h5>Image</h5>
<pre><code class="language-yaml">image: wordpress:cli
</code></pre>
<p>Using <code>wordpress:cli</code> tells Docker to use the WordPress CLI image. This image provides the <code>wp</code> command-line tool for managing a WordPress site.</p>
<h5>Container Name</h5>
<pre><code class="language-yaml">container_name: wpcli
</code></pre>
<p>This assigns the container the fixed name <code>wpcli</code>, making it easier to identify and manage when using Docker commands.</p>
<h5>Depends On</h5>
<pre><code class="language-yaml">depends_on:
      - wordpress
</code></pre>
<p>This setting tells Docker Compose to start the <code>wordpress</code> service before the <code>wpcli</code> container.</p>
<h5>Entrypoint</h5>
<pre><code class="language-yaml">entrypoint: wp
</code></pre>
<p>This configures the container to use <code>wp</code> as its default command. As a result, WP-CLI commands can be run without specifying <code>wp</code> each time.</p>
<p>For example:</p>
<pre><code class="language-bash">docker compose run --rm wpcli plugin list
</code></pre>
<h5>Working Directory</h5>
<pre><code class="language-yaml">working_dir: /var/www/html
</code></pre>
<p>This specifies <code>/var/www/html</code> as the working directory inside the container. It helps ensure that commands run from the WordPress root directory.</p>
<h5>Volumes</h5>
<pre><code class="language-yaml">volumes:
      - wp_html:/var/www/html
</code></pre>
<p>This volume mapping connects the Docker volume <code>wp_html</code> to <code>/var/www/html</code> inside the container. By sharing the same volume as the WordPress service, WP-CLI can work with the same WordPress files.</p>
<h5>Environment</h5>
<pre><code class="language-yaml">environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
</code></pre>
<p>The environment variables in the <code>wpcli</code> service mirror those used by the <code>wordpress</code> service because both containers connect to the same WordPress database. This ensures that WP-CLI commands operate on the same site data and configuration as the main WordPress application.</p>
<h5>Networks</h5>
<pre><code class="language-yaml">networks:
      - wp-network
</code></pre>
<p>For the <code>wpcli</code> service, the Docker network allows it to communicate with WordPress and MySQL using service names instead of fixed IP addresses. In this setup, <code>wp-network</code> provides that internal connection.</p>
<h3>Volumes</h3>
<pre><code class="language-yaml">volumes:
  wp_html:
    external: true
  mysql_data:
    external: true
</code></pre>
<p>This section defines two named Docker volumes: <code>wp_html</code> and <code>mysql_data</code>.</p>
<ul>
<li><strong><code>wp_html</code></strong> stores the WordPress website files.</li>
<li><strong><code>mysql_data</code></strong> stores the MySQL database files.</li>
<li><strong><code>external: true</code></strong> tells Docker Compose to use an existing Docker volume rather than creating a new one.</li>
</ul>
<p>This approach helps ensure that important data is stored independently of the containers, allowing it to persist even if the containers are recreated or updated.</p>
<h3>Networks</h3>
<pre><code class="language-yaml">networks:
  wp-network:
</code></pre>
<p>The <code>networks</code> section defines a custom Docker network named <code>wp-network</code>.</p>
<p>Docker Compose networks provide a straightforward way for containers to communicate without relying on fixed IP addresses. By connecting services to the same network, Docker allows them to discover and connect to one another using their service names.</p>
<p>In this stack, <code>wp-network</code> enables communication between WordPress, MySQL, and WP-CLI.</p>
<h3>Start the WordPress Stack Using Docker Desktop</h3>
<p>From inside the project folder <code>wordpressawslightsailsamples/Docker_Compose_and_Wordpress</code>, run:</p>
<pre><code class="language-bash">docker compose up -d
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker compose</code></strong> manages multi-container applications using a Compose file.</li>
<li><strong><code>up</code></strong> creates and starts the services defined in <code>docker-compose.yml</code>.</li>
<li><strong><code>-d</code></strong> runs the containers in the background in detached mode.</li>
</ul>
<h3>What Starts Automatically</h3>
<p>Docker Compose will create and start the following services:</p>
<ul>
<li><strong><code>mysql</code></strong> initializes the database and stores data in the <code>mysql_data</code> volume.</li>
<li><strong><code>wordpress</code></strong> runs the web server and serves the site on port <code>80</code>.</li>
<li><strong><code>wpcli</code></strong> provides the command-line tool for managing the WordPress site.</li>
</ul>
<p>On the first run, Docker downloads the required images:</p>
<ul>
<li><code>mysql</code></li>
<li><code>wordpress</code></li>
<li><code>wordpress:cli</code></li>
</ul>
<p>Docker then creates the containers, connects them to the <code>wp-network</code>, and attaches the external volumes <code>wp_html</code> and <code>mysql_data</code> to the appropriate services.</p>
<h3>Verify the Stack Is Running</h3>
<h4>Option 1: Command Line</h4>
<p>Run the following command:</p>
<pre><code class="language-bash">docker compose ps
</code></pre>
<p>You should see the WordPress, MySQL, and WP-CLI services listed.</p>
<h4>Option 2: Docker Desktop UI</h4>
<p>Open Docker Desktop and locate the project container group, for example:</p>
<ul>
<li><code>wordpress-docker</code></li>
</ul>
<p>You should see the following services listed:</p>
<ul>
<li><code>mysql</code></li>
<li><code>wordpress</code></li>
<li><code>wpcli</code></li>
</ul>
<p>You can click each container to:</p>
<ul>
<li>View logs.</li>
<li>Inspect environment variables.</li>
<li>Restart or stop the container.</li>
</ul>
<h4>Option 3: Start the Stack and Configure WordPress with WP-CLI</h4>
<p>Start the WordPress stack in the background:</p>
<pre><code class="language-bash">docker compose up -d
</code></pre>
<p>Once the containers are running, you can use WP-CLI to complete the initial WordPress setup from the command line. This will be covered in more detail in the <code>Docker and WP-CLI</code> chapter.</p>
<pre><code class="language-bash">docker compose run --rm wpcli core install --url="http://localhost" \
  --title="My WordPress Site" \
  --admin_user="admin" \
  --admin_password="password" \
  --admin_email="admin@example.com"
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker compose</code></strong> manages multi-container applications using a Compose file.</li>
<li><strong><code>run --rm</code></strong> starts a temporary container and removes it when the command finishes.</li>
<li><strong><code>wpcli</code></strong> is the Docker Compose service that runs WP-CLI.</li>
<li><strong><code>core install</code></strong> runs the <code>wp core install</code> command.</li>
<li><strong><code>--url="http://localhost"</code></strong> sets the URL for the new site.</li>
<li><strong><code>--title="My WordPress Site"</code></strong> sets the name of the new site.</li>
<li><strong><code>--admin_user="admin"</code></strong> sets the username for the site administrator.</li>
<li><strong><code>--admin_password="password"</code></strong> sets the password for the administrator account. If this option is not supplied, WordPress can generate a secure password automatically.</li>
<li><strong><code>--admin_email="admin@example.com"</code></strong> sets the email address for the administrator account.</li>
</ul>
<h4>Access WordPress</h4>
<p>Once the containers are running, open a web browser and go to:</p>
<pre><code class="language-url">http://localhost
</code></pre>
<p>This opens the local WordPress site. On the first visit, WordPress should display the initial setup screen unless the site has already been configured with WP-CLI.</p>
<h3>View Logs for Troubleshooting</h3>
<p>To view container logs, run:</p>
<pre><code class="language-bash">docker compose logs -f
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker compose</code></strong> manages multi-container applications using a Compose file.</li>
<li><strong><code>logs</code></strong> displays log output from the containers.</li>
<li><strong><code>-f</code></strong> follows the logs in real time.</li>
</ul>
<h3>Stop the Stack</h3>
<p>When you have finished working with the WordPress stack, you can stop the running containers using:</p>
<pre><code class="language-bash">docker compose down
</code></pre>
<p>Because this project uses external Docker volumes, the following volumes are retained:</p>
<ul>
<li><strong><code>wp_html</code></strong> for the WordPress website files.</li>
<li><strong><code>mysql_data</code></strong> for the MySQL database files.</li>
</ul>
<h3>Use Docker Compose with AWS Lightsail</h3>
<p>The same Docker Compose stack can also be managed remotely on an AWS Lightsail instance. In this example, Docker connects to the Lightsail server over SSH using the Docker <code>-H</code> option.</p>
<h4>Verify Remote Docker Access</h4>
<p>First, confirm that Docker is available on your Lightsail instance:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance info
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker</code></strong> runs the Docker command-line interface.</li>
<li><strong><code>-H ssh://MyUbuntuInstance</code></strong> tells Docker to connect to the remote Docker host named <code>MyUbuntuInstance</code> over SSH.</li>
<li><strong><code>info</code></strong> requests detailed information about the Docker environment on the remote host.</li>
</ul>
<h4>Start the WordPress Stack with Docker Compose</h4>
<p>Once remote Docker access has been verified, start the WordPress, MySQL, and WP-CLI services on <code>MyUbuntuInstance</code>:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance compose up -d
</code></pre>
<h4>Options Explained</h4>
<ul>
<li><strong><code>docker</code></strong> runs the Docker command-line interface.</li>
<li><strong><code>-H ssh://MyUbuntuInstance</code></strong> connects Docker to the remote Lightsail instance over SSH.</li>
<li><strong><code>compose</code></strong> runs Docker Compose commands against the selected Docker host.</li>
<li><strong><code>up</code></strong> creates and starts the services defined in <code>docker-compose.yml</code>.</li>
<li><strong><code>-d</code></strong> runs the containers in the background in detached mode.</li>
</ul>
<h4>Retrieve the Lightsail Static IP Address</h4>
<p>Using the AWS CLI, you can retrieve the current static IP address assigned to the Lightsail instance <code>MyUbuntuInstance</code>:</p>
<pre><code class="language-bash">aws lightsail get-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h4>Access WordPress Remotely</h4>
<p>Once the containers are running, open a web browser and go to:</p>
<pre><code class="language-url">http://ipAddress
</code></pre>
<p>Replace <code>ipAddress</code> with the static IP address returned by the AWS CLI command.</p>
<h4>Stop the WordPress Stack with Docker Compose</h4>
<p>To gracefully stop the WordPress stack running on the remote Lightsail instance and remove the containers associated with the application, run:</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance compose down
</code></pre>
<p>Because this project uses external Docker volumes, the following volumes are retained:</p>
<ul>
<li><strong><code>wp_html</code></strong> for the WordPress website files.</li>
<li><strong><code>mysql_data</code></strong> for the MySQL database files.</li>
</ul>
<p>This means the site files and database are preserved even after the containers are removed.</p>
<h2>Further Reading</h2>
<ul>
<li><a href="https://docs.docker.com/compose/">Docker Compose</a></li>
<li><a href="https://docs.docker.com/reference/compose-file/services/">Services in Docker Compose</a></li>
<li><a href="https://hub.docker.com/_/mysql">MySQL Docker Official Image</a></li>
<li><a href="https://docs.percona.com/percona-server/8.0/docker-config.html">MySQL Docker environment variables</a></li>
<li><a href="https://docs.docker.com/compose/how-tos/networking/">Networking in Compose</a></li>
<li><a href="https://hub.docker.com/_/wordpress">WordPress Docker Official Image</a></li>
<li><a href="https://wordpress.org/cli/">WP-CLI</a></li>
<li><a href="https://developer.wordpress.org/cli/commands/core/install/">wp core install</a></li>
</ul>
<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/docker-compose-and-wordpress/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1325</post-id>	</item>
		<item>
		<title>AWS Lightsail Docker Volume</title>
		<link>https://adamjohnston.me/aws-lightsail-docker-volume/</link>
					<comments>https://adamjohnston.me/aws-lightsail-docker-volume/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sun, 19 Jul 2026 13:10:49 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1317</guid>

					<description><![CDATA[Summary This guide shows you how to attach an AWS Lightsail block storage disk to an Ubuntu instance, format and mount it at /data, and configure Docker so its named volumes live on that disk. This keeps your WordPress and database data on the larger block storage volume and ensures it persists across reboots (and [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Summary</h2>
<p>This guide shows you how to attach an AWS Lightsail block storage disk to an Ubuntu instance, format and mount it at <strong>/data</strong>, and configure Docker so its named volumes live on that disk. This keeps your WordPress and database data on the larger block storage volume and ensures it persists across reboots (and can survive instance rebuilds if you reattach the disk).</p>
<h3>1. Confirm your Region and Availability Zone</h3>
<p>Before you create the disk, you need the instance’s Availability Zone (AZ). The AWS Lightsail create-disk command won’t work unless you provide &#8211;availability-zone.</p>
<ul>
<li><code>lightsail-instance-config.json</code>: Get the Availability Zone from the <code>lightsail-instance-config.json</code> file created in <a href="../Lightsail_Instance_for_Docker/Lightsail_Instance_for_Docker.md">Lightsail Instance for Docker</a></li>
<li><code>AWS CLI (pull the AZ directly from Lightsail)</code>:</li>
</ul>
<pre><code class="language-bash">aws lightsail get-instances --query "instances[?name=='MyUbuntuInstance'].location.availabilityZone | [0]" --output text --profile MyUbuntuProfile
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>aws lightsail get-instances</code></strong> This command tells the AWS CLI to return details for all instances in the account/region tied to the selected profile.</li>
<li><strong><code>--query "instances[?name=='MyUbuntuInstance'].location.availabilityZone | [0]"</code></strong> <a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html">AWS CLI User Guide – Filtering output with &#8211;query</a>.</li>
<li><strong><code>--output text</code></strong> Prints the result as plain text.</li>
<li><strong><code>--profile MyUbuntuProfile</code></strong> Selects which AWS CLI profile to use. This is helpful if you have multiple accounts or credentials configured.</li>
</ul>
<h3>2. Create the Lightsail disk</h3>
<p>Create a new Lightsail block storage disk using the aws lightsail <code>aws lightsail create-disk</code> command, and provisioning in the same Availability Zone as your existing instance.</p>
<pre><code class="language-bash">aws lightsail create-disk --disk-name MyUbuntuProfile-Docker-Volume-1 --region ap-southeast-2a --size-in-gb 32 --profile MyUbuntuProfile
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>aws lightsail create-disk</code></strong> This command tells the AWS CLI to create a new block storage disk.</li>
<li><strong><code>--disk-name MyUbuntuProfile-Docker-Volume-1</code></strong> Choose a unique and descriptive name for the disk in your Lightsail account.</li>
<li><strong><code>--region ap-southeast-2a</code></strong> Despite the flag name, Lightsail expects the AZ for block storage here (e.g., ap-southeast-2a).</li>
<li><strong><code>--size-in-gb 32</code></strong> Disk size. You choose based on WordPress + DB growth, uploads, backups, etc.</li>
<li><strong><code>--profile MyUbuntuProfile</code></strong> Selects which AWS CLI profile to use. This is helpful if you have multiple accounts or credentials configured.</li>
</ul>
<h3>3. Attach the disk to your instance</h3>
<p>Now that the disk is created <code>MyUbuntuProfile-Docker-Volume-1</code>, attach it to the instance <code>MyUbuntuInstance</code> so Ubuntu can detect it as a new drive.</p>
<pre><code class="language-bash">aws lightsail attach-disk --disk-name MyUbuntuProfile-Docker-Volume-1 --disk-path /dev/xvdf --instance-name MyUbuntuInstance --profile MyUbuntuProfile
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>aws lightsail attach-disk</code></strong> This command tells the AWS CLI to attach a block storage disk to an instance.</li>
<li><strong><code>--disk-name MyUbuntuProfile-Docker-Volume-1</code></strong> The name of the Lightsail disk you created earlier. This must match exactly.</li>
<li><strong><code>--disk-path /dev/xvdf</code></strong> Device name Ubuntu will see for the newly attached disk in Ubuntu instance. This is the attachment path; in Ubuntu, it may appear as /dev/xvdf or sometimes /dev/nvme, depending on the virtualization.</li>
<li><strong><code>--instance-name MyUbuntuInstance</code></strong> Instance name you’re attaching the disk to.</li>
<li><strong><code>--profile MyUbuntuProfile</code></strong> Selects which AWS CLI profile to use. This is helpful if you have multiple accounts or credentials configured.</li>
</ul>
<h3>4. Verify attachment</h3>
<p>Now let’s confirm the command returns a quick status summary for the Lightsail block storage disk.</p>
<pre><code>aws lightsail get-disk --disk-name MyUbuntuProfile-Docker-Volume-1 --query 'disk.{name:name,state:state,attachedTo:attachedTo,path:path,isAttached:isAttached}' --output table --profile MyUbuntuProfile
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>aws lightsail get-disk</code></strong> This command tells the AWS CLI to retrieve details about one block storage disk.</li>
<li><strong><code>--disk-name MyUbuntuProfile-Docker-Volume-1</code></strong> Which disk to look up in Lightsail disk resource.</li>
<li><strong><code>--query 'disk.{name:name,state:state,attachedTo:attachedTo,path:path,isAttached:isAttached}'</code></strong> Using a <code>JMESPath</code> query extracting from the top-level disk object.</li>
<li><strong><code>--output table</code></strong> Render the result as a human-readable ASCII table &#8211; <a href="https://docs.aws.amazon.com/cli/v1/userguide/cli-usage-output-format.html">Setting the output format in the AWS CLI</a></li>
<li><strong><code>--profile MyUbuntuProfile</code></strong> Selects which AWS CLI profile to use. This is helpful if you have multiple accounts or credentials configured.</li>
</ul>
<h4>Output</h4>
<pre><code class="language-text">-----------------------------------------------------------------
|                            GetDisk                            |
+------------+--------------------------------------------------+
|  attachedTo|  MyUbuntuProfile-Docker-Volume-1-docker-1        |
|  isAttached|  True                                            |
|  name      |  MyUbuntuProfile-Docker-Volume-1                 |
|  path      |  /dev/xvdf                                       |
|  state     |  in-use                                          |
+------------+--------------------------------------------------+
</code></pre>
<h3>5. Connect to the Ubuntu instance via SSH</h3>
<p>Next, connect to the Lightsail instance via SSH so we can format and mount the disk on the Ubuntu server.</p>
<pre><code class="language-bash">ssh MyUbuntuInstance
</code></pre>
<h3>6. Identify the new disk in the Ubuntu Instance</h3>
<p>Next, we need to identify the disk that will be mounted on the system.</p>
<pre><code class="language-bash">sudo lsblk
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>sudo</code></strong> Run the command with administrator privileges.</li>
<li><strong><code>lsblk</code></strong> Run the command to display all disks, partitions, and mount points currently available on the Ubuntu server.</li>
</ul>
<h4>Output</h4>
<pre><code class="language-text">NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS

nvme1n1      259:5    0   32G  0 disk
</code></pre>
<h3>7. Create a filesystem on the new disk (only if empty)</h3>
<p>Next we need to format the disk <code>/dev/nvme1n1</code> with the XFS filesystem.</p>
<pre><code class="language-bash">sudo mkfs -t xfs /dev/nvme1n1
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>sudo</code></strong> Run the Linux command with administrator privileges.</li>
<li><strong><code>mkfs</code></strong> Is the Linux command <code>make filesystem</code>, create a new filesystem on the target disk.</li>
<li><strong><code>-t xfs</code></strong> Create the disk using the XFS filesystem type.</li>
<li><strong><code>/dev/nvme1n1</code></strong> Disk device being formatted.</li>
</ul>
<h4>Output</h4>
<pre><code class="language-text">meta-data=/dev/nvme1n1           isize=512    agcount=16, agsize=524288 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=1
         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=0
data     =                       bsize=4096   blocks=8388608, imaxpct=25
         =                       sunit=1      swidth=1 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
         =                       sectsz=512   sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
</code></pre>
<h3>8. Create a mount point (folder) and mount the disk</h3>
<p>First, create a folder that will be used as the disk’s mount location.</p>
<pre><code class="language-bash">sudo mkdir -p /data
</code></pre>
<p>Next, mount the disk to that folder.</p>
<pre><code class="language-bash">sudo mount /dev/nvme1n1 /data
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>sudo</code></strong> Run the command with administrator privileges.</li>
<li><strong><code>mount</code></strong> Is the Linux command used to attach a storage device to the filesystem.</li>
<li><strong><code>/dev/nvme1n1</code></strong> is the block device representing the disk that was identified.</li>
<li><strong><code>/data</code></strong> This is the folder where the disk will be accessible and mounted.</li>
</ul>
<p>Finally, confirm that the disk is mounted successfully using <code>df</code> utility command.</p>
<pre><code class="language-bash">df -h | grep /data
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>df</code></strong> Shows disk usage and mounted filesystems.</li>
<li><strong><code>-h</code></strong> Displays sizes in GB, MB, etc.</li>
<li><strong><code>grep /data</code></strong> Filters the output to show only the <code>/data</code> mount.</li>
</ul>
<p>This mount is temporary and will disappear after a reboot. In the next step, the disk will be added to /etc/fstab so it automatically mounts when the server starts.</p>
<h3>9. Persist the mount using <strong><code>/etc/fstab</code></strong> on reboot</h3>
<p>Before modifying the filesystem table, it is recommended to create a backup of the file. If an error is introduced while editing <strong><code>/etc/fstab</code></strong>, the system may fail to mount disks correctly during startup.</p>
<pre><code class="language-bash">sudo cp /etc/fstab /etc/fstab.orig
</code></pre>
<p>We need to use the UUID (Universally Unique Identifier) of the disk instead of the device name.<br />
This is more reliable because device names like <strong><code>/dev/nvme1n1</code></strong> can sometimes change after reboot.</p>
<pre><code class="language-bash">sudo blkid /dev/nvme1n1 
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>sudo</code></strong> Run the command with administrator privileges.</li>
<li><strong><code>blkid</code></strong> Utility command that shows block device attributes, such as UUID , filesystem type and label.</li>
<li><strong><code>/dev/nvme1n1</code></strong> Block device representing the disk.</li>
</ul>
<h4>Output</h4>
<pre><code class="language-text">/dev/nvme1n1: UUID="92a4a81e-d66f-420e-9f7a-234cbb5c681e" BLOCK_SIZE="512" TYPE="xfs"
</code></pre>
<p>Open the filesystem table configuration file, this file controls which disks are mounted automatically when the system boots.</p>
<pre><code class="language-bash">sudo nano /etc/fstab
</code></pre>
<p>Add the following line to the bottom of the file, please tab.</p>
<pre><code class="language-text">UUID=92a4a81e-d66f-420e-9f7a-234cbb5c681e  /data  xfs   defaults,nofail  0  2
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>UUID=92a4a81e-d66f-420e-9f7a-234cbb5c681e</code></strong> Unique identifier for the disk.</li>
<li><strong><code>/data</code></strong> Folder where the disk will be mounted and made accessible.</li>
<li><strong><code>xfs</code></strong> Filesystem type used when the disk was formatted.</li>
<li><strong><code>defaults,nofail</code></strong> Standard mount options. nofail prevents boot errors if the disk is missing.</li>
<li><strong><code>0</code></strong> Dump backup option, which is typically set to 0 to disable filesystem backups.</li>
<li><strong><code>2</code></strong> Order for filesystem checks during boot.</li>
</ul>
<h3>10. Reboot test</h3>
<p>Restart the server to confirm the disk mounted <code>/data</code> automatically.</p>
<pre><code class="language-bash">sudo reboot
</code></pre>
<p>Next, reconnect to the Lightsail instance via SSH.</p>
<pre><code class="language-bash">ssh MyUbuntuInstance
</code></pre>
<p>Finally, run the df command to confirm the disk is mounted successfully.</p>
<pre><code class="language-bash">df -h | grep /data
</code></pre>
<h4>Output</h4>
<pre><code class="language-text">/dev/nvme1n1      32G  660M   32G   3% /data
</code></pre>
<h3>11. Adding Docker Volume</h3>
<p>We need to ensure Docker starts after <strong><code>/data</code></strong> is mounted. it is important that <strong><code>/data</code></strong> is available before Docker starts.</p>
<p>If Docker starts before <strong><code>/data</code></strong> is mounted during system boot, it may create empty directories under <strong><code>/data</code></strong>. This can cause containers to start with missing or incorrect data.</p>
<p>To prevent this issue, add a dependency so Docker waits until <strong><code>/data</code></strong> is mounted before starting.</p>
<p>Connect to the Lightsail instance via SSH.</p>
<pre><code class="language-bash">ssh MyUbuntuInstance
</code></pre>
<p>Create a systemd override for Docker, this opens a small override file.</p>
<pre><code class="language-bash">sudo systemctl edit docker
</code></pre>
<p>Add the dependency. This tells systemd that Docker must wait until the /data mount is available before starting.</p>
<pre><code class="language-ini">[Unit]
RequiresMountsFor=/data
</code></pre>
<p>Reload systemd and restart Docker or reboot.</p>
<pre><code class="language-bash">sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl restart docker
</code></pre>
<p>Or.</p>
<pre><code class="language-bash">sudo reboot
</code></pre>
<h3>12. Preparing Docker Volumes for WordPress for Lightsail</h3>
<p>Create the folders under <strong><code>/data</code></strong> that will hold the persistent data for the WordPress files and MySQL database. Docker will later bind the named volumes to these locations.</p>
<p>Create the folders on <strong><code>/data</code></strong> that will hold the Docker volume data.</p>
<pre><code class="language-bash">sudo mkdir -p /data/volumes/wp_html
sudo mkdir -p /data/volumes/mysql
</code></pre>
<p>Create named Docker volumes backed by those folders on <strong><code>/data</code></strong>.</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance volume create wp_html --driver local --opt type=none --opt device=/data/volumes/wp_html --opt o=bind
</code></pre>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance volume create mysql_data --driver local --opt type=none --opt device=/data/volumes/mysql --opt o=bind
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>docker volume</code></strong> create creates a new Docker volume, wp_html and mysql_data are the names of the volumes.</li>
<li><strong><code>--driver</code></strong> local tells Docker to use the local volume driver.</li>
<li><strong><code>--opt type=none</code></strong> is used when creating a bind-backed volume.</li>
<li><strong><code>--opt device=...</code></strong> points Docker to the folder on your machine.</li>
<li><strong><code>--opt o=bind</code></strong> tells Docker to bind that folder into the volume.</li>
</ul>
<h4>Verify Volumes</h4>
<p>Check that Docker is using your local folders.</p>
<pre><code class="language-bash">docker -H ssh://MyUbuntuInstance volume inspect wp_html
</code></pre>
<h4>Output</h4>
<p>Docker will return JSON output describing each volume.</p>
<pre><code class="language-json">[
    {
        "CreatedAt": "2025-12-16T11:14:48Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/wp_html/_data",
        "Name": "wp_html",
        "Options": {
            "device": "/data/volumes/wp_html",
            "o": "bind",
            "type": "none"
        },
        "Scope": "local"
    }
]
</code></pre>
<pre><code class="language-bash">docker volume inspect mysql_data
</code></pre>
<h4>Output</h4>
<pre><code class="language-json">[
    {
        "CreatedAt": "2025-12-16T11:16:01Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",
        "Name": "mysql_data",
        "Options": {
            "device": "/data/volumes/mysql",
            "o": "bind",
            "type": "none"
        },
        "Scope": "local"
    }
]
</code></pre>
<h2>Further Reading</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/lightsail/latest/userguide/create-and-attach-additional-block-storage-disks-linux-unix.html">Create and attach Lightsail block storage disks to Ubuntu instances</a></li>
<li><a href="https://docs.aws.amazon.com/en_us/lightsail/latest/userguide/elastic-block-storage-and-ssd-disks-in-amazon-lightsail.html">Expand storage and performance with Lightsail block storage disks</a></li>
<li><a href="https://docs.aws.amazon.com/cli/latest/reference/lightsail/create-disk.html">AWS CLI &#8211; create-disk</a></li>
<li><a href="https://docs.aws.amazon.com/lightsail/latest/userguide/understanding-regions-and-availability-zones-in-amazon-lightsail.html">Regions and Availability Zones for Lightsail</a></li>
<li><a href="https://jmespath.org/">JMESPath is a query language for JSON</a></li>
<li><a href="https://help.ubuntu.com/community/Fstab">Introduction to fstab</a></li>
</ul>
<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/aws-lightsail-docker-volume/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1317</post-id>	</item>
		<item>
		<title>Docker Desktop volumes for WordPress</title>
		<link>https://adamjohnston.me/docker-desktop-and-volumes/</link>
					<comments>https://adamjohnston.me/docker-desktop-and-volumes/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 04:54:01 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1301</guid>

					<description><![CDATA[Summary This chapter explains how to create persistent Docker Desktop volumes for WordPress and MySQL using local folders on Windows, macOS, and Linux. Docker Desktop manages the volumes while allowing the data to remain accessible on your local machine. This ensures that your WordPress files and database data are retained when containers are stopped, removed, [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Summary</h2>
<div>
<div>This chapter explains how to create persistent Docker Desktop volumes for WordPress and MySQL using local folders on Windows, macOS, and Linux.</div>
<div>Docker Desktop manages the volumes while allowing the data to remain accessible on your local machine. This ensures that your WordPress files and database data are retained when containers are stopped, removed, or recreated.</div>
<div>In the next chapter, you will learn how this approach differs from using AWS block storage and manually mounted volumes on an AWS Lightsail instance.</div>
</div>
<h3>1. Create Local Folders for Data</h3>
<p>Choose a location on your computer where Docker will store persistent WordPress and MySQL data.</p>
<h4>Windows</h4>
<pre><code class="language-powershell">mkdir C:\docker-data\wp_html
mkdir C:\docker-data\mysql
</code></pre>
<h5>Output</h5>
<ul>
<li>C:\docker-data\wp_html for WordPress files</li>
<li>C:\docker-data\mysql for MySQL database files</li>
</ul>
<h4>macOS / Linux</h4>
<pre><code class="language-bash">mkdir -p ~/docker-data/wp_html
mkdir -p ~/docker-data/mysql
</code></pre>
<h5>Output</h5>
<ul>
<li>~/docker-data/wp_html for WordPress files</li>
<li>~/docker-data/mysql for MySQL database files</li>
</ul>
<h3>2. Create Bind-Backed Docker Volumes</h3>
<p>Create named Docker volumes that bind to the local folders you created earlier. This allows Docker to store WordPress and database data in those folders instead of inside Docker’s default internal storage.</p>
<h4>Windows</h4>
<pre><code class="language-powershell">docker volume create wp_html --driver local --opt type=none --opt device=C:\docker-data\wp_html --opt o=bind
</code></pre>
<pre><code class="language-powershell">docker volume create mysql_data --driver local --opt type=none --opt device=C:\docker-data\mysql --opt o=bind
</code></pre>
<h4>macOS / Linux</h4>
<pre><code class="language-bash">docker volume create wp_html --driver local --opt type=none --opt device=$HOME/docker-data/wp_html --opt o=bind
</code></pre>
<pre><code class="language-bash">docker volume create mysql_data --driver local --opt type=none --opt device=$HOME/docker-data/mysql_data --opt o=bind
</code></pre>
<h4>Options explained</h4>
<ul>
<li><strong><code>docker volume</code></strong> creates a new Docker volume. In this example, wp_html and mysql_data are the names of the volumes being created.</li>
<li><strong><code>--driver</code></strong> local tells Docker to use the local volume driver.</li>
<li><strong><code>--opt type=none</code></strong> is used when creating a bind-backed volume.</li>
<li><strong><code>--opt device=...</code></strong> tells Docker which folder on your machine should be used for the volume.</li>
<li><strong><code>--opt o=bind</code></strong> tells Docker to bind that folder into the volume.</li>
</ul>
<h3>3. Verify the Docker Volumes</h3>
<p>Check that Docker is using the local folders you mapped.</p>
<pre><code class="language-powershell">docker volume inspect wp_html
</code></pre>
<h4>Output</h4>
<p>Docker will return JSON describing the volume configuration.</p>
<pre><code class="language-json">[
    {
        "CreatedAt": "2026-03-17T12:01:21Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/wp_html/_data",
        "Name": "wp_html",
        "Options": {
            "device": "C:\\docker-data\\wp_html",
            "o": "bind",
            "type": "none"
        },
        "Scope": "local"
    }
]
</code></pre>
<pre><code class="language-powershell">docker volume inspect mysql_data
</code></pre>
<h4>Output</h4>
<pre><code class="language-json">[
    {
        "CreatedAt": "2026-03-17T12:00:51Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",
        "Name": "mysql_data",
        "Options": {
            "device": "C:\\docker-data\\mysql",
            "o": "bind",
            "type": "none"
        },
        "Scope": "local"
    }
]
</code></pre>
<h3>4. Start Your Containers Using the Volumes</h3>
<p>After the volumes have been created, they can be attached to your WordPress and database containers. When the containers use wp_html and mysql_data, Docker stores the data in the local folders you configured earlier rather than in Docker’s default internal storage.</p>
<h4>A typical setup maps</h4>
<p>wp_html -&gt; /var/www/html<br />
mysql_data -&gt; /var/lib/mysql</p>
<p>You can then start your containers with Docker Compose, depending on how your project is structured. Because the data is stored outside the containers, it remains available even if the containers are stopped, removed, or recreated.</p>
<p>This gives you a straightforward Docker Desktop development setup with persistent storage. WordPress files remain available between container restarts, MySQL data is retained even if containers are rebuilt, and the files stay accessible from the host machine. Another advantage is that no manual disk formatting or mounting is required.</p>
<p>Because this approach works across Windows, macOS, and Linux with Docker Desktop, it is well suited to local WordPress development, plugin testing, theme experimentation, or preparing an application before deploying it to a cloud server.</p>
<h2>Further Reading</h2>
<ul>
<li><a href="https://docs.docker.com/engine/storage/volumes/">Docker Volumes</a></li>
</ul>
<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/docker-desktop-and-volumes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1301</post-id>	</item>
		<item>
		<title>AWS Lightsail Instance for Docker</title>
		<link>https://adamjohnston.me/lightsail-instance-for-docker/</link>
					<comments>https://adamjohnston.me/lightsail-instance-for-docker/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sun, 05 Jul 2026 06:59:24 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1275</guid>

					<description><![CDATA[Summary This chapter guides you through setting up an Ubuntu Lightsail instance pre-configured for Docker, enabling you to deploy and manage containers like WordPress and MySQL Server quickly. You’ll learn how to: Generate and secure a custom SSH key pair to access the instance. Use AWS CLI commands and configuration files to launch your Lightsail [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Summary</h2>
<p>This chapter guides you through setting up an Ubuntu Lightsail instance pre-configured for Docker, enabling you to deploy and manage containers like WordPress and MySQL Server quickly.</p>
<p>You’ll learn how to:</p>
<ul>
<li>Generate and secure a custom SSH key pair to access the instance.</li>
<li>Use AWS CLI commands and configuration files to launch your Lightsail instance.</li>
<li>Apply a user-data script to automatically install Docker, Docker Compose, and supporting tools during creation.</li>
<li>Assign and attach a static IP address for reliable access.</li>
<li>Connect via SSH and verify your environment.</li>
<li>Clean up resources when they’re no longer needed.</li>
</ul>
<p>By the end of this chapter, you’ll have a fully operational AWS Lightsail instance ready to run Docker containers for WordPress, MySQL and other applications in a secure and repeatable way.</p>
<h2>Create a Custom SSH Key Pair</h2>
<p>Before running ‘aws lightsail create-instances’, you need an SSH key pair so the AWS account can associate it with the new instance. The key pair provides the secure SSH credentials required to connect to the instance after it is created. If you skip this step, you won’t have a valid .pem file to authenticate with your server. By creating the key pair first, you ensure that when you launch the instance, it can be accessed securely using your private key immediately.</p>
<p>Create a directory (e.g., MyUbuntuInstance).</p>
<h3>1. Create the SSH key pair</h3>
<p>Run this in PowerShell (Windows) or bash (Linux/macOS):</p>
<pre><code class="language-bash">aws lightsail create-key-pair --region ap-southeast-2 --key-pair-name MyUbuntuInstanceKeyPair --query privateKeyBase64 --output text &gt; MyUbuntuInstanceKeyPair.pem --profile MyUbuntuProfile
</code></pre>
<h4>Options explained:</h4>
<ul>
<li><strong><code>aws lightsail create-key-pair</code></strong> This command tells the AWS Cli to create a new Lightsail SSH key pair.</li>
<li><strong><code>--region ap-southeast-2</code></strong> Specifies the AWS region (Sydney). If you don’t set this, the AWS Cli defaults to whatever is configured in your AWS profile.</li>
<li><strong><code>--key-pair-name MyUbuntuInstanceKeyPair</code></strong> The name you’re giving to the new key pair in Lightsail. You’ll use this name later when creating an instance with &#8211;key-pair-name.</li>
<li><strong><code>--query privateKeyBase64</code></strong> Filters the command’s JSON output so that only the private key (in base64-encoded text) is returned, not the whole JSON response.</li>
<li><strong><code>--output text</code></strong> Ensures the result is output as plain text instead of JSON. Without this, you’d get JSON formatting that isn’t usable as a .pem file.</li>
<li><strong><code>&gt; MyUbuntuInstanceKeyPair.pem</code></strong> Redirects the output (the private key) into a file called MyUbuntuInstanceKeyPair.pem. This file is what you’ll use with SSH.</li>
<li><strong><code>--profile MyUbuntuProfile</code></strong> Selects which AWS CLI profile to use. This is helpful if you have multiple accounts or credentials configured.</li>
</ul>
<h3>2. Fix permissions</h3>
<p>SSH requires that your .pem file is locked down. SSH refuses to use a .pem file if it’s too “open” (i.e., readable by other users). Locking it down ensures only you can read it.</p>
<p><strong>Linux/macOS:</strong></p>
<pre><code class="language-bash">chmod 600 MyUbuntuInstanceKeyPair.pem
</code></pre>
<h4>Options explained:</h4>
<ul>
<li><strong><code>chmod</code></strong> &#8211; Change file mode (permissions).</li>
<li><strong><code>600</code></strong> &#8211; Sets permissions so that:
<ul>
<li><strong>Owner:</strong> Read and Write</li>
<li><strong>Group:</strong> No permissions</li>
<li><strong>Others:</strong> No permissions</li>
</ul>
</li>
</ul>
<p><strong>Windows PowerShell:</strong></p>
<pre><code class="language-powershell">icacls.exe MyUbuntuInstanceKeyPair.pem /inheritance:r
</code></pre>
<h4>Options explained:</h4>
<ul>
<li><strong><code>icacls.exe</code></strong>  A Windows command-line tool used to view or modify file and folder access control lists (ACLs).</li>
<li><strong><code>MyUbuntuInstanceKeyPair.pem</code></strong> Target file.</li>
<li><strong><code>/inheritance:r</code></strong> Removes inherited permissions (so the file doesn’t inherit broad access rights from the folder).</li>
</ul>
<pre><code class="language-powerhell">icacls.exe MyUbuntuInstanceKeyPair.pem /grant:r "$($env:USERNAME):(R)"
</code></pre>
<ul>
<li><strong><code>/grant:r</code></strong> Grants permissions, replacing any existing ones.</li>
<li><strong><code>"$($env:USERNAME)"</code></strong> Expands to your current Windows username.</li>
<li><strong><code>:(R)</code></strong> Read-only permission.</li>
</ul>
<h3>3. List SSH Key pair names</h3>
<pre><code class="language-bash">aws lightsail get-key-pairs --region ap-southeast-2 --query "keyPairs[].name" --output text --profile MyUbuntuProfile
</code></pre>
<h3>4. Deleting an SSH Key Pair</h3>
<p>If you no longer need the key, delete both to keep your system and AWS environment tidy.</p>
<h4>1. Delete the local .pem file</h4>
<p><strong>Linux/macOS:</strong></p>
<pre><code class="language-bash">rm MyUbuntuInstanceKeyPair.pem
</code></pre>
<p><strong>Windows PowerShell:</strong></p>
<pre><code class="language-powershell">icacls "MyUbuntuInstanceKeyPair.pem" /inheritance:e
</code></pre>
<ul>
<li><strong><code>/inheritance:e</code></strong> re-enables permission inheritance from the parent folder.</li>
<li>This means the file will now take on the normal ACLs (Access Control Lists) from its directory again, instead of being locked to just the user.</li>
</ul>
<pre><code class="language-powershell">icacls "MyUbuntuInstanceKeyPair.pem" /reset
</code></pre>
<ul>
<li><strong><code>/reset</code></strong> wipes any custom permissions on the file.</li>
<li>After this, only the default inherited permissions apply (e.g. Administrators, your user, System). This step ensures you (and Windows) can manage or delete the file normally.</li>
</ul>
<pre><code class="language-powershell">Remove-Item "MyUbuntuInstanceKeyPair.pem" -Force
</code></pre>
<ul>
<li><strong><code>Remove-Item</code></strong>  deletes the file.</li>
<li><strong><code>-Force</code></strong> bypasses prompts and ignores hidden/system attributes if set.</li>
<li>Now that inheritance is restored and ACLs are reset, Windows lets you remove the file without Access Denied errors.</li>
</ul>
<h4>2. Delete the SSH key pair from AWS Lightsail</h4>
<p>First, check which key pairs exist in your region:</p>
<pre><code class="language-bash">aws lightsail get-key-pairs --region ap-southeast-2 --query "keyPairs[].name" --output text --profile MyUbuntuProfile
</code></pre>
<p>Then delete the one you no longer need:</p>
<pre><code class="language-bash">aws lightsail delete-key-pair --key-pair-name MyUbuntuInstanceKeyPair --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h2>Creating a Lightsail Instance</h2>
<pre><code class="language-bash">aws lightsail create-instances --cli-input-json file://lightsail-instance-config.json --user-data file://userdata.bash --profile MyUbuntuProfile
</code></pre>
<h3>1. Create the Configuration File</h3>
<p>Create a new file named <strong>lightsail-instance-config.json</strong> and add:</p>
<pre><code class="language-json">{
  "instanceNames": ["MyUbuntuInstance"],
  "availabilityZone": "ap-southeast-2a",
  "blueprintId": "ubuntu_24_04",
  "bundleId": "small_3_2",
  "userData":  "",
  "keyPairName": "MyUbuntuInstanceKeyPair",
  "tags": [
    {
      "key": "Docker",
      "value": "WordPress-Docker"
    }
  ]
}

</code></pre>
<h3>2. Create external user-data file</h3>
<p>Create a new file named <strong>userdata.bash</strong> and add:</p>
<pre><code class="language-bash">#!/bin/bash

LOGFILE="/var/log/userdata.log"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $*" &gt;&gt; "$LOGFILE"
}

log "Start user-data script"

log "sudo apt-get update -y"
sudo apt-get update -y

log "apt-get install -y libarchive-tools"
sudo apt-get install -y libarchive-tools

log "apt install -y zip"
sudo apt install -y zip

log "Install BashNovusTools"
sudo mkdir -p /etc/bashnovustools &amp;&amp; curl -L https://github.com/novuslogic/BashNovusTools/releases/download/v0.1.3/BashNovusTools.v0.1.3.zip -o /tmp/bashnovustools.zip &amp;&amp; sudo bsdtar -xf /tmp/bashnovustools.zip -C /etc/bashnovustools &amp;&amp; sudo chmod +x /etc/bashnovustools/bin/*.sh &amp;&amp; echo 'export PATH=\"/etc/bashnovustools/bin:$PATH\"' | sudo tee /etc/profile.d/bashnovustools.sh

# Update Ubuntu to latest packages
log "Update Ubuntu to latest packages"
sudo /etc/bashnovustools/bin/update-ubuntu.sh

# Install Docker Engine
log "Install Docker Engine"
sudo /etc/bashnovustools/bin/install-docker-engine.sh

# Install Docker Compose
log "Install Docker Compose"
sudo /etc/bashnovustools/bin/install-docker-compose.sh

# Add ubuntu user to docker group (will take effect on next login)
log "Add ubuntu user to docker group"
sudo /usr/sbin/usermod -aG docker ubuntu || true


log "End user-data script" 

</code></pre>
<h2>Create a static IP</h2>
<h3>1. Pick a unique name for it (e.g. MyUbuntuInstanceStaticIP):</h3>
<pre><code class="language-bash">aws lightsail allocate-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h3>2. Attach a public static IP address to the instance</h3>
<pre><code class="language-bash">aws lightsail attach-static-ip --static-ip-name MyUbuntuInstanceStaticIP --instance-name MyUbuntuInstance --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h3>3. Verify</h3>
<pre><code class="language-bash">aws lightsail get-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h3>4. Test the SSH Connection</h3>
<p>Replace &lt;STATIC_IP&gt; with the address returned above:</p>
<pre><code class="language-bash">ssh -i MyUbuntuInstanceKeyPair.pem ubuntu@&lt;STATIC_IP&gt;
</code></pre>
<p>If you see a “bad permissions” warning on Linux/macOS, re-run chmod 600 MyUbuntuInstanceKeyPair.pem.<br />
On Windows, re-apply the icacls steps.</p>
<h2>Clean up resources</h2>
<p>Are you finished with your AWS Lightsail instance? Before you move on, take a few minutes to clean up all associated resources. Not only will this help you avoid surprise charges, but it will also keep your AWS account organized and secure.</p>
<h3>1. Release the Static IP</h3>
<p>If you have a static IP attached to your instance, make sure to release it first. Otherwise, AWS may keep charging you for the reserved IP.</p>
<pre><code class="language-bash">aws lightsail release-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h3>2. Delete the Instance</h3>
<p>Next, delete the AWS Lightsail instance. This action is permanent and will result in the loss of all data on the instance.</p>
<pre><code class="language-bash">aws lightsail delete-instance --instance-name MyUbuntuInstance --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h3>3. Delete the SSH Key Pair in AWS Lightsail</h3>
<p>Next, Delete the SSH Key Pair</p>
<pre><code class="language-bash">aws lightsail delete-key-pair --key-pair-name MyUbuntuInstanceKeyPair --region ap-southeast-2 --profile MyUbuntuProfile
</code></pre>
<h2>Further Reading</h2>
<ul>
<li><a href="https://github.com/novuslogic/BashNovusTools/">BashNovusTools</a></li>
<li><a href="https://docs.aws.amazon.com/lightsail/">AWS Lightsail Documentation</a></li>
<li><a href="https://docs.docker.com/">Docker Official Docs</a></li>
</ul>
<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png" data-wplink-edit="true"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/lightsail-instance-for-docker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1275</post-id>	</item>
		<item>
		<title>BashNovusTools</title>
		<link>https://adamjohnston.me/bashnovustools/</link>
					<comments>https://adamjohnston.me/bashnovustools/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sat, 27 Jun 2026 13:01:12 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<category><![CDATA[Docker]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1264</guid>

					<description><![CDATA[BashNovusTools is a collection of Linux administration scripts for common deployment and operations tasks. It provides commands for installing Docker, managing Docker access and services, and updating Ubuntu packages. The project can be used directly from source or packaged as a Snap. https://github.com/novuslogic/BashNovusTools]]></description>
										<content:encoded><![CDATA[<p>BashNovusTools is a collection of Linux administration scripts for common deployment and operations tasks. It provides commands for installing Docker, managing Docker access and services, and updating Ubuntu packages. The project can be used directly from source or packaged as a Snap.</p>
<p><a href="https://github.com/novuslogic/BashNovusTools">https://github.com/novuslogic/BashNovusTools</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/bashnovustools/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1264</post-id>	</item>
		<item>
		<title>Installing AWS CLI</title>
		<link>https://adamjohnston.me/installing-aws-cli/</link>
					<comments>https://adamjohnston.me/installing-aws-cli/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Fri, 12 Jun 2026 13:35:47 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1250</guid>

					<description><![CDATA[Summary The&#160;AWS CLI&#160;is a command-line tool that lets you manage and automate AWS services including Lightsail using PowerShell, Command Prompt, or Terminal. With AWS CLI, you can automate tasks, configure AWS resources, and streamline the deployment and management of Lightsail instances, Docker containers, and WordPress environments. Prerequisites Python (if applicable): Required only for AWS CLI [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 id="summary">Summary</h2>



<p>The&nbsp;<strong>AWS CLI</strong>&nbsp;is a command-line tool that lets you manage and automate AWS services including Lightsail using PowerShell, Command Prompt, or Terminal. With AWS CLI, you can automate tasks, configure AWS resources, and streamline the deployment and management of Lightsail instances, Docker containers, and WordPress environments.</p>



<h2 id="prerequisites">Prerequisites</h2>



<ul><li><strong>Python (if applicable):</strong><ul><li><strong>Required only for AWS CLI v1 (installed via pip):</strong>&nbsp;Python 3.7 or later recommended.</li><li><strong>AWS CLI v2:</strong>&nbsp;Python is bundled; you don&#8217;t need to install it separately.</li></ul></li><li><strong>Administrator or sudo privileges:</strong>&nbsp;Required for installation and configuration on most systems.</li></ul>



<h2 id="installation">Installation</h2>



<p><strong>Tip:</strong>&nbsp;All commands below should be run in your system&#8217;s terminal, PowerShell, or command prompt.</p>



<h3 id="windows">Windows</h3>



<h4 id="-option-1-msi-installer-"><strong>Option 1: MSI Installer</strong></h4>



<ol><li>Download the installer from the&nbsp;<a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html">official AWS CLI documentation</a>.</li><li>Run the installer (e.g.,&nbsp;<code>AWSCLIV2.msi</code>).<em>Or, run this command:</em><code>msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi</code></li></ol>



<h4 id="-option-2-chocolatey-"><strong>Option 2: Chocolatey</strong></h4>



<p><a href="https://community.chocolatey.org/packages/awscli">Chocolatey</a>&nbsp;is a command-line package manager for Windows.</p>



<p>To install or upgrade AWS CLI:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
choco upgrade awscli

</pre></div>


<h4 id="-verify-installation-"><strong>Verify Installation</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
aws --version

</pre></div>


<h3 id="linux">Linux</h3>



<h4 id="-option-1-official-bundled-installer-"><strong>Option 1: Official Bundled Installer</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;
unzip awscliv2.zip
sudo ./aws/install
rm -rf awscliv2.zip aws/

</pre></div>


<h4 id="-option-2-snap-ubuntu-debian-"><strong>Option 2: Snap (Ubuntu/Debian)</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
sudo snap install aws-cli --classic

</pre></div>


<h4 id="-verify-installation-"><strong>Verify Installation</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
aws --version

</pre></div>


<h3 id="macos">macOS</h3>



<h4 id="-option-1-homebrew-"><strong>Option 1: Homebrew</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
brew update
brew install awscli

</pre></div>


<h4 id="-verify-installation-"><strong>Verify Installation</strong></h4>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
aws --version

</pre></div>


<h2 id="creating-an-iam-user-group-for-lightsail-access">Creating an IAM User Group for Lightsail Access</h2>



<p>You can use either a&nbsp;<strong>service-linked role</strong>&nbsp;(created automatically by Lightsail) or set up a custom role with your own group and permissions.</p>



<h3 id="1-sign-in-to-the-aws-management-console">1. Sign in to the AWS Management Console</h3>



<ul><li>Go to the&nbsp;<strong>IAM (Identity and Access Management)</strong>&nbsp;service (search for &#8220;IAM&#8221; in the AWS Console search bar).</li></ul>



<h3 id="2-create-a-user-group">2. Create a User Group</h3>



<ul><li>Navigate to&nbsp;<strong>User groups</strong>&nbsp;?&nbsp;<strong>Create group</strong>.</li><li>Name your group (e.g.,&nbsp;<code>LightsailUsers</code>).</li><li>(Optional) Add users now, or skip and add later.</li><li>Click&nbsp;<strong>Next</strong>.</li></ul>



<h3 id="3-attach-permissions">3. Attach Permissions</h3>



<ul><li>In&nbsp;<strong>Attach permissions policies</strong>, search for&nbsp;<code>AdministratorAccess</code>.</li><li>Check the box for&nbsp;<code>AdministratorAccess</code>.</li><li>Click&nbsp;<strong>Next</strong>, then&nbsp;<strong>Create group</strong>.</li></ul>



<h3 id="4-add-users-if-you-didn-t-earlier-">4. Add Users (if you didn�t earlier)</h3>



<ul><li>In&nbsp;<strong>User groups</strong>, select your group.</li><li>Go to the&nbsp;<strong>Users</strong>&nbsp;tab, click&nbsp;<strong>Create user</strong>.</li></ul>



<h3 id="5-create-user-access-key">5. Create User &amp; Access Key</h3>



<ul><li>Set a username (e.g.,&nbsp;<code>developer</code>).</li><li>Leave console access unchecked (optional).</li><li>On&nbsp;<strong>Permissions</strong>, choose&nbsp;<strong>Add user to group</strong>&nbsp;and pick&nbsp;<code>LightsailUsers</code>.</li><li>Skip permission boundaries (optional).</li><li>Click&nbsp;<strong>Create user</strong>.</li></ul>



<h4 id="-create-access-key-"><strong>Create Access Key:</strong></h4>



<ul><li>In&nbsp;<strong>Users</strong>, click your user&#8217;s name.</li><li>Go to&nbsp;<strong>Security credentials</strong>&nbsp;tab, click&nbsp;<strong>Create access key</strong>.</li><li>Select&nbsp;<strong>Command Line Interface (CLI)</strong>.</li><li>Confirm recommendations and continue.</li><li>Download your credentials&nbsp;<code>.csv</code>&nbsp;and store securely.</li></ul>



<blockquote class="wp-block-quote"><p><strong>Tip:</strong>&nbsp;Tags (key-value pairs) can help organize and automate your Lightsail resources.</p></blockquote>



<h2 id="aws-cli-configuration">AWS CLI Configuration</h2>



<h3 id="1-run-the-aws-configure-command">1. Run the&nbsp;<code>aws configure</code>&nbsp;Command</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
aws configure

</pre></div>


<p>You&#8217;ll be prompted for:</p>



<ul><li><strong>AWS Access Key ID:</strong>&nbsp;(From your downloaded&nbsp;<code>.csv</code>)</li><li><strong>AWS Secret Access Key:</strong>&nbsp;(From your downloaded&nbsp;<code>.csv</code>)</li><li><strong>Default region name:</strong>&nbsp;(e.g.,&nbsp;<code>ap-southeast-2</code>)</li><li><strong>Default output format:</strong>&nbsp;(<code>json</code>,&nbsp;<code>text</code>, or&nbsp;<code>table</code>)</li></ul>



<p>These are stored as your&nbsp;<strong>default profile</strong>.</p>



<h3 id="2-add-additional-profiles-optional-">2. Add Additional Profiles (Optional)</h3>



<p>You can create multiple named profiles (for different users/accounts):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
aws configure --profile MyUbuntuProfile

</pre></div>


<h3 id="3-where-profiles-are-stored">3. Where Profiles Are Stored</h3>



<p>Profiles are kept in two files:</p>



<ul><li><strong>Linux/macOS:</strong>&nbsp;<code>~/.aws/</code></li><li><strong>Windows:</strong>&nbsp;<code>C:\Users\&lt;YourUsername&gt;\.aws\</code></li></ul>



<p><strong>Files:</strong></p>



<ul><li><strong><code>credentials</code></strong>&nbsp;&#8211; stores access keys</li><li><strong><code>config</code></strong>&nbsp;&#8211; stores region and output format</li></ul>



<p><strong>Example:</strong></p>



<p><code>~/.aws/credentials</code></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;default]
aws_access_key_id = AKIAEXAMPLE1
aws_secret_access_key = secret1

&#x5B;MyUbuntuInstance]
aws_access_key_id = AKIAEXAMPLE2
aws_secret_access_key = secret2

</pre></div>


<p><code>~/.aws/config</code></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;default]
region = ap-southeast-2
output = json

&#x5B;profile MyUbuntuInstance]
region = us-west-2
output = table

</pre></div>


<h2 id="using-multi-profiles">Using Multi-Profiles</h2>



<p>Multi-profiles allow you to easily switch between AWS accounts, users, or environments from a single machine.</p>



<ul><li><strong>View all profiles:</strong><code>aws configure list-profiles</code></li><li><strong>Use a profile:</strong><code>aws s3 ls --profile default aws ec2 describe-instances --profile MyUbuntuProfile</code></li></ul>



<h2 id="further-reading">Further Reading</h2>



<ul><li><a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html">AWS CLI Official Docs &#8211; Installation &amp; Configuration</a></li></ul>


<p><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png" data-wplink-edit="true"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></p>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/installing-aws-cli/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1250</post-id>	</item>
		<item>
		<title>Installing Desktop Docker</title>
		<link>https://adamjohnston.me/installing-desktop-docker/</link>
					<comments>https://adamjohnston.me/installing-desktop-docker/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sat, 06 Jun 2026 11:33:34 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1226</guid>

					<description><![CDATA[Summary For Local Docker Development. We could use Docker Engine, which is the primary container runtime that runs directly on Linux and Windows servers. It is built for production use because it is lightweight, stable, and can be automated with command-line tools, system services, and CI/CD pipelines. This setup provides the performance and control necessary [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2 id="summary">Summary</h2>
<p>For <strong>Local Docker Development</strong>. We could use Docker Engine, which is the primary container runtime that runs directly on Linux and Windows servers. It is built for production use because it is lightweight, stable, and can be automated with command-line tools, system services, and CI/CD pipelines. This setup provides the performance and control necessary to run applications at scale. On the other hand, Docker Desktop is meant for development on macOS, Windows, and Linux desktops. It includes Docker Engine inside a small virtual machine and adds a graphical dashboard, resource controls, Docker Compose, and optional Kubernetes for local testing. In short, Docker Engine runs containers in production, while Docker Desktop provides the developer with an easy way to build, test, and debug containers locally before deploying them to production.</p>
<p>We will install Docker Desktop for our development work on either Windows, Linux, or macOS.</p>
<h2 id="installing-docker-desktop">Installing Docker Desktop</h2>
<h3 id="windows-11-or-higher">Windows 11 or higher</h3>
<h4 id="1-prerequisites">1. Prerequisites</h4>
<p>Before installing Docker Desktop on Windows:</p>
<ul>
<li><code>Windows Version:</code> You need Windows 11 or a newer version. Docker Desktop uses Hyper-V and WSL2.</li>
<li><code>Hardware Requirements:</code> Your system must support virtualization technology enabled in BIOS. Docker Desktop for Windows requires at least 4GB RAM and recommends SSD storage for optimal performance.</li>
<li><code>Licensing:</code> Docker Desktop is free for individuals, education, and small businesses (&lt; 250 employees or &lt; $10 million revenue). Large enterprises need a paid plan.</li>
</ul>
<h4 id="2-install-wsl2-">2. Install WSL2:</h4>
<ul>
<li>
<ol>
<li>Open PowerShell as an Administrator, then enter the following command.</li>
</ol>
</li>
</ul>
<pre><code class="lang-powwrshell">dism.exe <span class="hljs-regexp">/online /</span>enable-feature <span class="hljs-regexp">/featurename:Microsoft-Windows-Subsystem-Linux /</span>all <span class="hljs-regexp">/norestart</span>
</code></pre>
<p>This enables the core WSL feature on your system.</p>
<ul>
<li>
<ol>
<li>Enable Virtual Machine Platform</li>
</ol>
</li>
</ul>
<p>WSL 2 requires the Virtual Machine Platform feature to run the Linux kernel:</p>
<pre><code>dism.exe <span class="hljs-regexp">/online /</span>enable-feature <span class="hljs-regexp">/featurename:VirtualMachinePlatform /</span>all <span class="hljs-regexp">/norestart</span>
</code></pre>
<ul>
<li>
<ol>
<li>Set WSL 2 as the Default Version</li>
</ol>
</li>
</ul>
<pre><code class="lang-powershell">wsl --install
wsl --<span class="hljs-keyword">set</span>-<span class="hljs-keyword">default</span>-version <span class="hljs-number">2</span>
</code></pre>
<p>If prompted, please reboot your system and launch Ubuntu from the Microsoft Store once to complete the setup.</p>
<h4 id="3-download-and-install-docker-desktop-for-windows-">3. Download and install Docker Desktop for Windows.</h4>
<h5 id="1-install-via-gui-recommended-for-most-users-download-manually">1. Install via GUI (Recommended for Most Users) &#8211; Download Manually</h5>
<p>The simplest and most popular way to install Docker Desktop on Windows 11 or higher is described here.</p>
<p>Go to the official download page:</p>
<p><a href="https://docs.docker.com/desktop/setup/install/windows-install/">Install Docker Desktop on Windows</a></p>
<ul>
<li>
<ol>
<li>Click <code>Download Docker Desktop for Windows</code>.</li>
</ol>
</li>
<li>
<ol>
<li>Save the file (for example, Docker Desktop Installer.exe).</li>
</ol>
</li>
<li>
<ol>
<li>Double-click the installer to start setup.</li>
</ol>
</li>
</ul>
<h5 id="2-curl-with-cmd-or-powershell">2. Curl with CMD or Powershell</h5>
<p>Below is a single CMD command to download and silently install Docker Desktop with the WSL 2 backend. Please run as Administrator.</p>
<pre><code class="lang-cmd">curl -L <span class="hljs-string">"https://desktop.docker.com/win/main/amd64/Docker%%20Desktop%%20Installer.exe"</span> -o <span class="hljs-string">"%TEMP%\DockerDesktopInstaller.exe"</span> &amp;&amp; start /w <span class="hljs-string">""</span> <span class="hljs-string">"%TEMP%\DockerDesktopInstaller.exe"</span> install --<span class="hljs-keyword">accept</span>-license --quiet --backend=wsl-<span class="hljs-number">2</span>
</code></pre>
<h5 id="3-chocolatey">3. Chocolatey</h5>
<p>To install Docker Desktop on Windows using Chocolatey, run the following, Open PowerShell as Administrator and run:</p>
<h6 id="1-check-if-chocolatey-is-installed">1. Check if Chocolatey is installed</h6>
<pre><code class="lang-powershell"><span class="hljs-attribute">choco -v</span>
</code></pre>
<p>If a version number, such as 2.2.2, appears, the process is complete. If not, please install it using the following command:</p>
<pre><code class="lang-powershell"><span class="hljs-keyword">Set</span>-ExecutionPolicy <span class="hljs-comment">Bypass -Scope Process -Force</span>; [<span class="hljs-keyword">System</span>.Net.ServicePointManager]::SecurityProtocol = [<span class="hljs-keyword">System</span>.Net.ServicePointManager]::SecurityProtocol -bor <span class="hljs-number">3072</span>; iex ((New-Object <span class="hljs-keyword">System</span>.Net.WebClient).DownloadString(<span class="hljs-string">'https://community.chocolatey.org/install.ps1'</span>))
</code></pre>
<h6 id="2-install-docker-desktop">2. Install Docker Desktop</h6>
<pre><code class="lang-powershell">choco <span class="hljs-keyword">install</span> docker-desktop -y
</code></pre>
<ul>
<li><code>choco</code> Chocolatey command-line tool.</li>
<li><code>install</code> Checks for a lastest version of the package and installs it.</li>
<li><code>docker-desktop</code> The name of the Docker Desktop package.</li>
<li><code>-y</code> automatically accepts prompts.</li>
</ul>
<h6 id="3-update-docker-desktop">3. Update Docker Desktop</h6>
<pre><code class="lang-powershell"> choco upgrade docker-desktop -y
`
</code></pre>
<ul>
<li><code>choco</code> Chocolatey command-line tool.</li>
<li><code>upgrade</code> Checks for a newer version of the package and installs it.</li>
<li><code>docker-desktop</code> The name of the Docker Desktop package.</li>
<li><code>-y</code> automatically accepts prompts.</li>
</ul>
<h3 id="install-on-macos">Install on macOS</h3>
<h4 id="1-prerequisites">1. Prerequisites</h4>
<p>Before installing Docker Desktop on macOS:</p>
<ul>
<li><code>MacOS Version</code> Requires macOS Monterey (12) or newer.</li>
<li><code>Hardware Requirements</code> You need an Intel or Apple Silicon (M1, M2, M3, or newer) CPU, at least 4 GB of RAM, and 2 GB of free disk space.</li>
<li><code>Virtualization</code> Make sure Rosetta 2 is enabled for Apple Silicon, or Hypervisor Framework is enabled for Intel.</li>
<li><code>Licensing</code> Same free-tier rules apply as Windows.</li>
</ul>
<p>Docker Desktop for macOS can be installed in three ways:</p>
<h5 id="1-install-via-gui-recommended-for-most-users-">1. Install via GUI (Recommended for Most Users)</h5>
<ul>
<li>
<ol>
<li>Download Installer &#8211; Visit the official Docker Desktop for Mac download page <a href="https://docs.docker.com/desktop/setup/install/mac-install/">Install Docker Desktop on Mac</a>.</li>
</ol>
</li>
<li>
<ol>
<li>Choose the correct version and download:
<ul>
<li><a href="https://desktop.docker.com/mac/main/arm64/Docker.dmg?utm_source=docker&amp;utm_medium=webreferral&amp;utm_campaign=docs-driven-download-mac-arm64&amp;_gl=1*lb0mcn*_gcl_au*Nzk1NTkwMTE3LjE3NjIxNjk3ODU.*_ga*MTYzMzE2OTQzNy4xNzYyMTY5Nzg1*_ga_XJWPQMJYHQ*czE3NjIzNDM5NjUkbzMkZzEkdDE3NjIzNDU0NjMkajU5JGwwJGgw">Apple Silicon <code>Docker.dmg</code> Apple Chip</a></li>
<li><a href="https://desktop.docker.com/mac/main/amd64/Docker.dmg?utm_source=docker&amp;utm_medium=webreferral&amp;utm_campaign=docs-driven-download-mac-amd64&amp;_gl=1*hc9vj6*_gcl_au*Nzk1NTkwMTE3LjE3NjIxNjk3ODU.*_ga*MTYzMzE2OTQzNy4xNzYyMTY5Nzg1*_ga_XJWPQMJYHQ*czE3NjIzNDM5NjUkbzMkZzEkdDE3NjIzNDU1NDYkajYwJGwwJGgw">Intel <code>Docker.dmg</code> Intel Chip</a></li>
</ul>
</li>
</ol>
</li>
<li>
<ol>
<li>Open the Installer
<ul>
<li>Double-click the downloaded .dmg file.</li>
<li>Drag the Docker.app icon into the Applications folder.</li>
</ul>
</li>
</ol>
</li>
<li>
<ol>
<li>Launch Docker Desktop
<ul>
<li>Open Applications folder and launch Docker.app.</li>
<li>The first time you open the program, you might be asked to enter your system password.</li>
<li>Wait for the whale docker icon to appear in the macOS status bar.</li>
</ul>
</li>
</ol>
</li>
</ul>
<h5 id="2-using-homebrew-command-line-install-homebrew-https-brew-sh-">2. Using Homebrew (Command Line Install) <a href="https://brew.sh/">Homebrew</a></h5>
<p>Homebrew is a package manager for macOS that simplifies installing applications from the command line.</p>
<ul>
<li>
<ol>
<li>Open the Terminal App, in Terminal run:</li>
</ol>
</li>
</ul>
<pre><code class="lang-bash">/<span class="hljs-keyword">bin/bash </span>-c <span class="hljs-string">"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"</span>
</code></pre>
<ul>
<li>
<ol>
<li>Once installed, verify:</li>
</ol>
</li>
</ul>
<pre><code class="lang-bash">brew <span class="hljs-comment">--version</span>
</code></pre>
<ul>
<li>
<ol>
<li>Install Docker Desktop via Homebrew</li>
</ol>
</li>
</ul>
<p>Homebrew downloads and installs the latest version of Docker Desktop that works with your Mac�s architecture, whether it is Intel or Apple Silicon.</p>
<pre><code class="lang-bash"><span class="hljs-keyword">brew </span><span class="hljs-keyword">install </span>--cask docker
</code></pre>
<ul>
<li>
<ol>
<li>Once the installation is complete, open Docker Desktop. Wait until you see the whale Docker icon in the macOS status bar.</li>
</ol>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-keyword">open</span> /Applications/Docker.<span class="hljs-keyword">app</span>
</code></pre>
<h5 id="3-using-mac-app-store-apple-silicon-only-">3. Using Mac App Store (Apple Silicon only)</h5>
<ul>
<li>
<ol>
<li>Open the Mac App Store</li>
</ol>
</li>
<li>
<ol>
<li>In the top-left corner of the App Store window, click the Search bar.</li>
</ol>
</li>
<li>
<ol>
<li>Type Docker Desktop and press Return.</li>
</ol>
</li>
<li>
<ol>
<li>You should see the official app listed as Docker Desktop Developer Tools by Docker Inc.</li>
</ol>
</li>
<li>
<ol>
<li>macOS will automatically download and install Docker Desktop in your Applications folder. Please wait until the download finishes.</li>
</ol>
</li>
<li>
<ol>
<li>Once the installation is complete, open Docker Desktop. Wait until you see the whale Docker icon in the macOS status bar.</li>
</ol>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-keyword">open</span> /Applications/Docker.<span class="hljs-keyword">app</span>
</code></pre>
<h3 id="install-on-linux-ubuntu-24-04-">Install on Linux (Ubuntu 24.04)</h3>
<ul>
<li>
<ol>
<li>Add Official Docker Repository</li>
</ol>
</li>
</ul>
<p>Before you install Docker Desktop, you need Docker’s CLI and daemon packages to be available through its official repositories</p>
<p>Open a terminal (Ctrl+Alt+T) and run the following:</p>
<pre><code class="lang-bash">sudo apt <span class="hljs-keyword">update</span>
sudo apt install apt-transport-https <span class="hljs-keyword">ca</span>-certificates curl gnupg -<span class="hljs-built_in">y</span>

</code>These packages enable HTTPS access to repositories and manage trusted keys.</pre>
<p>Now, import the Docker GPG key and add the official Ubuntu repo:</p>
<pre><code class="lang-bash">sudo apt install apt-transport-https ca-certificates curl gnupg
curl -fsSL <span class="hljs-string">https:</span><span class="hljs-comment">//download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg</span>
echo <span class="hljs-string">"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable"</span> | sudo tee <span class="hljs-regexp">/etc/</span>apt<span class="hljs-regexp">/sources.list.d/</span>docker.list &gt; <span class="hljs-regexp">/dev/</span><span class="hljs-literal">null</span>
</code></pre>
<p>Then update your package index:</p>
<pre><code class="lang-bash"><span class="hljs-attribute">sudo apt update</span>
</code></pre>
<ul>
<li>
<ol>
<li>Download the Docker Desktop .deb Package</li>
</ol>
</li>
</ul>
<p>Docker Desktop for Linux comes as a .deb file. To get the latest version, you can use curl</p>
<pre><code class="lang-bash">curl -fsSL -<span class="hljs-keyword">o</span> docker-desktop.<span class="hljs-keyword">deb</span> http<span class="hljs-variable">s:</span>//desktop.docker.<span class="hljs-keyword">com</span>/linux/main/amd64/docker-desktop-latest.<span class="hljs-keyword">deb</span>
</code></pre>
<ul>
<li>
<ol>
<li>Install Docker Desktop</li>
</ol>
</li>
</ul>
<p>After you download the package, use apt to install it. This will make sure all the needed dependencies are installed automatically.</p>
<pre><code class="lang-bash">sudo apt <span class="hljs-keyword">install</span> ./docker-desktop.deb
</code></pre>
<p>This process installs Docker Desktop and its main components, such as:</p>
<pre><code><span class="hljs-comment">    * Docker Engine</span>
<span class="hljs-comment">    * Docker CLI (docker command)</span>
<span class="hljs-comment">    * Docker Compose</span>
<span class="hljs-comment">    * Docker Desktop system service</span>
</code></pre>
<ul>
<li>
<ol>
<li>Enable User Access to Docker</li>
</ol>
</li>
</ul>
<p>If you want to run Docker commands without using sudo, add your user to the docker group. The newgrp command lets you apply your group changes right away, so you do not need to log out first.</p>
<pre><code class="lang-bash">sudo usermod -aG docker $<span class="hljs-keyword">USER</span>
<span class="hljs-title">newgrp</span> docker
`
</code></pre>
<ul>
<li>
<ol>
<li>Launch Docker Desktop</li>
</ol>
</li>
</ul>
<p>Now you can start Docker Desktop with</p>
<pre><code class="lang-bash">systemctl --<span class="hljs-keyword">user</span> <span class="hljs-title">start</span> docker-desktop
`
</code></pre>
<h2 id="verify-docker-desktop-installation">Verify Docker Desktop Installation</h2>
<ul>
<li>
<ol>
<li>Start Docker Desktop</li>
</ol>
</li>
<li><code>Windows:</code> Find &#8220;Docker Desktop&#8221; in the Start Menu and open it. You should then see the Docker whale icon in the system tray.</li>
<li><code>Mac:</code> Open your Applications folder, find &#8220;Docker Desktop,&#8221; and start it. The Docker whale icon will show up in the menu bar.</li>
<li><code>Linux (Ubuntu 24.04):</code> The location and icon for launching Docker Desktop can vary depending on your Linux distribution. Check your distribution’s documentation or search for &#8220;Docker Desktop&#8221; in your application launcher for more information.</li>
<li>
<ol>
<li>Verify Docker Engine and Client</li>
</ol>
</li>
</ul>
<p>Open your terminal, command prompt, then run this command.</p>
<pre><code class="lang-bash">docker <span class="hljs-comment">--version</span>
</code></pre>
<p>This command shows the version of the Docker client and engine, so you can check that Docker is installed and working from your command line.</p>
<ul>
<li>
<ol>
<li>Run a Test Container</li>
</ol>
</li>
</ul>
<p>Execute the &#8220;hello-world&#8221; container to verify that Docker can pull images, create and run containers, then run this command.</p>
<pre><code class="lang-bash">docker <span class="hljs-keyword">run</span><span class="bash"> hello-world</span>
</code></pre>
<p>If the process works correctly, you will see a message</p>
<pre><code class="lang-bash">Hello <span class="hljs-keyword">from</span> Docker!
This message shows <span class="hljs-keyword">that</span> your installation appears <span class="hljs-keyword">to</span> be working correctly.
</code></pre>
<p>This confirms that the Docker engine, container networking, image pulling, and runtime execution are functioning correctly.</p>
<h2 id="further-reading">Further Reading</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/windows/wsl/install">How to install Linux on Windows with WSL</a></li>
<li><a href="https://chocolatey.org/install">Installing Chocolatey</a></li>
<li><a href="https://docs.docker.com/desktop/setup/install/windows-install/">Install Docker Desktop on Windows</a></li>
<li><a href="https://docs.docker.com/desktop/setup/install/mac-install/">Install Docker Desktop on Mac</a></li>
<li><a href="https://brew.sh/">Homebrew</a></li>
<li><a href="https://docs.docker.com/desktop/setup/install/linux/ubuntu/">Install Docker Desktop on Linux (Ubuntu Example)</a></li>
</ul>
<h2><a href="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" loading="lazy" class="alignnone size-medium wp-image-1209" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394-200x300.png?resize=200%2C300" alt="" width="200" height="300" srcset="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?w=412&amp;ssl=1 412w" sizes="(max-width: 200px) 100vw, 200px" data-recalc-dims="1" /></a></h2>
<h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/installing-desktop-docker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1226</post-id>	</item>
		<item>
		<title>Using WordPress on AWS Lightsail and Docker &#8211; Early Access Edition</title>
		<link>https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/</link>
					<comments>https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Sun, 24 May 2026 11:52:39 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Using WordPress on AWS Lightsail and Docker]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1206</guid>

					<description><![CDATA[Learn how to deploy WordPress on AWS Lightsail using Docker. This book provides a clear, step-by-step guide to setting up the AWS CLI, creating a Lightsail virtual server, installing Docker, and deploying WordPress with Docker Compose.You will also explore how to automate WordPress theme deployments using WP-CLI and CI/CD pipelines. It is designed for developers, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-left has-text-align-justify has-small-font-size" id="Using-WordPress-on-AWS-Lightsail-and-Docker"><img data-attachment-id="1209" data-permalink="https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/title_page/" data-orig-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=412%2C618&amp;ssl=1" data-orig-size="412,618" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="title_page" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=200%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623451394.png?fit=683%2C1024&amp;ssl=1" class="wp-image-1209" style="width: 150px;" src="https://i0.wp.com/adamjohnston.me/wp-content/uploads/2026/05/title_page-e1779623271306.png" alt="" data-recalc-dims="1">      </p>



<p>Learn how to deploy WordPress on AWS Lightsail using Docker.</p>



<p>This book provides a clear, step-by-step guide to setting up the AWS CLI, creating a Lightsail virtual server, installing Docker, and deploying WordPress with Docker Compose.<br>You will also explore how to automate WordPress theme deployments using WP-CLI and CI/CD pipelines.</p>



<p>It is designed for developers, site owners, and technical users who want a simpler, more reliable, and more secure approach to WordPress deployment using DevOps practices.</p>



<p>Early Access Edition</p>



<p><h2><a href="https://leanpub.com/wordpressawslightsail">Using WordPress on AWS Lightsail and Docker</a></h2></p>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/using-wordpress-on-aws-lightsail-and-docker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1206</post-id>	</item>
		<item>
		<title>NovuscodeLibrary update for Delphi 11</title>
		<link>https://adamjohnston.me/novuscodelibrary-update-for-delphi-11/</link>
					<comments>https://adamjohnston.me/novuscodelibrary-update-for-delphi-11/#respond</comments>
		
		<dc:creator><![CDATA[Adam Craig Johnston]]></dc:creator>
		<pubDate>Mon, 17 Jan 2022 23:46:13 +0000</pubDate>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[NovuscodeLibrary]]></category>
		<guid isPermaLink="false">https://adamjohnston.me/?p=1147</guid>

					<description><![CDATA[An update to the NovuscodeLibrary &#8211; a Delphi library of utility functions and non-visual classes for Delphi 11 is now ready. https://github.com/novuslogic/NovuscodeLibrary Changelog ToDo]]></description>
										<content:encoded><![CDATA[
<p>An update to the NovuscodeLibrary &#8211; a Delphi library of utility functions and non-visual classes for Delphi 11 is now ready.</p>



<p><a href="https://github.com/novuslogic/NovuscodeLibrary">https://github.com/novuslogic/NovuscodeLibrary</a></p>



<p><a rel="noreferrer noopener" href="https://github.com/novuslogic/NovuscodeLibrary/blob/master/Changelog.md" target="_blank">Changelog</a></p>



<p><a rel="noreferrer noopener" href="https://github.com/novuslogic/NovuscodeLibrary/blob/master/ToDo.md" target="_blank">ToDo</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://adamjohnston.me/novuscodelibrary-update-for-delphi-11/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1147</post-id>	</item>
	</channel>
</rss>
