<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Personal Tech Blog</title>
    <description>Technical Blog &amp; Personal Project Updates</description>
    <link>https://jmoore53.com/</link>
    <atom:link href="https://jmoore53.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 29 Jul 2025 02:50:57 +0000</pubDate>
    <lastBuildDate>Tue, 29 Jul 2025 02:50:57 +0000</lastBuildDate>
    <generator>Jekyll v4.3.3</generator>
    
      <item>
        <title>Restic clean up backups</title>
        <description>&lt;p&gt;Efficient backup management is essential to maintain storage space and ensure important data is retained without unnecessary redundancy.
Restic provides powerful features to manage backups effectively.
One of the common tasks is to clean up older backups that are no longer needed, which can be automated using a scheduled cron job.
Below is how I setup a cleanup job.&lt;/p&gt;

&lt;p&gt;As backups accumulate over time, they can consume a significant amount of storage.
Automating the cleanup of older backups ensures that storage usage is optimized and only essential backups are retained.
By scheduling this task, it is possible to maintain a balance between data retention and storage management.&lt;/p&gt;

&lt;h3 id=&quot;crontab-restic-cleanup&quot;&gt;Crontab Restic Cleanup&lt;/h3&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;11&lt;/span&gt; * * &lt;span class=&quot;n&quot;&gt;Sun&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;restic&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forget&lt;/span&gt; --&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;daily&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;21&lt;/span&gt; --&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;weekly&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9&lt;/span&gt; --&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;monthly&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Options&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--keep-daily 21&lt;/code&gt;: Retains the last 21 daily backups.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--keep-weekly 9&lt;/code&gt;: Retains the last 9 weekly backups.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--keep-monthly 12&lt;/code&gt;: Retains the last 12 monthly backups.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using these options, it ensures that a reasonable number of backups are kept over time, while older, less necessary backups are deleted.
This approach keeps the backup storage manageable and efficient.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Automating the cleanup of backups with Restic and Crontab is a straightforward process that can significantly improve backup management. By configuring a cron job to regularly clean up older backups, it is possible to maintain a streamlined backup system that conserves storage space without sacrificing the availability of important data.&lt;/p&gt;

&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://restic.readthedocs.io/&quot;&gt;Restic Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crontab.guru/&quot;&gt;Crontab Guru&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Tue, 09 Jul 2024 16:51:37 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/07/09/Restic-clean-up-backups.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/07/09/Restic-clean-up-backups.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Nginx Subdirectory Configuration</title>
        <description>&lt;p&gt;The following solution involves making modifications to a Dockerfile and adjusting URL settings to ensure the site is served correctly from different paths.&lt;/p&gt;

&lt;p&gt;The goal was to configure an Nginx blog from a dockerfile to be testable and runnable from both the root directory and any subdirectory on the site.
This flexibility allows for testing different versions of the site or hosting multiple versions simultaneously on different subfolders without interfering with each other.&lt;/p&gt;

&lt;h3 id=&quot;how-to-implement-the-configuration&quot;&gt;How to Implement the Configuration&lt;/h3&gt;

&lt;p&gt;To achieve this, several changes were made to the Dockerfile and the configuration files:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dockerfile Setup&lt;/strong&gt;: The Dockerfile was modified to build the site with a specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FULLBASEURL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUBFOLDER&lt;/code&gt; argument. This setup allows for dynamically setting the base URL and the subdirectory where the site should be served. The Dockerfile is divided into two stages: the build stage and the final stage.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Dockerfile:&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ruby:3.3-alpine&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;builder&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ARG&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; FULLBASEURL=&quot;https://jmoore53.com&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ARG&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; SUBFOLDER=&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ARG&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; BUILT=&quot;Wed 03 Jul 2024 02:01:53 PM EDT&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apk update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    git &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    build-base

&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ./ /app&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /app&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;Gemfile.lock

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|BASEURLHERE|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$FULLBASEURL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|&quot;&lt;/span&gt; _config.yml
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|BUILTDATE|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BUILT&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|&quot;&lt;/span&gt; _config.yml
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|SUBFOLDERHERE|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SUBFOLDER&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|&quot;&lt;/span&gt; nginx/default.conf

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;jekyll build &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /public

&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; nginx:latest&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ARG&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; FULLBASEURL=&quot;https://jmoore53.com&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ARG&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; SUBFOLDER=&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/usr/share/nginx/html/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SUBFOLDER&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /usr/share/nginx/html/&lt;span class=&quot;nv&quot;&gt;$SUBFOLDER&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=builder /public/ /usr/share/nginx/html/$SUBFOLDER/&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=builder /app/nginx/default.conf /etc/nginx/conf.d/default.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|SUBFOLDERHERE|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SUBFOLDER&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|&quot;&lt;/span&gt; /etc/nginx/conf.d/default.conf
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=builder /app/nginx/nginx.conf /etc/nginx/nginx.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;This Dockerfile first builds the site using Ruby and Jekyll, then copies the built static files to the Nginx container. It also makes sure that URLs and paths in the configuration files are correctly set up based on the provided build arguments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Running the Blog&lt;/strong&gt;: The blog can be run with specific arguments to test it from different subdirectories. This is done by passing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FULLBASEURL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUBFOLDER&lt;/code&gt; as build arguments when creating the Docker image.&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Remove the current blog image&lt;/span&gt;
docker image &lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;jmoore53-blog

&lt;span class=&quot;c&quot;&gt;# Build Docker Image for testing&lt;/span&gt;
docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; jmoore53-blog:testa &lt;span class=&quot;nt&quot;&gt;--build-arg&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;FULLBASEURL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://10.100.0.20:8888/a&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--build-arg&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;SUBFOLDER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;These commands first remove any existing Docker image for the blog to prevent conflicts. Then, a new Docker image is built with the specified base URL and subfolder. This setup allows for testing the site under different conditions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Configuration Adjustments&lt;/strong&gt;: After these changes to the Dockerfile, modifications were made to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yml&lt;/code&gt; file. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseurl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt; settings were updated, and static hrefs were converted to absolute links. These adjustments ensure that static resources are correctly referenced, regardless of whether the site is served from the root or a subdirectory.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more details on the specific changes made to the repository, see the &lt;a href=&quot;https://gitea.jmoore53.com/jmoore53/jmoore53.com/commit/35903297f639fa3e2d5ce0a0e5212529655b0dba&quot;&gt;link to commit&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By modifying the Dockerfile and adjusting configuration settings, the Nginx blog can now be served from any specified subdirectory on the site. This setup provides flexibility in managing different versions of the site and ensures that all resources are correctly loaded regardless of the path from which the site is accessed.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitea.jmoore53.com/jmoore53/jmoore53.com/commit/35903297f639fa3e2d5ce0a0e5212529655b0dba&quot;&gt;Link to commit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 09 Jul 2024 15:23:37 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/07/09/Nginx-Subdirectory-Configuration.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/07/09/Nginx-Subdirectory-Configuration.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Kanboard Copy Multiple Links</title>
        <description>&lt;p&gt;Using Kanboard a lot I found myself wanting to add multiple links at a time. This made me pull down the kanboard source code and build my own docker image with the feature I needed.&lt;/p&gt;

&lt;p&gt;To implement this feature, the “Add External Links” function was updated to support multiline input.
This enhancement allows users to paste several URLs at once.
A lookup function was also added to fetch and display the titles of these links within the task view, making it easier to identify the nature of each linked resource.
This improvement saves time and reduces the need to add links one by one manually.&lt;/p&gt;

&lt;h3 id=&quot;process-of-applying-fixesrebase&quot;&gt;Process of Applying Fixes/Rebase&lt;/h3&gt;

&lt;p&gt;Here is the step-by-step process used to apply recent fixes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Merge New Changes&lt;/strong&gt;: Update the branch with the latest changes from the Kanboard repository.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git pull main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rebuild Docker Image&lt;/strong&gt;: Build the updated Kanboard Docker image.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; jmoore53/kanboard:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Restart Kanboard Services&lt;/strong&gt;: Stop and restart the Kanboard service using Docker Compose to apply the new build.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker compose stop kanboard
docker compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These steps allow the changes to run locally, ensuring the new feature functions as expected.&lt;/p&gt;

&lt;h3 id=&quot;ssh-key-management-for-github&quot;&gt;SSH Key Management for GitHub&lt;/h3&gt;

&lt;p&gt;Something I ran into along the way was the SSH agent for github. Below is the fix.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Start the SSH Agent&lt;/strong&gt;: Initiate the SSH agent in the background.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;ssh-agent &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Add SSH Private Key&lt;/strong&gt;: Add the SSH private key to the SSH agent.
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh-add ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id_ed25519&lt;/code&gt; with the specific private key file name if different.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;This update simplifies the process of adding multiple external links to Kanboard tasks, enhancing usability and project management efficiency. By automating and streamlining these actions, it is possible to maintain a more organized and accessible task management system.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jmoore53/kanboard&quot;&gt;Kanboard GitHub Repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jmoore53/kanboard/tree/296b22d1b09750d350a98b7e47b5ca5cfd575a71&quot;&gt;Specific Branch with Updates&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&quot;&gt;GitHub Documentation on SSH Keys&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 02 Mar 2024 16:00:14 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/03/02/Kanboard-Copy-Multiple-Links.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/03/02/Kanboard-Copy-Multiple-Links.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Custom Kernel Install for Ubuntu</title>
        <description>&lt;p&gt;I wanted to test out running the mainline kernel for some eBPF features that weren’t available to me. Below is a post on running the mainline kernel.&lt;/p&gt;

&lt;p&gt;A mainline kernel is often needed for specific tasks such as installing eBPF, which requires the latest LLVM version (like llvm-17).
Using the latest mainline kernel can help unlock these capabilities, allowing for advanced system tuning and development tasks.&lt;/p&gt;

&lt;h3 id=&quot;how-to-install-a-mainline-kernel-on-ubuntu&quot;&gt;How to Install a Mainline Kernel on Ubuntu&lt;/h3&gt;

&lt;p&gt;To install a mainline kernel on an Ubuntu system, follow these steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Download and install the mainline kernel script:&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; wget https://raw.githubusercontent.com/pimlie/ubuntu-mainline-kernel.sh/master/ubuntu-mainline-kernel.sh
 &lt;span class=&quot;nb&quot;&gt;sudo install &lt;/span&gt;ubuntu-mainline-kernel.sh /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Check for the latest available kernel version and install it:&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;ubuntu-mainline-kernel.sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;ubuntu-mainline-kernel.sh &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Reboot the system to apply the changes:&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Verify the installed kernel version:&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;gui-interface-for-kernel-updates&quot;&gt;GUI Interface for Kernel Updates&lt;/h3&gt;

&lt;p&gt;For users who prefer a graphical interface, there is an alternative method to update the kernel using a GUI tool. Install the GUI tool by running the following commands:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;add-apt-repository ppa:cappelikan/ppa
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;mainline
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;installing-llvm&quot;&gt;Installing LLVM&lt;/h3&gt;

&lt;p&gt;LLVM is required for various development tasks, including working with eBPF. The latest version of LLVM can be installed using the following command:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;wget &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; - https://apt.llvm.org/llvm.sh&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command downloads and executes a script to install the desired version of LLVM directly from the official repositories.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Installing a mainline kernel and LLVM on Ubuntu is straightforward and can provide the latest features and improvements for development and testing environments. Using scripts and tools simplifies the process and ensures the system is up to date with the latest software.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://phoenixnap.com/kb/how-to-update-kernel-ubuntu&quot;&gt;How to Update Kernel on Ubuntu - PhoenixNAP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://askubuntu.com/questions/1388115/how-do-i-update-my-kernel-to-the-latest-one&quot;&gt;How to Update Kernel on Ubuntu - Ask Ubuntu&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://releases.llvm.org/&quot;&gt;LLVM Releases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://apt.llvm.org/&quot;&gt;LLVM Official APT Repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://clang.llvm.org/get_started.html&quot;&gt;Getting Started with Clang&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ubuntuhandbook.org/index.php/2023/09/how-to-install-clang-17-or-16-in-ubuntu-22-04-20-04/&quot;&gt;How to Install Clang 17 or 16 in Ubuntu&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tecadmin.net/how-to-install-clang-on-ubuntu/&quot;&gt;How to Install Clang on Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 02 Mar 2024 15:44:27 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/03/02/Custom-Kernel-Install-for-Ubuntu.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/03/02/Custom-Kernel-Install-for-Ubuntu.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>bitmagnet - dht</title>
        <description>&lt;p&gt;Setting up a custom indexer using a Distributed Hash Table (DHT) requires careful configuration and deployment.
This post outlines the steps taken to install bitmagnet on an Alpine Linux virtual machine (VM), configure OpenVPN for secure tunneling, and use NFS for storage instead of MinIO due to compatibility issues.&lt;/p&gt;

&lt;h3 id=&quot;installing-dht-on-alpine-vm&quot;&gt;Installing DHT on Alpine VM&lt;/h3&gt;

&lt;p&gt;To begin, a new Alpine VM was set up to run the DHT. Transmission and OpenVPN were also installed on this server. Here is the output of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip route&lt;/code&gt; command after configuring the network:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alpineylinux:~# ip route
0.0.0.0/1 via 10.35.112.1 dev tun0
default via 192.168.122.1 dev eth0 metric 202
10.35.112.0/24 dev tun0 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 10.35.112.226
10.100.0.0/24 via 192.168.122.1 dev eth0
128.0.0.0/1 via 10.35.112.1 dev tun0
172.17.0.0/16 dev docker0 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.17.0.1 linkdown
172.20.0.0/16 dev br-94bb901b6c16 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.20.0.1
172.23.0.0/16 dev br-716551f713d9 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.23.0.1 linkdown
191.96.150.41 via 192.168.122.1 dev eth0
192.168.122.0/24 dev eth0 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 192.168.122.115
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configuring-openvpn&quot;&gt;Configuring OpenVPN&lt;/h3&gt;

&lt;p&gt;OpenVPN was configured to provide a secure tunnel interface on the VM. The key configuration file, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openvpn.cnf&lt;/code&gt;, is shown below:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tun0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;proto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;udp&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;newyorkcity&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;privacy&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1198&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resolv&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;infinite&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nobind&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;persist&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;persist&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;tun&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cipher&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aes&lt;/span&gt;-&lt;span class=&quot;m&quot;&gt;128&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;cbc&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tls&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;tls&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;pass&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;openvpn&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;creds&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;conf&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;compress&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;verb&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;reneg&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;sec&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;gateway&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;def1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net_gateway&lt;/span&gt;

&amp;lt;&lt;span class=&quot;n&quot;&gt;crl&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;verify&lt;/span&gt;&amp;gt;
-----&lt;span class=&quot;n&quot;&gt;BEGIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X509&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CRL&lt;/span&gt;-----
-----&lt;span class=&quot;n&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X509&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CRL&lt;/span&gt;-----
&amp;lt;/&lt;span class=&quot;n&quot;&gt;crl&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;verify&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span class=&quot;n&quot;&gt;ca&lt;/span&gt;&amp;gt;
-----&lt;span class=&quot;n&quot;&gt;BEGIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CERTIFICATE&lt;/span&gt;-----
-----&lt;span class=&quot;n&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CERTIFICATE&lt;/span&gt;-----
&amp;lt;/&lt;span class=&quot;n&quot;&gt;ca&lt;/span&gt;&amp;gt;

&lt;span class=&quot;n&quot;&gt;disable&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;occ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The most important line in this configuration is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;route 10.100.0.0 255.255.255.0 net_gateway&lt;/code&gt;, which instructs the VM to route all traffic to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.100.0.0&lt;/code&gt; network using the local network gateway.&lt;/p&gt;

&lt;h3 id=&quot;docker-configuration-for-postgresql&quot;&gt;Docker Configuration for PostgreSQL&lt;/h3&gt;

&lt;p&gt;To manage data, a Docker container running PostgreSQL was set up with the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; configuration:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bitmagnet-postgres&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./data/postgres:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ports:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#   - &quot;5432:5432&quot; Expose this port if you&apos;d like to dig around in the database&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_PASSWORD=postgres&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_DB=bitmagnet&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PGUSER=postgres&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;shm_size&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1g&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;healthcheck&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;CMD-SHELL&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pg_isready&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;start_period&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;20s&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;10s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NFS was used for storing the data due to issues with using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3fuse&lt;/code&gt; directories with Transmission. This setup runs on a VM with 8 GB of storage, 1 GB of RAM, and 1 vCPU. Although using an Alpine container could further reduce resource usage, the VM remains a more straightforward solution due to concerns about routing and VPN connections within Docker containers.&lt;/p&gt;

&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitmagnet.io/setup/installation.html&quot;&gt;bitmagnet setup and installation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitmagnet.io/endpoints.html&quot;&gt;bitmagnet endpoints&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitmagnet.io/internals-development.html&quot;&gt;bitmagnet internals and development&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bitmagnet-io/bitmagnet&quot;&gt;bitmagnet GitHub repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitmagnet.io/internals-development/dht-crawler.html&quot;&gt;bitmagnet DHT crawler documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.bittorrent.org/beps/bep_0051.html&quot;&gt;BitTorrent BEP 51&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://bittorrent.org/beps/bep_0005.html&quot;&gt;BitTorrent BEP 5&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.bittorrent.org/beps/bep_0033.html&quot;&gt;BitTorrent BEP 33&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.bittorrent.org/beps/bep_0010.html&quot;&gt;BitTorrent BEP 10&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf&quot;&gt;Kademlia paper&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/boramalper/magnetico/blob/master/cmd/magneticod/bittorrent/metadata/sink.go&quot;&gt;Magnetico metadata sink&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.boramalper.org/labs/magnetico/&quot;&gt;Magnetico project&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/anacrolix/torrent&quot;&gt;Anacrolix torrent repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/anacrolix?tab=repositories&amp;amp;q=&amp;amp;type=&amp;amp;language=&amp;amp;sort=stargazers&quot;&gt;Anacrolix GitHub repositories&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/anacrolix/dht/blob/master/dht.go&quot;&gt;Anacrolix DHT implementation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/anacrolix/torrent/blob/v1.54.0/NOTES.md&quot;&gt;Anacrolix torrent notes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/uber-go/zap&quot;&gt;Uber-go Zap logger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 22 Feb 2024 19:32:52 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/02/22/bitmagnet-dht.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/02/22/bitmagnet-dht.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>List Packages to be installed with APT with Ansible Task</title>
        <description>&lt;p&gt;Managing system updates across multiple servers can be a complex task, especially when dealing with different packages and updates. 
This blog post shows how to use Ansible to list upgradable packages on systems using APT, and how to parse this information into a formatted output.&lt;/p&gt;

&lt;h1 id=&quot;how-to-list-upgradable-packages-with-ansible&quot;&gt;How to List Upgradable Packages with Ansible&lt;/h1&gt;

&lt;p&gt;Here’s an example Ansible task that lists all upgradable packages using APT:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;List System Upgrades&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become_user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apt list --upgradable&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;output&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msg=&quot;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;potential-solutions-for-managing-upgrade-listings&quot;&gt;Potential Solutions for Managing Upgrade Listings&lt;/h1&gt;

&lt;p&gt;Moving forward this is how I want the output to show, but for now the playbook output is good enough.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[common-among all servers]
package-1
package-2
package-3
package-4

[server-1]
package-custom

[server-2]
package-custom
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;By creating a formatted list of upgradable packages, this allows me to better manage and apply updates.
This method provides a clear overview of what needs to be updated and allows for better planning of system upgrades.&lt;/p&gt;

</description>
        <pubDate>Wed, 31 Jan 2024 14:54:11 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/01/31/List-Packages-to-be-installed-with-APT-with-Ansible-Task.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/01/31/List-Packages-to-be-installed-with-APT-with-Ansible-Task.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Ansible Testing on Blank Container</title>
        <description>&lt;p&gt;Testing Ansible playbooks often requires a controlled environment where configurations and commands can be executed without interference. 
A blank Docker container provides an isolated environment that can be easily reset or modified, allowing for extensive testing of Ansible configurations.
This setup facilitates a streamlined process for testing playbooks, ensuring that they function correctly before being deployed in production.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;A blank Docker container is spun up with SSH access enabled to perform tasks using Ansible.
This container is based on Ubuntu 20.04 and includes necessary components such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssh-server&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt; to simulate a more traditional server environment.
The container is configured to run commands via SSH and allows for testing Ansible playbooks in a controlled setting.&lt;/p&gt;

&lt;h2 id=&quot;creating-the-docker-environment&quot;&gt;Creating the Docker Environment:&lt;/h2&gt;

&lt;p&gt;The following Dockerfile creates a minimal environment with SSH enabled.
This configuration is useful for basic testing scenarios where system services are not required.&lt;/p&gt;

&lt;div class=&quot;language-Dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ubuntu:20.04&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;openssh-server &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;useradd &lt;span class=&quot;nt&quot;&gt;-rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /home/ubuntu &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /bin/bash &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; root &lt;span class=&quot;nt&quot;&gt;-G&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 1000 &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;test:test&apos;&lt;/span&gt; | chpasswd

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;service ssh start

&lt;span class=&quot;k&quot;&gt;EXPOSE&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 22&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;/usr/sbin/sshd&quot;,&quot;-D&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This Dockerfile installs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssh-server&lt;/code&gt; and creates a user named “test” with sudo privileges, allowing remote SSH access for Ansible to connect and execute commands.&lt;/p&gt;

&lt;h2 id=&quot;dockerfile-with-systemd-for-testing-more-complex-scenarios&quot;&gt;Dockerfile with Systemd for Testing More Complex Scenarios:&lt;/h2&gt;

&lt;p&gt;For cases requiring a systemd environment, a more advanced Dockerfile is used.
This configuration allows testing services managed by systemd, which is not natively available in Docker containers.&lt;/p&gt;

&lt;div class=&quot;language-Dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ubuntu:20.04&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt-get update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-install-recommends&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    systemd systemd-sysv dbus dbus-user-session
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; docker-entrypoint.sh /&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;/docker-entrypoint.sh&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This setup is useful for simulating a real-world environment where services need to be managed by systemd, making it ideal for more comprehensive Ansible playbook testing.&lt;/p&gt;

&lt;h2 id=&quot;combining-ssh-and-systemd-in-a-docker-container&quot;&gt;Combining SSH and Systemd in a Docker Container:&lt;/h2&gt;

&lt;p&gt;To incorporate both SSH and systemd functionalities, a combined Dockerfile is used. This file creates an environment where Ansible can connect via SSH and also control services managed by systemd.&lt;/p&gt;

&lt;div class=&quot;language-Dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ubuntu:20.04&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-install-recommends&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    openssh-server &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    systemd systemd-sysv dbus dbus-user-session

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;useradd &lt;span class=&quot;nt&quot;&gt;-rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /home/ubuntu &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /bin/bash &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; root &lt;span class=&quot;nt&quot;&gt;-G&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 1000 &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;test:test&apos;&lt;/span&gt; | chpasswd
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;root:root&apos;&lt;/span&gt; | chpasswd
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;#!/bin/sh\nexit 0&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /usr/sbin/policy-rc.d
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;systemctl start systemd-logind&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/profile

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;service ssh start

&lt;span class=&quot;k&quot;&gt;EXPOSE&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 22&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;/sbin/init&quot;, &quot;&amp;amp;&amp;amp;&quot;, &quot;/usr/sbin/sshd&quot;,&quot;-D&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This Dockerfile includes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssh-server&lt;/code&gt; for SSH connectivity, adds a test user, and sets up systemd components, allowing the container to function similarly to a standard Ubuntu server.
The container starts the SSH service and systemd, providing a robust environment for testing.&lt;/p&gt;

&lt;h2 id=&quot;additional-considerations&quot;&gt;Additional Considerations:&lt;/h2&gt;

&lt;p&gt;Running commands as “root” in Docker containers can pose security concerns. It is essential to investigate and address these risks, particularly in environments where elevated privileges could lead to vulnerabilities.&lt;/p&gt;

&lt;p&gt;The lack of a native init system within Docker containers also requires workarounds, such as the use of systemd within the container. A solution involving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemctl&lt;/code&gt; commands is necessary for scenarios requiring full control over system services.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;/h2&gt;

&lt;p&gt;By using Docker containers configured with SSH and systemd, Ansible playbooks can be tested in environments that closely mimic production servers. This method provides a flexible and secure way to ensure configurations are correct and perform as expected, ultimately saving time and reducing errors in deployment.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/AkihiroSuda/containerized-systemd/blob/master/Dockerfile.ubuntu-20.04&quot;&gt;Containerized Systemd Dockerfile&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sun, 28 Jan 2024 18:12:26 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/01/28/Ansible-Testing-on-Blank-Container.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/01/28/Ansible-Testing-on-Blank-Container.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>IPv6 in the Homelab</title>
        <description>&lt;p&gt;Capturing and logging IPv6 address attempts is essential for understanding network traffic and ensuring robust security measures. Accurate logging allows for detailed monitoring and helps in identifying potential threats or misconfigurations.&lt;/p&gt;

&lt;p&gt;To effectively log IPv6 addresses and integrate logs with monitoring tools, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syslog-ng&lt;/code&gt; was utilized along with some configurations on the Nginx server.&lt;/p&gt;

&lt;h1 id=&quot;initial-setup-and-evaluation&quot;&gt;Initial Setup and Evaluation:&lt;/h1&gt;

&lt;p&gt;IPv6 tables configuration was evaluated on the Nginx server to ensure proper handling of IPv6 addresses.
It was confirmed that logs do occur on containers and that they follow a structure similar to IPv4, which is suitable for the current setup. 
However, some adjustments were necessary to ensure comprehensive logging.&lt;/p&gt;

&lt;h1 id=&quot;nginx-logging-configuration&quot;&gt;Nginx Logging Configuration:&lt;/h1&gt;

&lt;p&gt;The Nginx server was configured to log requests and errors, including those for IPv6 addresses. 
The following Nginx configuration was added to manage logs:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timed_combined&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;$remote_addr - $remote_user [$time_local] &apos;&lt;/span&gt;
                          &lt;span class=&quot;s1&quot;&gt;&apos;&quot;$host&quot; &quot;$request&quot; $status $body_bytes_sent &apos;&lt;/span&gt;
                          &lt;span class=&quot;s1&quot;&gt;&apos;&quot;$http_referer&quot; &quot;$http_user_agent&quot; &apos;&lt;/span&gt;
                          &lt;span class=&quot;s1&quot;&gt;&apos;$request_time $upstream_response_time $pipe&apos;&lt;/span&gt;;

&lt;span class=&quot;n&quot;&gt;access_log&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;nginx&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;timed_combined&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timed_combined&lt;/span&gt;;
&lt;span class=&quot;n&quot;&gt;access_log&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;nginx&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;access&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;;
&lt;span class=&quot;n&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;syslog&lt;/span&gt;:&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;=&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;252&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;514&lt;/span&gt;,&lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;=&lt;span class=&quot;n&quot;&gt;nginxSyslogAccess&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timed_combined&lt;/span&gt;;
&lt;span class=&quot;n&quot;&gt;error_log&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;nginx&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;;
&lt;span class=&quot;n&quot;&gt;error_log&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;syslog&lt;/span&gt;:&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;=&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;252&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;514&lt;/span&gt;,&lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;=&lt;span class=&quot;n&quot;&gt;nginxSyslogError&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration ensures that both access and error logs are captured and sent to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syslog-ng&lt;/code&gt; server. 
The use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log_format&lt;/code&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timed_combined&lt;/code&gt; captures additional details such as request time and upstream response time, which are valuable for analyzing server performance and client behavior.&lt;/p&gt;

&lt;h1 id=&quot;syslog-ng-configuration&quot;&gt;Syslog-ng Configuration:&lt;/h1&gt;

&lt;p&gt;To filter and properly display Nginx logs in the monitoring tools, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syslog-ng&lt;/code&gt; filter was configured:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f_syslog_nginx&lt;/span&gt; { &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;&quot;nginxSyslogError&quot;&lt;/span&gt;) &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;&quot;nginxSyslogAccess&quot;&lt;/span&gt;); };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This filter ensures that only relevant Nginx logs are processed, reducing noise and improving clarity in log analysis tools like Kibana.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verifying Log Appearance in Kibana:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After configuring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syslog-ng&lt;/code&gt; and Nginx, the logs were checked to ensure they appeared correctly in Kibana.
The following filter was used to confirm the presence of Nginx logs:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;syslog_program&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;nginxSyslogAccess&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All logs from Nginx, including those with IPv6 addresses, were properly displayed and filtered in Kibana, indicating that the setup was successful.&lt;/p&gt;

&lt;p&gt;Through careful configuration of Nginx and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syslog-ng&lt;/code&gt;, accurate logging for IPv6 addresses was achieved. This setup ensures comprehensive monitoring of network traffic, enhances security measures, and provides valuable data for ongoing analysis and optimization.&lt;/p&gt;

</description>
        <pubDate>Tue, 16 Jan 2024 15:52:14 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2024/01/16/Logging-for-IPv6.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2024/01/16/Logging-for-IPv6.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Matomo Server</title>
        <description>&lt;p&gt;Analytics provide valuable insights into website traffic and user behavior, which are crucial for optimizing online presence and performance. Implementing Matomo, an open-source web analytics platform, enables detailed tracking and analysis.&lt;/p&gt;

&lt;p&gt;Setting up a Matomo server involves several steps, including configuring the server, setting up a reverse proxy, and securing the environment.&lt;/p&gt;

&lt;h2 id=&quot;server-configuration&quot;&gt;Server Configuration:&lt;/h2&gt;

&lt;p&gt;A server was built to host Matomo, and configurations were carefully documented. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.example&lt;/code&gt; folder was placed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt&lt;/code&gt; directory to serve as a reference for configuration files.&lt;/p&gt;

&lt;h2 id=&quot;database-configuration&quot;&gt;Database Configuration:&lt;/h2&gt;

&lt;p&gt;Passwords and other sensitive information were managed using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.env&lt;/code&gt; file. The following configuration was applied to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.php.ini&lt;/code&gt; file to connect Matomo with the database:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;]
&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;db&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;matomo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;P@ssword123&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dbname&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;matomo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tables_prefix&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;matomo_&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;charset&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;utf8mb4&quot;&lt;/span&gt;

[&lt;span class=&quot;n&quot;&gt;General&lt;/span&gt;]
&lt;span class=&quot;n&quot;&gt;salt&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&quot;salty&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;trusted_hosts&lt;/span&gt;[] = &lt;span class=&quot;s2&quot;&gt;&quot;analytics.jmoore53.com&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;trusted_hosts&lt;/span&gt;[] = &lt;span class=&quot;s2&quot;&gt;&quot;hrvmatp1.cell.jmoore53.com:8080&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;trusted_hosts&lt;/span&gt;[] = &lt;span class=&quot;s2&quot;&gt;&quot;jmoore53.com&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;proxy_client_headers&lt;/span&gt;[] = &lt;span class=&quot;n&quot;&gt;HTTP_X_FORWARDED_FOR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration specifies the database connection settings and lists trusted hosts to ensure secure connections to the Matomo server.&lt;/p&gt;

&lt;h2 id=&quot;nginx-reverse-proxy-setup&quot;&gt;Nginx Reverse Proxy Setup:&lt;/h2&gt;

&lt;p&gt;Nginx was configured as a reverse proxy to handle incoming requests and direct them to the appropriate server. The setup included adding a certificate and configuring DNS for domain resolution. The Nginx configuration file used for the setup is as follows:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; {
    &lt;span class=&quot;n&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analytics&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;jmoore53&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;;

    &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; / {
        &lt;span class=&quot;n&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;://&lt;span class=&quot;n&quot;&gt;hrvmatp1&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;jmoore53&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy_params&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;Forwarded&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;For&lt;/span&gt; $&lt;span class=&quot;n&quot;&gt;proxy_add_x_forwarded_for&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_headers_hash_max_size&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;512&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_headers_hash_bucket_size&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;128&lt;/span&gt;;
    }

    ...&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration allows Nginx to act as a gatekeeper, forwarding traffic to the Matomo server while maintaining security and performance.&lt;/p&gt;

&lt;p&gt;The server setup was completed by adding DNS records and ensuring that all services are correctly configured and running. The Matomo server is now operational, providing comprehensive analytics for the specified domains.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matomo-org/docker&quot;&gt;Matomo Docker GitHub repository&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://matomo.org/faq/how-to-install/faq_98/&quot;&gt;Matomo website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Mon, 04 Dec 2023 18:26:29 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2023/12/04/Matomo-Server.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2023/12/04/Matomo-Server.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Some sort of kanboard plugin to save the external links as a scraped site to provide a preview</title>
        <description>&lt;p&gt;So this one was never finished off, but this is where I got with the Selenium Scraper. The reason was because I now have multiple dead links I wish I had.&lt;/p&gt;

&lt;h2 id=&quot;using-python-selenium-and-docker&quot;&gt;Using Python Selenium and Docker&lt;/h2&gt;

&lt;p&gt;I chose Python Selenium for web scraping due to its robust capabilities in interacting with web pages, combined with Docker to easily manage and run Selenium.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Commands:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we need to run the Selenium Docker container:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 4444:4444 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 7900:7900 &lt;span class=&quot;nt&quot;&gt;--shm-size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2g&quot;&lt;/span&gt; selenium/standalone-firefox:4.16.1-20231219
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Port 4444&lt;/strong&gt;: This is used by the Selenium WebDriver.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Port 7900&lt;/strong&gt;: This allows you to view what’s happening in real time through a web-based VNC client.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;scraping-the-data-with-selenium&quot;&gt;Scraping the Data with Selenium:&lt;/h2&gt;

&lt;p&gt;Here’s a basic Python script (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.py&lt;/code&gt;) using Selenium to access a webpage and fetch its content:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selenium&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;FirefoxOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_load_strategy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_argument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--ignore-ssl-errors=yes&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_argument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--ignore-certificate-errors&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# options.add_argument(&apos;--headless&apos;)  # Uncomment this line to run in headless mode
# options.add_argument(&apos;--no-sandbox&apos;) # Uncomment this line if needed for sandbox issues
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Remote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;command_executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;http://localhost:4444/wd/hub&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;https://jmoore53.com&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;quit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-webdriver-options&quot;&gt;Setting Up WebDriver Options:&lt;/h2&gt;

&lt;p&gt;I configure Firefox options to handle SSL errors and certificate issues, which is important for accessing a variety of websites without interruptions.
The script navigates to the desired URL and retrieves the HTML source of the page.
It was also important to always ensure to close the WebDriver session with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;driver.quit()&lt;/code&gt; to free up resources. I ran into an issue where if the driver wasn’t closed, the next open would lock.&lt;/p&gt;

&lt;h2 id=&quot;integrate-this-functionality-into-kanboard&quot;&gt;Integrate this functionality into Kanboard:&lt;/h2&gt;

&lt;p&gt;Database Interaction: Use Docker and MySQL to interact with Kanboard’s database and fetch the URLs from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_has_external_links&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; kanboard-db-1 /bin/mysql &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; root &lt;span class=&quot;nt&quot;&gt;-psecret&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;use kanboard; select url from task_has_external_links;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;automating-the-scrape-and-save&quot;&gt;Automating the Scrape and Save&lt;/h2&gt;

&lt;p&gt;My goal going forward was to create a PHP plugin that triggers the Selenium script for each fetched URL, scraping the content and saving it to your database as a blob for easy retrieval and manipulation.&lt;/p&gt;

&lt;h2 id=&quot;enhancing-the-scraped-data&quot;&gt;Enhancing the Scraped Data:&lt;/h2&gt;

&lt;p&gt;To refine the scraped data, you might consider using BeautifulSoup, a Python library for parsing HTML and XML documents, to extract just the relevant body content from the saved HTML.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://realpython.com/modern-web-automation-with-python-and-selenium/#motivation-tracking-listening-habits&quot;&gt;Modern Web Automation with Python and Selenium&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/SeleniumHQ/docker-selenium&quot;&gt;Selenium Docker Images&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.selenium.dev/selenium/docs/api/py/webdriver_remote/selenium.webdriver.remote.webdriver.html#selenium.webdriver.remote.webdriver.WebDriver&quot;&gt;Selenium WebDriver Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Fri, 01 Dec 2023 04:41:12 +0000</pubDate>
        <link>https://jmoore53.com/code/infrastructure/docker/2023/12/01/Some-sort-of-kanboard-plugin-to-save-the-external-links-as-a-scraped-site-to-provide-a-preview.html</link>
        <guid isPermaLink="true">https://jmoore53.com/code/infrastructure/docker/2023/12/01/Some-sort-of-kanboard-plugin-to-save-the-external-links-as-a-scraped-site-to-provide-a-preview.html</guid>
        
        
        <category>code</category>
        
        <category>infrastructure</category>
        
        <category>docker</category>
        
      </item>
    
  </channel>
</rss>
