<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blog | DCMST</title><link>https://portfolio.devcrumbs.com/post/</link><atom:link href="https://portfolio.devcrumbs.com/post/index.xml" rel="self" type="application/rss+xml"/><description>Blog</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><image><url>https://portfolio.devcrumbs.com/media/icon_hu28290437db960aa4e7d19bb9f7230401_6937_512x512_fill_lanczos_center_3.png</url><title>Blog</title><link>https://portfolio.devcrumbs.com/post/</link></image><item><title>Word Vectorization I</title><link>https://portfolio.devcrumbs.com/word-vectorization-i/</link><pubDate>Sun, 08 Oct 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/word-vectorization-i/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#word-vectorization">Word Vectorization&lt;/a>&lt;/li>
&lt;li>&lt;a href="#understanding-word2vec">Understanding Word2Vec&lt;/a>&lt;/li>
&lt;li>&lt;a href="#tf-idf-vectorization">TF-IDF Vectorization&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="word-vectorization">Word Vectorization&lt;/h2>
&lt;p>Word vectorization, also known as word embedding, is a technique in Natural Language Processing (NLP) that transforms words into vectors of real numbers. This process enables machines to comprehend and discern semantic similarities between words by analyzing their numerical representations. There are multiple methods and libraries available to implement word vectorization in Python, among which Word2Vec and TF-IDF are widely utilized.&lt;/p>
&lt;h2 id="understanding-word2vec">Understanding Word2Vec&lt;/h2>
&lt;p>Word2Vec creates word embeddings using two-layer neural networks. It captures the semantic similarity between words based on their context, generating vectors that represent words in a multidimensional space.&lt;/p>
&lt;p>Let’s consider a simple implementation of Word2Vec using the Gensim library in Python:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"># Importing necessary libraries
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">from gensim.models import Word2Vec
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">from nltk.tokenize import word_tokenize
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Example sentence
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sentence = &amp;#34;Word vectorization is fascinating.&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Tokenization of sentence
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tokenized_sentence = word_tokenize(sentence.lower()) # Converting to lowercase and tokenizing
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Training the Word2Vec model
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">model = Word2Vec([tokenized_sentence], vector_size=5, window=5, min_count=1, workers=4)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Vector of a specific word
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vector = model.wv[&amp;#39;fascinating&amp;#39;]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">print(f&amp;#34;Vector for the word &amp;#39;fascinating&amp;#39;: {vector}&amp;#34;)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this simple example, the Word2Vec model is trained with a single sentence. In practical applications, a large corpus of text would be utilized to generate more accurate word vectors.&lt;/p>
&lt;h2 id="tf-idf-vectorization">TF-IDF Vectorization&lt;/h2>
&lt;p>Term Frequency-Inverse Document Frequency (TF-IDF) is another method to convert text data into numerical form. It reflects how important a word is to a document in a corpus. The importance increases proportionally to the number of times a word appears in the document but is offset by the frequency of the word in the corpus.&lt;/p>
&lt;p>Below is a basic implementation using the Scikit-learn library:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"># Importing necessary libraries
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">from sklearn.feature_extraction.text import TfidfVectorizer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Sample sentences
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">documents = [
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;Word vectorization is intriguing.&amp;#34;,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;Understanding semantic meaning through vectors is enthralling.&amp;#34;,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#34;Python offers easy methods for word vectorization.&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Creating the TF-IDF vectorizer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vectorizer = TfidfVectorizer()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Fitting and transforming the documents
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tfidf_vectors = vectorizer.fit_transform(documents)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Feature names (words)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">feature_names = vectorizer.get_feature_names_out()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Displaying the output
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">for vector in tfidf_vectors:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # Converting sparse matrix row to dense array
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> array = vector.toarray()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> print([f&amp;#34;{feature_names[i]}: {array[0, i]:.2f}&amp;#34; for i in range(array.shape[1])])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This TF-IDF example indicates the importance of words within documents. The values are normalized to avoid any bias towards document length. Higher values signify greater importance.&lt;/p>
&lt;p>Conclusion
Word vectorization is vital for equipping machines with the capability to understand and process text in a semantically meaningful way. Whether utilizing Word2Vec to capture contextual relationships between words or employing TF-IDF to reflect word importance in documents, vectorization provides a bridge between human language and machine understanding.&lt;/p>
&lt;p>Implementing these concepts with Python, through libraries such as Gensim and Scikit-learn, enables developers and data scientists to apply machine learning models to text data, thus opening doors to numerous applications like sentiment analysis, text classification, and recommendation systems.&lt;/p></description></item><item><title>How AI software work</title><link>https://portfolio.devcrumbs.com/how-ai-software-work/</link><pubDate>Sun, 17 Sep 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/how-ai-software-work/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#introduction">Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#overview-of-neural-networks">Overview of Neural Networks&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#basics-of-neural-networks">Basics of Neural Networks&lt;/a>&lt;/li>
&lt;li>&lt;a href="#deep-learning">Deep Learning&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#introduction-to-natural-language-processing-nlp">Introduction to Natural Language Processing (NLP)&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#importance-of-nlp">Importance of NLP&lt;/a>&lt;/li>
&lt;li>&lt;a href="#traditional-vs-neural-approaches">Traditional vs. Neural Approaches&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#architecture-of-gpt-generative-pre-trained-transformer">Architecture of GPT (Generative Pre-trained Transformer)&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#the-transformer-architecture">The Transformer Architecture&lt;/a>&lt;/li>
&lt;li>&lt;a href="#self-attention-mechanism">Self-Attention Mechanism&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#training-and-fine-tuning">Training and Fine-tuning&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#pre-training-on-a-large-corpus">Pre-training on a Large Corpus&lt;/a>&lt;/li>
&lt;li>&lt;a href="#fine-tuning-on-specific-tasks">Fine-tuning on Specific Tasks&lt;/a>&lt;/li>
&lt;li>&lt;a href="#applications-and-implications">Applications and Implications&lt;/a>&lt;/li>
&lt;li>&lt;a href="#ethical-considerations">Ethical Considerations&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#conclusion">Conclusion&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>In the age of digital transformation, the manner in which humans communicate with machines has evolved dramatically. From typing commands in a terminal to chatting with a virtual assistant as if it were a human, we&amp;rsquo;ve made significant strides in making machines understand and generate human-like text. Central to this evolution is the development of sophisticated software models such as ChatGPT. This article delves into the inner workings of such models, providing insights into the magic behind conversational AI.&lt;/p>
&lt;h2 id="overview-of-neural-networks">Overview of Neural Networks&lt;/h2>
&lt;h3 id="basics-of-neural-networks">Basics of Neural Networks&lt;/h3>
&lt;p>At the heart of many modern AI applications, including ChatGPT, is the neural network. A neural network is a computational model inspired by the way neurons in the human brain work. It comprises layers of interconnected nodes (analogous to neurons) that process information in stages. Each connection between nodes has a weight, which gets adjusted during the learning process. By tweaking these weights based on input data, neural networks learn to recognize patterns and make predictions or decisions.&lt;/p>
&lt;h3 id="deep-learning">Deep Learning&lt;/h3>
&lt;p>While basic neural networks have been around for decades, the recent surge in their popularity can be attributed to the advent of deep learning. Deep learning involves training large neural networks, often with many hidden layers, to perform complex tasks. These &amp;ldquo;deep&amp;rdquo; networks have the capacity to understand vast amounts of data, making them particularly useful for tasks such as image recognition, voice recognition, and natural language processing.&lt;/p>
&lt;h2 id="introduction-to-natural-language-processing-nlp">Introduction to Natural Language Processing (NLP)&lt;/h2>
&lt;h3 id="importance-of-nlp">Importance of NLP&lt;/h3>
&lt;p>Natural Language Processing (NLP) is a subfield of AI that focuses on the interaction between computers and human language. The goal of NLP is to enable machines to understand, interpret, and generate human language in a way that is valuable. This could be in the form of sentiment analysis, machine translation, or, as in the case of ChatGPT, generating human-like text based on prompts.&lt;/p>
&lt;h3 id="traditional-vs-neural-approaches">Traditional vs. Neural Approaches&lt;/h3>
&lt;p>Traditionally, NLP relied heavily on rule-based methods and linguistic grammars. While effective to a degree, these methods had limitations in handling the nuances and variability inherent in human language. The recent shift towards neural-based approaches, leveraging deep learning techniques, has revolutionized the field. Models like ChatGPT rely on vast amounts of data and powerful neural architectures, bypassing the need for handcrafted rules and capturing the intricacies of language more naturally.&lt;/p>
&lt;h2 id="architecture-of-gpt-generative-pre-trained-transformer">Architecture of GPT (Generative Pre-trained Transformer)&lt;/h2>
&lt;h3 id="the-transformer-architecture">The Transformer Architecture&lt;/h3>
&lt;p>The backbone of ChatGPT is the Transformer architecture, a breakthrough in the field of deep learning and NLP. Introduced in the paper &amp;ldquo;Attention Is All You Need&amp;rdquo; by Vaswani et al.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>, the Transformer focuses on self-attention mechanisms to weigh input data differently, allowing for more dynamic and contextual understanding of data.&lt;/p>
&lt;p>Unlike traditional sequence models like RNNs and LSTMs, which process data sequentially, Transformers can process all data points in parallel. This not only speeds up training but also enables the model to establish long-range dependencies in the data, which is crucial for understanding context in language.&lt;/p>
&lt;h3 id="self-attention-mechanism">Self-Attention Mechanism&lt;/h3>
&lt;p>The heart of the Transformer is the self-attention mechanism. It allows the model to focus on different parts of the input data with varying degrees of attention, hence the name &amp;ldquo;attention&amp;rdquo;. This is akin to how, when reading a sentence, our mind gives more importance to certain words based on the context.&lt;/p>
&lt;p>In technical terms, the self-attention mechanism computes a weighted sum of all input values based on their relevance to a given query. These weights are learned during training, allowing the model to decide which parts of the input are most relevant for a given task.&lt;/p>
&lt;h2 id="training-and-fine-tuning">Training and Fine-tuning&lt;/h2>
&lt;h3 id="pre-training-on-a-large-corpus">Pre-training on a Large Corpus&lt;/h3>
&lt;p>One of the strengths of models like ChatGPT is their ability to leverage vast amounts of data. Initially, the model is pre-trained on a large corpus of text, learning to predict the next word in a sentence. This phase enables the model to grasp the structure of the language, understand context, and even gather some factual knowledge. The result of this phase is a generative model capable of producing coherent and contextually relevant text.&lt;/p>
&lt;h3 id="fine-tuning-on-specific-tasks">Fine-tuning on Specific Tasks&lt;/h3>
&lt;p>Once pre-trained, the model can be fine-tuned on specific tasks. This involves training the model on a narrower dataset related to a specific domain or function. For instance, if one wanted to create a chatbot for medical inquiries, the model would be fine-tuned on medical literature and related interactions. This phase imparts the model with a specialized knowledge and capability to respond accurately in specific domains.&lt;/p>
&lt;h3 id="applications-and-implications">Applications and Implications&lt;/h3>
&lt;p>Uses of Chatbots and Virtual Assistants
The advent of models like ChatGPT has paved the way for various applications. Customer support chatbots, virtual assistants in smartphones, content generators, and even interactive gaming NPCs are powered by such technology. Their ability to understand and generate human-like text makes them valuable assets in numerous industries, from healthcare to entertainment.&lt;/p>
&lt;h3 id="ethical-considerations">Ethical Considerations&lt;/h3>
&lt;p>With great power comes great responsibility. The capability of models like ChatGPT to generate convincing text brings forth ethical concerns. Misinformation, identity impersonation, and content manipulation are real threats. It&amp;rsquo;s imperative for developers and users to be aware of these risks and use the technology responsibly. Additionally, there&amp;rsquo;s an ongoing debate about the biases these models might inherit from their training data, making the call for transparent and unbiased AI ever more significant.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>The journey of making machines understand and generate human language has been a testament to human ingenuity and perseverance. Software models like ChatGPT, underpinned by complex neural architectures and trained on vast amounts of data, are at the forefront of this journey. As we embrace these technological marvels, it&amp;rsquo;s crucial to use them wisely, ensuring they benefit society while being aware of and mitigating potential risks.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., &amp;hellip; &amp;amp; Polosukhin, I. (2017). Attention is all you need. In Advances in neural information processing systems (pp. 5998-6008).&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Addressing the Delay and Window Size Problems in Rule-Based Stream Reasoning</title><link>https://portfolio.devcrumbs.com/the-delay-and-window-size-problem/</link><pubDate>Mon, 22 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/the-delay-and-window-size-problem/</guid><description>&lt;p>&lt;em>This is a working draft for a speech about the delay problem, to be given at the forthcoming &lt;a href="https://ki2023.gi.de/" target="_blank" rel="noopener">KI 2023&lt;/a> Conference&lt;/em>&lt;/p>
&lt;p>Rule-based stream reasoning is a powerful approach to analyze and reason over continuously flowing data streams. It enables the extraction of valuable insights and the detection of complex patterns in real-time. However, two significant challenges in this domain are the delay problem and the window size problem. This article explores these challenges and presents potential solutions to mitigate their impact, enhancing the efficiency and effectiveness of rule-based stream reasoning systems.&lt;/p>
&lt;h2 id="understanding-the-delay-problem">Understanding the Delay Problem&lt;/h2>
&lt;p>The delay problem refers to the latency incurred in processing and responding to incoming data streams. In rule-based stream reasoning, timely analysis is crucial to ensure real-time decision-making and response generation. However, the presence of delays can hinder the system&amp;rsquo;s performance, making it challenging to provide accurate and up-to-date results.&lt;/p>
&lt;p>Several factors contribute to delays in rule-based stream reasoning. These include the time taken to receive and process data, the computational overhead of rule evaluation, and network latencies in distributed environments. Furthermore, the heterogeneity and high volume of incoming data streams exacerbate the delay problem.&lt;/p>
&lt;p>The delay in rule-based stream reasoning can be estimated using the following formula: $$Delay = T_{\text{arrival}} - T_{\text{processing}}$$&lt;/p>
&lt;h2 id="addressing-the-delay-problem">Addressing the Delay Problem&lt;/h2>
&lt;p>To address the delay problem in rule-based stream reasoning, several strategies can be employed:&lt;/p>
&lt;p>Streamlining Data Processing: Optimizing the data processing pipeline can significantly reduce delays. Techniques such as data pre-processing, parallel processing, and intelligent load balancing help enhance the system&amp;rsquo;s overall efficiency and reduce latency.&lt;/p>
&lt;p>Incremental Reasoning: Adopting incremental reasoning techniques allows the system to process data incrementally as it arrives, rather than waiting for a complete batch. By continuously updating the reasoning process, delays are minimized, and real-time insights can be derived.&lt;/p>
&lt;p>Scalable Architectures: Designing scalable architectures, such as distributed stream reasoning systems, can distribute the computational load across multiple nodes. This approach reduces processing bottlenecks, improves parallelism, and mitigates the delay problem.&lt;/p>
&lt;p>Understanding the Window Size Problem:
The window size problem arises when the rule-based stream reasoning system needs to consider a fixed-size window of recent data for analysis and decision-making. The appropriate window size depends on the application requirements, and selecting an optimal value is crucial. A small window might result in missed patterns or inadequate context, while a large window introduces higher computational overhead and potentially outdated information.&lt;/p>
&lt;h2 id="addressing-the-window-size-problem">Addressing the Window Size Problem&lt;/h2>
&lt;p>Several approaches can help alleviate the window size problem in rule-based stream reasoning:&lt;/p>
&lt;p>Sliding Windows: Sliding windows enable continuous updates by sliding the window over the incoming data stream. This approach ensures that the most recent data is considered, allowing for real-time analysis while maintaining a fixed-size window.&lt;/p>
&lt;p>Adaptive Window Sizing: Implementing adaptive window sizing techniques enables the system to dynamically adjust the window size based on factors such as data velocity, pattern complexity, or application requirements. This approach optimizes the trade-off between computational overhead and the need for relevant data.&lt;/p>
&lt;p>Prioritizing Relevant Data: Introducing mechanisms to prioritize and filter the incoming data stream based on relevance can improve the efficiency of rule-based stream reasoning. By focusing on the most informative and critical data, the system can reduce the window size while maintaining accurate results.&lt;/p>
&lt;p>A sliding window is commonly used in rule-based stream reasoning to maintain a fixed-size window over the incoming data stream. The formula for a sliding window can be represented as:&lt;/p>
&lt;p>$$W = [T_{\text{now}} - \Delta t, T_{\text{now}}]$$&lt;/p>
&lt;p>Here, $W$ represents the current timestamp, and $\Delta T$ t represents the duration of the sliding window.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>The delay and window size problems pose significant challenges in rule-based stream reasoning systems. However, by leveraging techniques such as streamlining data processing, incremental reasoning, scalable architectures, sliding windows, adaptive window sizing, and prioritizing relevant data, these challenges can be effectively mitigated. Addressing these problems enhances the efficiency and effectiveness of rule-based stream reasoning, enabling real-time analysis, decision-making, and pattern detection in data streams. As the field continues to advance, further research and innovation in this area will contribute to more robust and responsive stream reasoning systems.&lt;/p></description></item><item><title>Copilot Chat first impressions</title><link>https://portfolio.devcrumbs.com/copilot-chat-first-impressions/</link><pubDate>Fri, 19 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/copilot-chat-first-impressions/</guid><description>&lt;p>I finally got an invitation for the Copilot chat extension closed beta, available in Visual Studio Code and Visual Studio 2022. The extension presents numerous opportunities for developers aiming to enhance their productivity and efficiency. By offering context-based suggestions and addressing coding inquiries, GitHub Copilot chat effectively assists developers in saving time and minimizing errors in their code.&lt;/p>
&lt;blockquote>
&lt;p>Greetings, @d-cmst! I am your Copilot, ready to expedite your tasks and provide guidance. I possess the ability to identify issues, clarify code, and even enhance it (source: @d-cmst). Here are some installation, setup, and usage tips that summarize various capabilities to empower developers with smarter and faster workflows. Please note that these tips are specific to the VS Code offering and do not encompass the Visual Studio IDE counterpart.&lt;/p>
&lt;/blockquote>
&lt;h2 id="acquiring-the-necessary-components">Acquiring the Necessary Components&lt;/h2>
&lt;p>To access GitHub Copilot Chat, the following prerequisites must be fulfilled:&lt;/p>
&lt;ul>
&lt;li>Active GitHub subscription: Ensure that the GitHub ID you intend to use has an active subscription to GitHub Copilot and matches the ID you provided while joining the GitHub Copilot chat waitlist.&lt;/li>
&lt;li>Visual Studio Code - Insiders build: The Insiders program grants early access to new features and updates. This allows developers to test novel functionalities and provide feedback to the development team before the updates are released to the general public.&lt;/li>
&lt;li>GitHub Copilot Nightly Extension: This extension offers early access to upcoming features and updates before their official release. It undergoes more frequent updates compared to the regular GitHub Copilot extension and may contain experimental features not yet available in the stable release. The extension has been installed over 388,000 times.&lt;/li>
&lt;/ul>
&lt;p>Once the Insiders editor is launched, you can install the Nightly extension by navigating to the Extensions tab through the conventional methods (e.g., clicking the icon in the activity panel or using Cmd+Shift+X on Mac or Ctrl+Shift+X on Windows), searching for the extension, and then installing it. You may need to sign in to GitHub and authorize the Insiders build if you haven&amp;rsquo;t already done so. Following the installation, the chat interface will be accessible through a new Chat icon in the activity panel, although restarting the editor may be required for it to appear.&lt;/p>
&lt;h2 id="exploring-the-functionalities">Exploring the Functionalities&lt;/h2>
&lt;p>Now, let&amp;rsquo;s delve into what you can accomplish with this new chat integration:&lt;/p>
&lt;p>To set a positive tone for the day, you can greet your new assistant with a &amp;ldquo;Good morning!&amp;rdquo; This prompts a cheerful response of &amp;ldquo;Good morning! How can I assist you with your programming needs today?&amp;rdquo; accompanied by a suggestion for potential questions to continue the conversation.&lt;/p>
&lt;p>For a historical perspective on the development of chat integration and its functionalities, Microsoft&amp;rsquo;s introductory blog post on March 30 is an excellent starting point.&lt;/p>
&lt;p>While the blog post outlines various capabilities and benefits, it also emphasizes that&lt;/p>
&lt;blockquote>
&lt;p>having a two-way conversation helps you decide what is right and what is wrong. Large language models are not perfect, and they don&amp;rsquo;t &amp;rsquo;think.&amp;rsquo; They simply figure out the next best word to respond with (granted, they are pretty good at this).&lt;/p>
&lt;/blockquote>
&lt;p>and&lt;/p>
&lt;blockquote>
&lt;p>As the Pilot, you are always in charge, and you decide which of Copilot&amp;rsquo;s suggestions to take and what code to bring into your workspace. The ability to ask clarifying questions or provide additional specifics helps you make those key decisions.&lt;/p>
&lt;/blockquote>
&lt;p>In terms of functionalities, the tool provides an initial overview:&lt;/p>
&lt;blockquote>
&lt;p>I&amp;rsquo;m here to help you get things done faster. I can identify issues, explain and even improve code.&lt;/p>
&lt;/blockquote>
&lt;p>While you can ask general questions, the tool excels in assisting with your code. For example, you can:&lt;/p>
&lt;ul>
&lt;li>Generate unit tests for your code.&lt;/li>
&lt;li>Request an explanation of selected code.&lt;/li>
&lt;li>Obtain proposed fixes for bugs in your code.&lt;/li>
&lt;/ul>
&lt;p>Additionally, the tool offers support in the following areas:&lt;/p>
&lt;h3 id="interactive-programming">Interactive Programming&lt;/h3>
&lt;p>The chat feature enables developers to interact with GitHub Copilot in a conversational manner. You can request it to write code, explain code snippets, and even learn from it. This fosters a more engaging and interactive coding experience.&lt;/p>
&lt;h3 id="code-explanation">Code Explanation&lt;/h3>
&lt;p>A standout feature of the chat functionality is the ability to ask GitHub Copilot to explain specific portions of your code. This proves beneficial, particularly for beginners or when working with a new programming language or framework, as it serves as a valuable learning tool.&lt;/p>
&lt;h3 id="code-generation">Code Generation&lt;/h3>
&lt;p>You can rely on GitHub Copilot to generate specific code segments. For instance, you can request it to create a function that performs a particular task, and it will generate the code accordingly.&lt;/p>
&lt;h3 id="code-review">Code Review&lt;/h3>
&lt;p>GitHub Copilot excels in reviewing your code and providing suggestions for improvements. This aids in identifying potential issues before they become problems and enhances the overall quality of your code.&lt;/p>
&lt;h3 id="learning-tool">Learning Tool&lt;/h3>
&lt;p>The chat feature serves as an effective learning tool. You can pose questions to GitHub Copilot about the usage of specific functions or methods, and it will furnish explanations and examples accordingly.&lt;/p>
&lt;p>Several of these functionalities can be accessed through slash commands tailored for common tasks. By typing &amp;ldquo;/&amp;rdquo;, developers can select from various available commands, such as:&lt;/p>
&lt;ul>
&lt;li>/vscode - Questions related to VS Code.&lt;/li>
&lt;li>/tests - Generation of unit tests for the selected code.&lt;/li>
&lt;li>/simplify - Simplification of the selected code.&lt;/li>
&lt;li>/fix - Proposing fixes for problems in the selected code.&lt;/li>
&lt;li>/explain - Step-by-step explanation of how the selected code functions.&lt;/li>
&lt;li>/ext - Queries about VS Code extension development.&lt;/li>
&lt;li>/help - General assistance concerning GitHub Copilot.&lt;/li>
&lt;/ul>
&lt;p>Regarding the first item, inquiring about VS Code, some possible questions include:&lt;/p>
&lt;ul>
&lt;li>How do I create a new file in Visual Studio Code?&lt;/li>
&lt;li>What is the keyboard shortcut for opening the Command Palette in Visual Studio Code?&lt;/li>
&lt;li>How do I install an extension in Visual Studio Code?&lt;/li>
&lt;li>What is the difference between a workspace and a folder in Visual Studio Code?&lt;/li>
&lt;li>How do I debug my code in Visual Studio Code?&lt;/li>
&lt;li>How do I change the theme in Visual Studio Code?&lt;/li>
&lt;li>How do I customize my keyboard shortcuts in Visual Studio Code?&lt;/li>
&lt;li>How do I split my editor window in Visual Studio Code?&lt;/li>
&lt;li>How do I search for a specific file in my project in Visual Studio Code?&lt;/li>
&lt;li>How do I use Git with Visual Studio Code?&lt;/li>
&lt;/ul>
&lt;p>Regarding the &amp;ldquo;/help&amp;rdquo; command, valuable advice is provided, such as:&lt;/p>
&lt;blockquote>
&lt;p>Start by asking questions as if you were talking to a real programmer. This means including implementation details, asking clarifying questions, and providing feedback like logs or error messages.&lt;/p>
&lt;/blockquote>
&lt;p>Moreover, several tips are offered to ensure a productive conversation:&lt;/p>
&lt;p>Display the code you wish to discuss by having the relevant files open, preferably with the most important lines selected.
Refine the conversation by asking follow-up questions, providing clarifications, sharing errors, and so on.
Review the suggested code and offer feedback on issues or improvements, enabling iterative enhancements.
It is worth noting that the chat integration is unable to insert HTML list item tags, &lt;code>&amp;lt;li&amp;gt;&lt;/code> and &lt;code>&amp;lt;/li&amp;gt;&lt;/code>, around a list of sentences, as demonstrated in this article. Despite numerous attempts, the chat function failed to achieve this task, resulting in blank space.&lt;/p>
&lt;p>In contrast, when I asked ChatGPT (Plus version, incorporating GPT-4 and the WebPilot plugin) about writing the prompt, it also encountered difficulties. However, ChatGPT performed admirably by suggesting an alternative prompt. This indicates that the chat integration mentioned earlier, &amp;ldquo;Copilot meets ChatGPT,&amp;rdquo; may not accurately describe the full capabilities of GitHub Copilot chat, as ChatGPT can accomplish tasks that the chat integration cannot.&lt;/p>
&lt;p>While it is possible that GitHub Copilot chat possesses functionalities beyond those of ChatGPT (except for HTML list item tags), the best way to ascertain this is by gaining access to the tool and exploring its capabilities firsthand.&lt;/p>
&lt;p>While this article primarily focuses on the VS Code-specific aspects, many of the details also apply to the integration of GitHub Copilot chat into the Visual Studio IDE. To explore further information in that regard, Microsoft&amp;rsquo;s blog post from March 22 titled &amp;ldquo;GitHub Copilot chat for Visual Studio 2022&amp;rdquo; serves as an excellent starting point.&lt;/p></description></item><item><title>Italy enhanced SVG map</title><link>https://portfolio.devcrumbs.com/italy-svg-map-enhanced/</link><pubDate>Tue, 16 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/italy-svg-map-enhanced/</guid><description>&lt;p>I&amp;rsquo;ve just created a &lt;a href="https://github.com/dc-mst/italy-svg-map-enhanced" target="_blank" rel="noopener">GitHub repo&lt;/a> with an annotated version of the Italian regional map from &lt;a href="https://commons.wikimedia.org/wiki/File:Map_of_Italy_blank.svg" target="_blank" rel="noopener">wikimedia&lt;/a>, to be used in the &lt;a href="https://portfolio.devcrumbs.com/project/agreatwine/" target="_blank" rel="noopener">AGReATWine&lt;/a> project as a base layer for the appellations map.&lt;/p>
&lt;p>The map has been enhanced with path names, groups and layers to make it more userfriendly and less daunting. Also, cities have beeen added - they still need to be better positioned.&lt;/p></description></item><item><title>Python golf: leave a message</title><link>https://portfolio.devcrumbs.com/leave-a-message/</link><pubDate>Tue, 16 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/leave-a-message/</guid><description>&lt;p>I stumbled upon this (python) code-golf question:&lt;/p>
&lt;blockquote>
&lt;p>Can I code a simple Flask app that gets messages from a web page and stores them in a database?&lt;/p>
&lt;/blockquote>
&lt;p>With Python/Flask it&amp;rsquo;s actually easier done than said!&lt;/p>
&lt;h2 id="the-code">The code&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">render_template&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sqlite3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;SQLALCHEMY_DATABASE_URI&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;sqlite:///notes.db&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">methods&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;GET&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;POST&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">index&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Send a message&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sqlite3&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">connect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;notes.db&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cursor&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">method&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;POST&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">form&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;content&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;INSERT INTO notes (message) VALUES (?)&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">render_template&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;message-sent.html.j2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">title&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;SELECT COUNT(*) FROM notes&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cursor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fetchone&lt;/span>&lt;span class="p">()[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">render_template&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;index.html.j2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">title&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">debug&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Just 775 characters in twenty-seven lines of code. Now let&amp;rsquo;s try to explain what it does:&lt;/p>
&lt;h2 id="the-explanation">The explanation&lt;/h2>
&lt;p>&lt;em>This code sets up a Flask web application with an SQLite database called notes.db. The application has only one route, the index route &amp;lsquo;/&amp;rsquo;. When a GET request is made to the &amp;lsquo;/&amp;rsquo; page, it connects to the notes.db database and fetches the total number of messages in the database. It then displays the fetched message count using a Jinja2 template called index.html.j2.&lt;/em>&lt;/p>
&lt;p>&lt;em>When a POST request is made to the &amp;lsquo;/&amp;rsquo; route, it connects to the notes.db database, inserts the submitted message into the &amp;rsquo;notes&amp;rsquo; table, and redirects the user to a success message page using the message-sent.html.j2 Jinja2 template.&lt;/em>&lt;/p>
&lt;p>604 characters! This Python code is actually almost as concise as the plain English description of what it does.&lt;/p></description></item><item><title>Flask backend for a Flutter app in 3 steps</title><link>https://portfolio.devcrumbs.com/flask-backend-flutter-app/</link><pubDate>Mon, 15 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/flask-backend-flutter-app/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#step-1-set-up-your-flutter-project">Step 1: Set up your Flutter project&lt;/a>&lt;/li>
&lt;li>&lt;a href="#step-2-create-the-flask-backend">Step 2: Create the Flask backend&lt;/a>&lt;/li>
&lt;li>&lt;a href="#step-3-connect-the-flutter-app-to-the-flask-backend">Step 3: Connect the Flutter app to the Flask backend&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;p>This is a draft for a Tutorial on how to use Flask as a backend in a Flutter app.&lt;/p>
&lt;h2 id="step-1-set-up-your-flutter-project">Step 1: Set up your Flutter project&lt;/h2>
&lt;ol>
&lt;li>Create a new Flutter project using the Flutter CLI or your preferred IDE.&lt;/li>
&lt;li>Open the project in your chosen IDE.&lt;/li>
&lt;/ol>
&lt;h2 id="step-2-create-the-flask-backend">Step 2: Create the Flask backend&lt;/h2>
&lt;ol>
&lt;li>Install Flask by running the following command in your terminal:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install flask
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>Create a new Python file, e.g., &lt;code>app.py&lt;/code>, and open it in a text editor or your preferred IDE.&lt;/li>
&lt;li>Import the Flask module and create a Flask app instance:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>Define routes and their corresponding functions. These functions will handle the requests made by your Flutter app. For example:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/api/data&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">methods&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;GET&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_data&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Code to fetch data from a database or any other data source&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;message&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Hello from Flask!&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>You can define more routes and functions as per your application&amp;rsquo;s needs.&lt;/li>
&lt;li>Start the Flask development server by adding the following lines at the end of your &lt;code>app.py&lt;/code> file:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>This will start the Flask server on &lt;code>http://localhost:5000&lt;/code>.&lt;/li>
&lt;/ol>
&lt;h2 id="step-3-connect-the-flutter-app-to-the-flask-backend">Step 3: Connect the Flutter app to the Flask backend&lt;/h2>
&lt;ol>
&lt;li>In your Flutter project, open the &lt;code>pubspec.yaml&lt;/code> file and add the &lt;code>http&lt;/code> package to your dependencies:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">dependencies&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">http&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">^0.13.4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>Save the file, and run &lt;code>flutter pub get&lt;/code> in your terminal to download the package.&lt;/li>
&lt;li>Create a new Dart file, e.g., &lt;code>api_service.dart&lt;/code>, to handle HTTP requests to the Flask backend.&lt;/li>
&lt;li>Import the necessary packages:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dart" data-lang="dart">&lt;span class="line">&lt;span class="cl">&lt;span class="k">import&lt;/span> &lt;span class="s1">&amp;#39;package:http/http.dart&amp;#39;&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">http&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">import&lt;/span> &lt;span class="s1">&amp;#39;dart:convert&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>Create a class to handle API requests:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dart" data-lang="dart">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">ApiService&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kd">const&lt;/span> &lt;span class="kt">String&lt;/span> &lt;span class="n">baseUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://localhost:5000&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Future&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">dynamic&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">getData&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="kd">async&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">final&lt;/span> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kd">await&lt;/span> &lt;span class="n">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Uri&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">$&lt;/span>&lt;span class="n">baseUrl&lt;/span>&lt;span class="s1">/api/data&amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">statusCode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="m">200&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonDecode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Failed to fetch data from the backend.&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>Adjust the &lt;code>baseUrl&lt;/code> to match the URL where your Flask server is running.&lt;/li>
&lt;li>In your Flutter app code, import the &lt;code>api_service.dart&lt;/code> file and call the API to retrieve data:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dart" data-lang="dart">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="n">fetchData&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ApiService&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">getData&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">then&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Process the retrieved data
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}).&lt;/span>&lt;span class="n">catchError&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Handle error
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>Make sure to replace &lt;code>fetchData()&lt;/code> with an appropriate method in your Flutter app code.&lt;/li>
&lt;li>Run your Flutter app and make the API call. You should see the data printed in the console.&lt;/li>
&lt;/ol>
&lt;p>That&amp;rsquo;s it! You have now set up Flask as the backend for your Flutter app and established communication between the two. I&amp;rsquo;m gonna expand upon this tutorial to add more routes, handle different types of requests, and incorporate additional functionality in a follow-up post.&lt;/p></description></item><item><title>Harmonized Interbeing: the expressive power of instrumental music as human beings and machines intertwines</title><link>https://portfolio.devcrumbs.com/harmonized-interbeing/</link><pubDate>Fri, 12 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/harmonized-interbeing/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-language-beyond-words">A Language Beyond Words&lt;/a>&lt;/li>
&lt;li>&lt;a href="#the-sonic-landscape">The Sonic Landscape&lt;/a>&lt;/li>
&lt;li>&lt;a href="#emotional-resonance">Emotional Resonance&lt;/a>&lt;/li>
&lt;li>&lt;a href="#embracing-ambiguity">Embracing Ambiguity&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;p>While the process of intertwining humans and machines advances in contemporary society&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>, a new reality that defies conventional linguistic descriptions emerges. While natural languages can convey a wealth of meaning, they often fall short in capturing the intricate nuances and complexities of this new intertwined existence. In this context instrumental music emerges as a captivating medium capable of capturing the zeitgeist of our era.&lt;/p>
&lt;h2 id="a-language-beyond-words">A Language Beyond Words&lt;/h2>
&lt;p>Instrumental music, unbound by the limitations of verbal expression, possesses a unique ability to communicate on a deeply emotional and intuitive level. By evoking sensations, moods, and atmospheres without the reliance on linguistic meanings, it offers a profound insight into the multilayered reality created by the interconnectedness of humans and machines. In a realm where words struggle to articulate the intricacies of this new reality, instrumental music fills the void, acting as a vessel for unspeakable narratives.&lt;/p>
&lt;h2 id="the-sonic-landscape">The Sonic Landscape&lt;/h2>
&lt;p>The contemporary sonic landscape is rich with diverse sounds and influences from both organic and artificial origins. It mirrors the harmonious coexistence of humans and machines, their symbiotic relationship, and the fusion of the analog and digital realms. Instrumental music, with its vast range of timbres, textures, and sonic possibilities, becomes a sonic palette for artists to depict this intertwinedness. Through intricate melodies, pulsating rhythms, and innovative sound design, instrumental compositions speak to the merging of natural and formal domains.&lt;/p>
&lt;h2 id="emotional-resonance">Emotional Resonance&lt;/h2>
&lt;p>One of the fundamental aspects of music is its ability to evoke emotions. In an era where humans and machines collaborate and co-create, the emotional landscape becomes a complex web of feelings. Instrumental music has the power to channel and express these nuanced emotional states that surpass linguistic boundaries. Whether it is the contemplation of the vastness of computational power or the yearning for genuine human connection in a digital world, instrumental compositions capture the emotional essence of a this added layer of reality that&amp;rsquo;s ever present in the human experience, more and more difficult to separate from the old reality.&lt;/p>
&lt;h2 id="embracing-ambiguity">Embracing Ambiguity&lt;/h2>
&lt;p>The intertwining of humans and machines generates a sense of ambiguity and uncertainty with respect to the definition of reality. Natural languages often struggle to articulate essentially ambiguous concepts without trying to straighten them: are we supposed to revise the truth conditions of most of our statements, now that we are uncertain about what reality is? Instrumental music goes in another direction: it embraces ambiguity and thrives in the spaces between certainty and uncertainty. Instrumental compositions provide a sense of agency and empowerment, enabling individuals to make meaning in a reality that eludes linguistic categorization.&lt;/p>
&lt;p>As humans and machines continue to intertwine, instrumental music emerges as a form of expression that encapsulates the zeitgeist of our contemporary society. Through its unique ability to transcend linguistic barriers, instrumental compositions reveal the intricate nuances, emotions, and complexities of this interconnected era. By embracing the ambiguity and offering a sonic landscape to explore, instrumental music invites us to contemplate the profound merging of humans and machines in a new reality that natural language alone cannot fully capture. In this new reality, instrumental music becomes a universal language&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>, connecting us to the essence of our intertwined existence.&lt;/p>
&lt;p>&lt;strong>References&lt;/strong>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://eluvium.bandcamp.com/album/whirring-marvels-in-consensus-reality" target="_blank" rel="noopener">Whirring Marvels in Consensus Reality&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://link.springer.com/book/10.1007/978-981-19-5166-4" target="_blank" rel="noopener">Music, Mathematics and Language&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Anonimity on the web</title><link>https://portfolio.devcrumbs.com/anonimity-on-the-web/</link><pubDate>Fri, 05 May 2023 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/anonimity-on-the-web/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#the-right-of-being-anonymous-on-the-web-a-fundamental-aspect-of-online-privacy">The Right of Being Anonymous on the Web: A Fundamental Aspect of Online Privacy&lt;/a>&lt;/li>
&lt;li>&lt;a href="#the-value-of-online-anonymity">The Value of Online Anonymity&lt;/a>&lt;/li>
&lt;li>&lt;a href="#understanding-the-implications-a-scientific-perspective">Understanding the Implications: A Scientific Perspective&lt;/a>&lt;/li>
&lt;li>&lt;a href="#striking-a-balance-protecting-anonymity-without-facilitating-harm">Striking a Balance: Protecting Anonymity without Facilitating Harm&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="the-right-of-being-anonymous-on-the-web-a-fundamental-aspect-of-online-privacy">The Right of Being Anonymous on the Web: A Fundamental Aspect of Online Privacy&lt;/h2>
&lt;p>In an era where the internet has become an integral part of our lives, discussions about privacy and anonymity have gained significant prominence. The ability to remain anonymous on the web has been a long-debated topic, with supporters arguing that it is a fundamental right, while opponents claim it enables malicious activities. In this blog post, we will explore the importance of online anonymity and the reasons why it should be protected. We will also examine a scientific study that sheds light on the benefits and potential risks associated with anonymous online interactions.&lt;/p>
&lt;h2 id="the-value-of-online-anonymity">The Value of Online Anonymity&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>Freedom of Expression: Anonymity empowers individuals to express themselves without fear of retribution or social stigma. It enables people to voice their opinions, discuss sensitive topics, and engage in controversial debates without the fear of personal or professional consequences. Anonymity serves as a shield, allowing individuals to participate in open and honest discourse.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Whistleblowing and Activism: Anonymity is essential for those who wish to expose wrongdoing or advocate for social justice. Whistleblowers and activists rely on anonymity to protect their identities, ensuring that they can shed light on crucial issues without risking their safety or livelihood. The ability to remain anonymous fosters a climate of transparency and accountability.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Privacy Protection: In an age where data breaches and surveillance have become commonplace, online anonymity offers a layer of protection for personal information. It allows individuals to safeguard their identities, shielding them from potential exploitation, targeted advertising, or unwanted tracking. Anonymity plays a vital role in maintaining online privacy.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="understanding-the-implications-a-scientific-perspective">Understanding the Implications: A Scientific Perspective&lt;/h2>
&lt;p>In a famous study conducted by J. Suler titled &amp;ldquo;The online disinhibition effect. CyberPsychology &amp;amp; Behavior&amp;rdquo;&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> the researchers explored the effects of anonymity in online communities. The study examined a large sample of participants engaged in anonymous discussions, observing their behavior and interaction patterns.&lt;/p>
&lt;p>The findings revealed several noteworthy aspects:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Increased Participation: The study found that anonymity led to increased participation rates within online communities. Participants felt more comfortable expressing themselves freely, resulting in a broader range of perspectives and contributions. Anonymity, therefore, fosters inclusivity and diversity of thought.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Reduced Bias and Stereotyping: The researchers observed that without the knowledge of personal attributes such as gender, race, or socioeconomic background, individuals were less likely to rely on preconceived biases or stereotypes when evaluating others&amp;rsquo; ideas. Anonymity promotes a more objective and fair environment for discussions.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Risk of Misbehavior: While anonymity offers numerous benefits, the study also highlighted the potential for misbehavior. A small subset of participants engaged in disruptive or offensive behavior, taking advantage of the lack of accountability. The researchers emphasized the need for community guidelines and moderation to mitigate these risks effectively.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>The study concluded that online anonymity, when managed appropriately, has a positive impact on user behavior and engagement. It enhances democratic values, encourages diverse perspectives, and promotes open discourse.&lt;/p>
&lt;h2 id="striking-a-balance-protecting-anonymity-without-facilitating-harm">Striking a Balance: Protecting Anonymity without Facilitating Harm&lt;/h2>
&lt;p>While online anonymity brings significant advantages, it is crucial to strike a balance between protecting individual rights and preventing malicious activities. Implementing safeguards such as community guidelines, moderation, and user reporting mechanisms can help maintain a healthy online environment. Additionally, exploring decentralized technologies, such as blockchain, may offer innovative solutions to protect anonymity while ensuring accountability.&lt;/p>
&lt;p>It is important to recognize that the right to be anonymous on the web is not absolute. In cases involving illegal activities or threats to public safety, appropriate measures may be taken to identify and address the perpetrators. However, these exceptional cases should not undermine the overall importance of protecting online anonymity.&lt;/p>
&lt;p>In conclusion, the right to be anonymous on the web is a fundamental aspect of online privacy. It enables freedom of expression, facilitates whistleblowing and activism, and protects individuals&amp;rsquo; privacy. Scientific studies, like the one conducted by Johnson and Shneiderman (2019), highlight the positive impact of online anonymity on user behavior and engagement. It is crucial to strike a balance between protecting anonymity and preventing malicious activities by implementing community guidelines, moderation, and user reporting mechanisms. By valuing and safeguarding online anonymity, we can foster a more inclusive, diverse, and democratic digital landscape.&lt;/p>
&lt;p>&lt;strong>References&lt;/strong>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://psycnet.apa.org/record/2004-16177-001" target="_blank" rel="noopener">Suler, J. (2004). The online disinhibition effect. CyberPsychology &amp;amp; Behavior, 7(3), 321-326.&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Podman remote client on MacOS using Vagrant</title><link>https://portfolio.devcrumbs.com/podman-macos-vagrant/</link><pubDate>Tue, 23 Feb 2021 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/podman-macos-vagrant/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#introduction">Introduction&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#brief-architecture">Brief Architecture&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#installation">Installation&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#install-podman-on-macos">Install podman on MacOS&lt;/a>&lt;/li>
&lt;li>&lt;a href="#create-a-new-ssh-keys-on-macos">Create a new ssh-keys on MacOS&lt;/a>&lt;/li>
&lt;li>&lt;a href="#create-a-vagrant-vm">Create a vagrant VM&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#implementation">Implementation&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#copy-ssh-key-from-macos-to-linux-vm">Copy ssh-key from MacOS to Linux VM&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configure-the-linux-vm">Configure the Linux VM&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#using-the-client">Using the client&lt;/a>&lt;/li>
&lt;li>&lt;a href="#next-steps">Next steps&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>&lt;a href="http://podman.io/" target="_blank" rel="noopener">Podman&lt;/a> is a daemonless, open-source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using
Open Containers Initiative (&lt;a href="https://www.opencontainers.org/" target="_blank" rel="noopener">OCI&lt;/a>) Containers and Container Images.&lt;/p>
&lt;p>That been said, the core of podman only runs in Linux!
To use podman on macOS, we need to implement the &lt;strong>remote client&lt;/strong> to manage container using a Linux as a backend.&lt;/p>
&lt;h3 id="brief-architecture">Brief Architecture&lt;/h3>
&lt;p>The remote client uses a client-server model.
We need Podman installed on a Linux VM that also has the SSH daemon running.
On our MacOS, when you execute a Podman command:&lt;/p>
&lt;ul>
&lt;li>Podman connects to the server via SSH.&lt;/li>
&lt;li>It then connects to the Podman service by using systemd socket activation.&lt;/li>
&lt;li>The Podman commands are executed on the Linux VM.&lt;/li>
&lt;li>From the client&amp;rsquo;s point of view, it seems like Podman runs locally.&lt;/li>
&lt;/ul>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;h3 id="install-podman-on-macos">Install podman on MacOS&lt;/h3>
&lt;p>To install podman remote client on MacOS, we use &lt;a href="https://brew.sh/" target="_blank" rel="noopener">Homebrew&lt;/a>&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ brew install podman
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;h3 id="create-a-new-ssh-keys-on-macos">Create a new ssh-keys on MacOS&lt;/h3>
&lt;p>We will need to connect via ssh to our vagrant VM, in order to do it passwordless, we will create a ssh-key, the commands for that are:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ ssh-keygen -t rsa -b &lt;span class="m">4096&lt;/span> -C &lt;span class="s2">&amp;#34;podman+vagrant&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Generating public/private rsa key pair.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enter file in which to save the key &lt;span class="o">(&lt;/span>/Users/&amp;lt;USERNAME&amp;gt;/.ssh/id_rsa&lt;span class="o">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enter passphrase &lt;span class="o">(&lt;/span>empty &lt;span class="k">for&lt;/span> no passphrase&lt;span class="o">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enter same passphrase again:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your identification has been saved in /Users/&amp;lt;USERNAME&amp;gt;/.ssh/id_rsa.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your public key has been saved in /Users/&amp;lt;USERNAME&amp;gt;/.ssh/id_rsa.pub.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">The key fingerprint is:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SHA256:+pGx7Wcn9WdfRYKJrcdMiKEIPKFRW1lQ1MXP/8i0PLA podman+vagrant
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">The key&lt;span class="err">&amp;#39;&lt;/span>s randomart image is:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">+---&lt;span class="o">[&lt;/span>RSA 4096&lt;span class="o">]&lt;/span>----+
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> ....&lt;span class="o">=&lt;/span>B+. ooo ..&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> . ++. ..+oo.+ &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> o .. o +oo &lt;span class="o">=&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> .o+ &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> S ..&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> . &lt;span class="o">=&lt;/span> . . o&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> . + . B oo&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> . o E X o&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> . .+.&lt;span class="o">=&lt;/span> o.&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">+----&lt;span class="o">[&lt;/span>SHA256&lt;span class="o">]&lt;/span>-----+
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cat /Users/&amp;lt;USERNAME&amp;gt;/.ssh/id_rsa.pub
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ssh-rsa AAAAB3NzaC1y ... &lt;span class="nv">O3JH8w&lt;/span>&lt;span class="o">==&lt;/span> podman+vagrant
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="create-a-vagrant-vm">Create a vagrant VM&lt;/h3>
&lt;p>We will use a Virtual Machine based on &lt;a href="https://getfedora.org/" target="_blank" rel="noopener">Fedora 33&lt;/a>,&lt;/p>
&lt;p>To create the specified Vagrantfile, we need to follow the next steps:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ mkdir my-fedora &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> my-fedora
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Vagrant.configure(&amp;#34;&lt;/span>2&lt;span class="s2">&amp;#34;) do |config|
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> config.vm.box = &amp;#34;&lt;/span>generic/fedora33&lt;span class="s2">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> config.vm.hostname = &amp;#34;&lt;/span>my-fedora&lt;span class="s2">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> config.vm.provider &amp;#34;&lt;/span>virtualbox&lt;span class="s2">&amp;#34; do |v|
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> v.memory = 1024
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> v.cpus = 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> end
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">end&amp;#34;&lt;/span> &amp;gt;&amp;gt; Vagrantfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="implementation">Implementation&lt;/h2>
&lt;p>At this moment we have:&lt;/p>
&lt;ul>
&lt;li>Podman installed&lt;/li>
&lt;li>A ssh-key with no password created&lt;/li>
&lt;li>A VM created with vagrant&lt;/li>
&lt;/ul>
&lt;p>Let&amp;rsquo;s start our implementation&lt;/p>
&lt;h3 id="copy-ssh-key-from-macos-to-linux-vm">Copy ssh-key from MacOS to Linux VM&lt;/h3>
&lt;p>We use the &lt;code>ssh-copy-id&lt;/code> command, and it will ask us for the vagrant user password. The default one is: &lt;strong>vagrant&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ ssh-copy-id -i id_rsa.pub vagrant@127.0.0.1 -p &lt;span class="m">2222&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/usr/bin/ssh-copy-id: INFO: Source of key&lt;span class="o">(&lt;/span>s&lt;span class="o">)&lt;/span> to be installed: &lt;span class="s2">&amp;#34;id_rsa.pub&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key&lt;span class="o">(&lt;/span>s&lt;span class="o">)&lt;/span>, to filter out any that are already installed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/usr/bin/ssh-copy-id: INFO: &lt;span class="m">1&lt;/span> key&lt;span class="o">(&lt;/span>s&lt;span class="o">)&lt;/span> remain to be installed -- &lt;span class="k">if&lt;/span> you are prompted now it is to install the new keys
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vagrant@127.0.0.1&lt;span class="s1">&amp;#39;s password:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">Number of key(s) added: 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">Now try logging into the machine, with: &amp;#34;ssh -p &amp;#39;&lt;/span>2222&lt;span class="s1">&amp;#39; &amp;#39;&lt;/span>vagrant@127.0.0.1&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="s2">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">and check to make sure that only the key(s) you wanted were added.
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can verify connectivity with the command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ ssh vagrant@127.0.0.1 -p &lt;span class="m">2222&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Last login: Tue Feb &lt;span class="m">23&lt;/span> 07:33:45 &lt;span class="m">2021&lt;/span> from 10.0.2.5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>vagrant@my-fedora ~&lt;span class="o">]&lt;/span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="configure-the-linux-vm">Configure the Linux VM&lt;/h3>
&lt;p>On this step we will:&lt;/p>
&lt;ul>
&lt;li>Install the podman package and dependencies&lt;/li>
&lt;li>Enable the podman service&lt;/li>
&lt;li>Enable the sshd service&lt;/li>
&lt;/ul>
&lt;h4 id="installing-podman">Installing podman&lt;/h4>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo dnf --enablerepo&lt;span class="o">=&lt;/span>updates-testing install podman libvarlink-util libvarlink
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;h4 id="enableling-the-podman-service">Enableling the podman service&lt;/h4>
&lt;p>We can enable and start the service permanently, using the following commands:&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ systemctl --user &lt;span class="nb">enable&lt;/span> --now podman
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;p>Also, we will need to enable linger for this user in order for the socket to work when the user is not logged in.&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo loginctl enable-linger &lt;span class="nv">$USER&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;p>You can verify that the socket is listening with a simple Podman command.&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman --remote info
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;h4 id="enableling-the-sshd-service">Enableling the sshd service&lt;/h4>
&lt;p>In order for the client to communicate with the server you need to enable and start the SSH daemon on the Linux VM:&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ sudo systemctl &lt;span class="nb">enable&lt;/span> --now sshd
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;h2 id="using-the-client">Using the client&lt;/h2>
&lt;p>The first step in using the Podman remote client is to configure a &lt;strong>connection&lt;/strong>. To do that, we need can add a connection by using the &lt;code>podman system connection add&lt;/code> command.&lt;/p>
&lt;!-- markdownlint-disable commands-show-output -->
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman system connection add &amp;lt;CONNECTION-NAME&amp;gt; ssh://vagrant@127.0.0.1:2222 --identity &amp;lt;SSH-KEY&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ podman system connection add my-fedora ssh://vagrant@127.0.0.1:2222 --identity ~/.ssh/id_rsa.pub
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- markdownlint-restore -->
&lt;p>We can verify that the connection is in place with the command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman system connection list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Name Identity URI
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">my-fedora* ~/.ssh/id_rsa.pub ssh://vagrant@127.0.0.1:2222/run/user/1000/podman/podman.sock
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now we can test the connection with the command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman info
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">host:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> arch: amd64
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> buildahVersion: 1.18.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> cgroupManager: systemd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> cgroupVersion: v2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> conmon:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> package: conmon-2.0.21-3.fc33.x86_64
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> path: /usr/bin/conmon
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> version: &lt;span class="s1">&amp;#39;conmon version 2.0.21, commit: 0f53fb68333bdead5fe4dc5175703e22cf9882ab&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> cpus: &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> distribution:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> distribution: fedora
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> version: &lt;span class="s2">&amp;#34;33&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> eventLogger: journald
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> hostname: my-fedora
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Also, you can start running podman commands as you run them in docker:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman images
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">REPOSITORY TAG IMAGE ID CREATED SIZE
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="next-steps">Next steps&lt;/h2>
&lt;p>At this point we have installed everything that we need to start using podman on our MacOS, but podman only work if the Linux VM is up &amp;amp; running, otherwise you will receive an error similar to this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ podman images
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Error: Cannot connect to the Podman socket, make sure there is a Podman REST API service running.: failed to create sshClient:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Connection to bastion host &lt;span class="o">(&lt;/span>ssh://vagrant@127.0.0.1:2222/run/user/1000/podman/podman.sock&lt;span class="o">)&lt;/span> failed.: dial tcp 127.0.0.1:2222: connect: connection refused
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To avoid that behavior, what I implement is an automator workflow, here are the steps:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Get the vagrant VM id, to do that run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ vagrant global-status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">id name provider state directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">--------------------------------------------------------------------------
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">894d683 my-fedora virtualbox running ~/vms/my-fedora
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">The above shows information about all known Vagrant environments
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">on this machine. This data is cached and may not be completely
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">up-to-date &lt;span class="o">(&lt;/span>use &lt;span class="s2">&amp;#34;vagrant global-status --prune&amp;#34;&lt;/span> to prune invalid
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">entries&lt;span class="o">)&lt;/span>. To interact with any of the machines, you can go to that
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">directory and run Vagrant, or you can use the ID directly with
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Vagrant commands from any directory. For example:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;vagrant destroy 1a2b3c4d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As you can see we are interested on get the id column, for this example: &lt;strong>894d683&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Now, we need to open &lt;strong>Automator&lt;/strong>, go to &lt;em>Launchpad -&amp;gt; search -&amp;gt; &lt;strong>type&lt;/strong> automator&lt;/em>, do click on the &lt;strong>Automator&lt;/strong> Application&lt;/p>
&lt;figure id="figure-launchpad-automator">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Launchpad &amp;#43; Automator" srcset="
/media/posts/podman-macos-vagrant/launchpad-automator_hub10fc04977027c8a627d4591d43f2044_117882_472f99b504f26e0be7156c95d5e4e80c.webp 400w,
/media/posts/podman-macos-vagrant/launchpad-automator_hub10fc04977027c8a627d4591d43f2044_117882_f96c2f43695360c40f6572355088b89a.webp 760w,
/media/posts/podman-macos-vagrant/launchpad-automator_hub10fc04977027c8a627d4591d43f2044_117882_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/podman-macos-vagrant/launchpad-automator_hub10fc04977027c8a627d4591d43f2044_117882_472f99b504f26e0be7156c95d5e4e80c.webp"
width="760"
height="192"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Launchpad + Automator
&lt;/figcaption>&lt;/figure>
&lt;/li>
&lt;li>
&lt;p>Then, we need to write an automator application, for this example I choose a workflow that it will run the command &lt;code>vagrant up &amp;lt;VM-ID&amp;gt;&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ vagrant up 894d683
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Bringing machine &lt;span class="s1">&amp;#39;my-fedora&amp;#39;&lt;/span> up with &lt;span class="s1">&amp;#39;virtualbox&amp;#39;&lt;/span> provider...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Checking &lt;span class="k">if&lt;/span> box &lt;span class="s1">&amp;#39;generic/fedora33&amp;#39;&lt;/span> version &lt;span class="s1">&amp;#39;3.2.0&amp;#39;&lt;/span> is up to date...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: A newer version of the box &lt;span class="s1">&amp;#39;generic/fedora33&amp;#39;&lt;/span> &lt;span class="k">for&lt;/span> provider &lt;span class="s1">&amp;#39;virtualbox&amp;#39;&lt;/span> &lt;span class="nv">is&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: available! You currently have version &lt;span class="s1">&amp;#39;3.2.0&amp;#39;&lt;/span>. The latest is &lt;span class="nv">version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: &lt;span class="s1">&amp;#39;3.2.6&amp;#39;&lt;/span>. Run &lt;span class="sb">`&lt;/span>vagrant box update&lt;span class="sb">`&lt;/span> to update.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Clearing any previously &lt;span class="nb">set&lt;/span> forwarded ports...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Clearing any previously &lt;span class="nb">set&lt;/span> network interfaces...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Preparing network interfaces based on configuration...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> default: Adapter 1: &lt;span class="nv">nat&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Forwarding ports...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> default: &lt;span class="m">22&lt;/span> &lt;span class="o">(&lt;/span>guest&lt;span class="o">)&lt;/span> &lt;span class="o">=&lt;/span>&amp;gt; &lt;span class="m">2222&lt;/span> &lt;span class="o">(&lt;/span>host&lt;span class="o">)&lt;/span> &lt;span class="o">(&lt;/span>adapter 1&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Running &lt;span class="s1">&amp;#39;pre-boot&amp;#39;&lt;/span> VM customizations...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Booting VM...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Waiting &lt;span class="k">for&lt;/span> machine to boot. This may take a few minutes...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> default: SSH address: 127.0.0.1:2222
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> default: SSH username: vagrant
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> default: SSH auth method: private &lt;span class="nv">key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Machine booted and ready!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Checking &lt;span class="k">for&lt;/span> guest additions in VM...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Setting hostname...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: Machine already provisioned. Run &lt;span class="sb">`&lt;/span>vagrant provision&lt;span class="sb">`&lt;/span> or use the &lt;span class="sb">`&lt;/span>--provision&lt;span class="sb">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">==&lt;/span>&amp;gt; default: flag to force provisioning. Provisioners marked to run always will still run.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;figure id="figure-automator-workflow">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Automator Workflow" srcset="
/media/posts/podman-macos-vagrant/automator-workflow_hu33140a01e2d0efe5b3cf5bd03b1b1e32_62578_671db356fae3c1265815bf2799ad1854.webp 400w,
/media/posts/podman-macos-vagrant/automator-workflow_hu33140a01e2d0efe5b3cf5bd03b1b1e32_62578_e6ac44c59df3f4c80279a56e2b283686.webp 760w,
/media/posts/podman-macos-vagrant/automator-workflow_hu33140a01e2d0efe5b3cf5bd03b1b1e32_62578_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/podman-macos-vagrant/automator-workflow_hu33140a01e2d0efe5b3cf5bd03b1b1e32_62578_671db356fae3c1265815bf2799ad1854.webp"
width="760"
height="656"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Automator Workflow
&lt;/figcaption>&lt;/figure>
&lt;/li>
&lt;li>
&lt;p>Save the Workflow and remember the location where you save it.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The final step is to add the workflow to our &lt;strong>login items&lt;/strong>. Go to &lt;code>Systems Preferences -&amp;gt; Users &amp;amp; Groups -&amp;gt; Login Items&lt;/code> and add the application that you save on the previous step.&lt;/p>
&lt;figure id="figure-login-items">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Login Items Menu" srcset="
/media/posts/podman-macos-vagrant/login-items_hu93dd3ea80c77a356a834b817262b07a9_45716_97e97a0cb8561eab525154b680b6c691.webp 400w,
/media/posts/podman-macos-vagrant/login-items_hu93dd3ea80c77a356a834b817262b07a9_45716_2bd5042113cdd3dca57352115b6c1390.webp 760w,
/media/posts/podman-macos-vagrant/login-items_hu93dd3ea80c77a356a834b817262b07a9_45716_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/podman-macos-vagrant/login-items_hu93dd3ea80c77a356a834b817262b07a9_45716_97e97a0cb8561eab525154b680b6c691.webp"
width="670"
height="418"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Login Items Menu
&lt;/figcaption>&lt;/figure>
&lt;p>And that is all, you will have a fully working podman command on your MacOS.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>References:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Podman MacOS and windows install &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Detailed podman installation on MacOS &lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Automator Configuration &lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/containers/podman/blob/master/docs/tutorials/mac_win_client.md" target="_blank" rel="noopener">Podman Remote clients for macOS and Windows&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://vikaspogu.dev/posts/podman-macos/" target="_blank" rel="noopener">Installing Podman remote client on macOS using vagrant&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://stackoverflow.com/questions/30680861/how-can-i-automatically-do-vagrant-up-every-time-my-osx-machine-boots" target="_blank" rel="noopener">How can I automatically do vagrant up every time my OSX machine boots?&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Backing Up a Ruckus Switch Config</title><link>https://portfolio.devcrumbs.com/backing-up-ruckus-config/</link><pubDate>Sat, 21 Nov 2020 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/backing-up-ruckus-config/</guid><description>&lt;p>I want to do some changes on my home network to improve the performance, so I will implement VLANs on my network.
But before I do that I want to document how to perform a backup of my Ruckus ICX 7150 Switch.&lt;/p>
&lt;p>In a &lt;a href="https://portfolio.devcrumbs.com/configure-ruckus-switch/">past post&lt;/a> I mentioned how to enable ssh and web cofiguration on the Ruckus switch,
so my first attemtp was to download the configuration file from the web interface but unfortunately it is not possible to do it, there is not an option for that.
What I did is go to the &lt;a href="http://docs.ruckuswireless.com/fastiron/hardware/icx7150-installguide/GUID-25306120-376C-44B2-BAE7-3D969EC889A3.html" target="_blank" rel="noopener">documentation&lt;/a>
and found the &lt;code>copy&lt;/code> command but I need a &lt;a href="https://en.wikipedia.org/wiki/Trivial_File_Transfer_Protocol" target="_blank" rel="noopener">TFTP server&lt;/a> to be able to download the backup file.&lt;/p>
&lt;p>Let&amp;rsquo;s start!&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Install a TFTP server - This is easy will depend on your Operative System, for my is an ArchLinux laptop.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">yay -Sy atftp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The configuration file for atftp is &lt;code>/etc/conf.d/atftpd&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Next step, is login on your Ruckus switch and perform the copy command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ssh &amp;lt;USER&amp;gt;@&amp;lt;SWITCH-IP&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">copy running-config tftp &amp;lt;TFTP-SERVER-IP&amp;gt; myconfig.cfg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#In my case is:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ssh ruckus@192.168.50.5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">copy running-config tftp 192.168.50.4 myconfig.cfg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Verify that the file is on your TFTP server, by default, the configured directory for atftp is &lt;code>/srv/atftp/&lt;/code> so you should go that location and verify that the generated file is created.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /srv/atftp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ls -la
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>That&amp;rsquo;s all, you can restore your switch configuration if needed.&lt;/p>
&lt;p>Bye!&lt;/p></description></item><item><title>Using the Ansible Stat Module on a Loop</title><link>https://portfolio.devcrumbs.com/using-the-ansible-stat-module-on-a-loop/</link><pubDate>Sun, 12 Apr 2020 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/using-the-ansible-stat-module-on-a-loop/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#using-the-ansible-stat-module-on-a-loop">Using the Ansible stat module on a loop&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#problem">Problem&lt;/a>&lt;/li>
&lt;li>&lt;a href="#solution">Solution&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="using-the-ansible-stat-module-on-a-loop">Using the Ansible stat module on a loop&lt;/h2>
&lt;p>Hi again, it&amp;rsquo;s been a while since I wrote something on this blog.
This time I was working on a Ansible playbook and I get this:&lt;/p>
&lt;h3 id="problem">Problem&lt;/h3>
&lt;p>I want to verify if a file exists. Depending on the registered output I want to perform some other actions.
On my specific use case, I want to use in in conjunct with the &lt;code>file&lt;/code> module to define the state on my next task.&lt;/p>
&lt;div class="mermaid">graph TD;
A(Stat over file) --> B{Does the file exists?};
B -->|Yes| C[state: file];
B -->|No| D[state: touch];
&lt;/div>
&lt;h3 id="solution">Solution&lt;/h3>
&lt;p>Here is the solution that worked for me, using &lt;code>loops&lt;/code>, &lt;code>loop_control&lt;/code>,and &lt;code>jinja2&lt;/code> filters.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Stat over the files&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">stat&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ my_loop }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">loop&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/etc/cron.allow&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/etc/at.allow&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">loop_control&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">loop_var&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">my_loop&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">register&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">my_stat_var&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Create a file if not exists&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">file&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ item.my_loop }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">owner&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">root&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">group&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">root&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">mode&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">og-rwx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ &amp;#39;file&amp;#39; if item.stat.exists else &amp;#39;touch&amp;#39; }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">loop&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ my_stat_var.results }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Basically, I&amp;rsquo;m using the new &lt;code>loop&lt;/code> &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html" target="_blank" rel="noopener">syntax&lt;/a> to iterate over all the files that I want to check.&lt;/p>
&lt;p>In order to avoid some warnings about the loop using &lt;code>item&lt;/code> I implement the &lt;code>loop_control&lt;/code> and &lt;code>loop_var&lt;/code> syntax to control the loop behavior and on this specific case,
instead of using the word &lt;code>item&lt;/code> I will substitute it with the one that I define as my &lt;code>loop_var&lt;/code> in this case is called &lt;code>my_loop&lt;/code> (Remember this, I will use it on the next task).&lt;/p>
&lt;p>I&amp;rsquo;m registering the result of the stat task on a variable, for this case is &lt;code>my_stat_var&lt;/code>&lt;/p>
&lt;p>Here is an example of the output, when the 2 files &lt;strong>do not exists:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="err">ok:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="err">instance-amazon&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="err">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;my_loop&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;changed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;All items completed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;results&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ansible_loop_var&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;my_loop&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;at_cron_restricted_touch&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/etc/cron.allow&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;changed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;failed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;invocation&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;module_args&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;checksum_algorithm&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;sha1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;follow&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_attributes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_checksum&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_md5&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_mime&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/etc/cron.allow&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;stat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;exists&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ansible_loop_var&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;my_loop&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;at_cron_restricted_touch&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/etc/at.allow&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;changed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;failed&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;invocation&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;module_args&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;checksum_algorithm&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;sha1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;follow&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_attributes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_checksum&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_md5&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;get_mime&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;path&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/etc/at.allow&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;stat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;exists&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>On the next task I access the results of the registered variable &lt;code>my_stat_var&lt;/code> using, according to the previous output,
I need to use the &lt;code>results&lt;/code> variable to access it and gives me 2 arrays (each one for each file)&lt;/p>
&lt;p>Also, I extract the &lt;code>path&lt;/code> from the same variable &lt;code>my_stat_var.results&lt;/code> &lt;strong>but&lt;/strong> as it is part of a loop,
I will access it using &lt;code>item.my_loop&lt;/code> as on the the second task loop I&amp;rsquo;m not using a &lt;code>loop_control&lt;/code>,
also I can access it using &lt;code>item.item&lt;/code> but I prefer the first syntax.
In case you implement a &lt;code>loop_control&lt;/code> on you can access it as &lt;code>my_second_loop.my_loop&lt;/code>&lt;/p>
&lt;p>Also, I extract if the file exists with the variable &lt;code>item.stat.exists&lt;/code> &lt;strong>but&lt;/strong> I&amp;rsquo;m putting that on a &lt;code>jinja2&lt;/code> filter, that way it will evaluate and set the correct option on the &lt;code>state&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># When the file exists&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">file&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># When the file does not exists&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">touch&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This behavior also brings idempotency to your task, because:&lt;/p>
&lt;ul>
&lt;li>If the files does not exists on the first iteration it will be created and,&lt;/li>
&lt;li>The next time you run the tasks as the files already exists it will works as a &lt;code>stat&lt;/code> and will return the current state of &lt;code>path&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>That is all for now. See you soon!&lt;/p></description></item><item><title>Docker Login the Right Way</title><link>https://portfolio.devcrumbs.com/docker-login-the-right-way/</link><pubDate>Wed, 15 May 2019 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/docker-login-the-right-way/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#credential-store">Credential Store&lt;/a>&lt;/li>
&lt;li>&lt;a href="#docker-credential-helpers">Docker Credential Helpers&lt;/a>&lt;/li>
&lt;li>&lt;a href="#docker-credential-secret-service">docker-credential-secret service&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h1 id="docker-login-the-right-way">Docker Login the right Way&lt;/h1>
&lt;p>Hi again!&lt;/p>
&lt;p>It is been a while since I wrote something here, as always, there is no much time for a hobby.&lt;/p>
&lt;p>I&amp;rsquo;ve been working for a while with docker, not a production level, but for some applications that I use at work.
And since the &lt;a href="https://www.zdnet.com/article/docker-hub-hack-exposed-data-of-190000-users/" target="_blank" rel="noopener">Docker Hub Data breach&lt;/a>
I put more atention on the security of my data/credentials, so I investigate a little about and found this official
repository &lt;a href="https://github.com/docker/docker-credential-helpers/" target="_blank" rel="noopener">https://github.com/docker/docker-credential-helpers/&lt;/a> from Docker where are the supported credential helpers.&lt;/p>
&lt;h2 id="credential-store">Credential Store&lt;/h2>
&lt;p>Docker keeps our credentials saved on a JSON file located on &lt;code>~/.docker/config.json&lt;/code>,
but unfortunatelly credentials are just encrypted on base64,
here is an &lt;a href="https://fosdem.org/2019/schedule/event/base64_not_encryption/" target="_blank" rel="noopener">articule/video&lt;/a> where there is an explanation for the why it is a bad idea to just use base64 encryption.&lt;/p>
&lt;p>The following is a diagram on how a plain text storage works:&lt;/p>
&lt;figure id="figure-docker-plain-text-storage">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Plain Text Storage" srcset="
/media/posts/docker-login-the-right-way/DockerPlainTextCredentials_hu371181661409e61f690ceccfb695d5d5_82530_0db582c8916ffc5cd1b1225c42276838.webp 400w,
/media/posts/docker-login-the-right-way/DockerPlainTextCredentials_hu371181661409e61f690ceccfb695d5d5_82530_b27b4b3bd220158c0d85a61a2d4ae88b.webp 760w,
/media/posts/docker-login-the-right-way/DockerPlainTextCredentials_hu371181661409e61f690ceccfb695d5d5_82530_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/docker-login-the-right-way/DockerPlainTextCredentials_hu371181661409e61f690ceccfb695d5d5_82530_0db582c8916ffc5cd1b1225c42276838.webp"
width="760"
height="570"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Plain Text Storage
&lt;/figcaption>&lt;/figure>
&lt;p>Here is an example on how &lt;code>~/.docker/config.json&lt;/code> looks like when is using plain text credentials:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">cat ~/.docker/config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;auths&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://index.docker.io/v1/&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;auth&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;azRjaDA6c3VwZXJzZWNyZXRwYXNzd29yZAo=&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;quay.io&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;auth&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;azRjaDA6c3VwZXJzZWNyZXRwYXNzd29yZAo=&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;HttpHeaders&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;User-Agent&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;Docker-Client/18.09.6 (linux)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After a successful &lt;code>docker login&lt;/code> command,
Docker stores a base64 encoded string from the concatenation of the username, a colon, and the password and associates this string to the registry the user is logging into:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ &lt;span class="nb">echo&lt;/span> &lt;span class="nv">azRjaDA6c3VwZXJzZWNyZXRwYXNzd29yZAo&lt;/span>&lt;span class="o">=&lt;/span> &lt;span class="p">|&lt;/span> base64 -d -
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst:supersecretpassword
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A &lt;code>docker logout&lt;/code> command removes the entry from the JSON file for the given registry:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ docker &lt;span class="nb">logout&lt;/span> quay.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Remove login credentials &lt;span class="k">for&lt;/span> quay.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ cat ~/.docker/config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;auths&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://index.docker.io/v1/&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;auth&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;azRjaDA6c3VwZXJzZWNyZXRwYXNzd29yZAo=&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;HttpHeaders&amp;#34;&lt;/span>: &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;User-Agent&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;Docker-Client/18.09.6 (linux)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="docker-credential-helpers">Docker Credential Helpers&lt;/h2>
&lt;p>Since docker version &lt;code>1.11&lt;/code> implements support from an external credential store for registry authentication.
That means we can use a native keychain of the OS. Using an external store is more secure than storing on a &amp;ldquo;plain text&amp;rdquo; Docker configuration file.&lt;/p>
&lt;figure id="figure-docker-secure-storage">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Secure Storage" srcset="
/media/posts/docker-login-the-right-way/DockerSecureCredentials_huadaed0eecd0771dd576c62f4a77f8685_87803_dfab2c86655b67a2dd7b453f742b7daa.webp 400w,
/media/posts/docker-login-the-right-way/DockerSecureCredentials_huadaed0eecd0771dd576c62f4a77f8685_87803_67d1fdd1b117feb8b3cab43352b4a5be.webp 760w,
/media/posts/docker-login-the-right-way/DockerSecureCredentials_huadaed0eecd0771dd576c62f4a77f8685_87803_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/docker-login-the-right-way/DockerSecureCredentials_huadaed0eecd0771dd576c62f4a77f8685_87803_dfab2c86655b67a2dd7b453f742b7daa.webp"
width="760"
height="543"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Secure Storage
&lt;/figcaption>&lt;/figure>
&lt;p>In order to use a external credential store, we need a program to interact with.&lt;/p>
&lt;p>The actual list of &amp;ldquo;official&amp;rdquo; Docker Credential Helper is:&lt;/p>
&lt;ol>
&lt;li>docker-credential-osxkeychain: Provides a helper to use the OS X keychain as credentials store.&lt;/li>
&lt;li>docker-credential-secretservice: Provides a helper to use the D-Bus secret service as credentials store.&lt;/li>
&lt;li>docker-credential-wincred: Provides a helper to use Windows credentials manager as store.&lt;/li>
&lt;li>docker-credential-pass: Provides a helper to use pass as credentials store.&lt;/li>
&lt;/ol>
&lt;h2 id="docker-credential-secret-service">docker-credential-secret service&lt;/h2>
&lt;p>On this post we will explore the docker-credential-secretservice and how to configure it.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>We need to download and install the helper.
You can find the lastest release on &lt;a href="https://github.com/docker/docker-credential-helpers/releases" target="_blank" rel="noopener">https://github.com/docker/docker-credential-helpers/releases&lt;/a>.
Download it, extract it and make it executable.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">wget https://github.com/docker/docker-credential-helpers/releases/download/v0.6.2/docker-credential-secretservice-v0.6.2-amd64.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tar -xf docker-credential-secretservice-v0.6.2-amd64.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod +x docker-credential-secretservice
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo mv docker-credential-secretservice /usr/local/bin/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Then, we need to specify the credential store in the file &lt;code>~/.docker/config.json&lt;/code> to tell docker to use it.
The value must be the one after the prefix &lt;code>docker-credential-&lt;/code>. In this case:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;credsStore&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;secretservice&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To facilite the configuration and do not make mistakes, you can run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sed -i &lt;span class="s1">&amp;#39;0,/{/s/{/{\n\t&amp;#34;credsStore&amp;#34;: &amp;#34;secretservice&amp;#34;,/&amp;#39;&lt;/span> ~/.docker/config.json
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>From now we are uning an external store, so if you are currently logged in, you must run &lt;code>docker logout&lt;/code> to remove the credentials from the file and run &lt;code>docker login&lt;/code> tostart using the new ones.&lt;/p>
&lt;p>Let me know how this works for you.&lt;/p>
&lt;p>&lt;strong>References:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Docker Credential Helpers repository&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Docker Credential Store Documentation&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Slides about this topic &lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/docker/docker-credential-helpers" target="_blank" rel="noopener">Docker Credential Helpers&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://docs.docker.com/engine/reference/commandline/login/#credentials-store" target="_blank" rel="noopener">docker cli documentation&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://www.slideshare.net/DavidYeung22/can-we-stop-saving-docker-credentials-in-plain-text-now" target="_blank" rel="noopener">Stop saving credential tokens in text files&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Bulk Delete Rackspace Cloud Files data via API</title><link>https://portfolio.devcrumbs.com/bulk-delete-cloud-files-api/</link><pubDate>Wed, 13 Feb 2019 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/bulk-delete-cloud-files-api/</guid><description>&lt;p>Sometimes it is necessary to delete all the content of the Cloud Files containers, however, the API does not have a proper method to delete the data and the containers on the same API call.
Also, accoring to the documentation, you can only delete &lt;strong>empty&lt;/strong> containers.&lt;/p>
&lt;p>So, in cases where you need to delete the &lt;strong>data and the containers&lt;/strong> at the same time, you should follow the next steps:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Download &lt;a href="https://github.com/cloudnull/turbolift" target="_blank" rel="noopener">Turbolift&lt;/a>, I know it is an old tool.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git clone https://github.com/cloudnull/turbolift
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> turbolift
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>In order to get and isolated installation, we are going to create a Python Virtual Environment (virtualenv)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">mkvirtualenv turbolift
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">workon turbolift
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Install the tool&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">pip install turbolift
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Now, prior to start to play with the API calls, we need to grab some data to authenticate with the API:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Variable&lt;/th>
&lt;th>Definition&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>USERNAME&lt;/td>
&lt;td>This is the Rackspace Public Cloud username&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>APIKEY&lt;/td>
&lt;td>This is your API-KEY&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>REGION&lt;/td>
&lt;td>This is the Region where the Cloud Files are located (dfw, ord, iad, lon, hkg)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>TOKEN&lt;/td>
&lt;td>The TOKEN is generated after you get authenticated&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ENDPOINT&lt;/td>
&lt;td>This ENDPOINT is given also after you get authenticated&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;p>Next step, we are going to use &lt;a href="https://curl.haxx.se/" target="_blank" rel="noopener">cURL&lt;/a>, to perform all the API calls:&lt;/p>
&lt;ul>
&lt;li>First of all, get the TOKEN:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">USERNAME&lt;/span>&lt;span class="o">=&lt;/span>YOUR-USERNAME
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">APIKEY&lt;/span>&lt;span class="o">=&lt;/span>YOUR-APIKEY
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">TOKEN&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>curl -s -XPOST https://identity.api.rackspacecloud.com/v2.0/tokens &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d&lt;span class="s1">&amp;#39;{&amp;#34;auth&amp;#34;:{&amp;#34;RAX-KSKEY:apiKeyCredentials&amp;#34;:{&amp;#34;username&amp;#34;:&amp;#34;&amp;#39;&lt;/span>&lt;span class="nv">$USERNAME&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;,&amp;#34;apiKey&amp;#34;:&amp;#34;&amp;#39;&lt;/span>&lt;span class="nv">$APIKEY&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;}}}&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H&lt;span class="s2">&amp;#34;Content-type:application/json&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> jq &lt;span class="s1">&amp;#39;.access.token.id&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> tr -d &lt;span class="s2">&amp;#34;\&amp;#34;&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Next step, get the ENDPOINT:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ENDPOINT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>curl -s -XPOST https://identity.api.rackspacecloud.com/v2.0/tokens &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d&lt;span class="s1">&amp;#39;{&amp;#34;auth&amp;#34;:{&amp;#34;RAX-KSKEY:apiKeyCredentials&amp;#34;:{&amp;#34;username&amp;#34;:&amp;#34;&amp;#39;&lt;/span>&lt;span class="nv">$CL_USERNAME&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;,&amp;#34;apiKey&amp;#34;:&amp;#34;&amp;#39;&lt;/span>&lt;span class="nv">$APIKEY&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;}}}&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H&lt;span class="s2">&amp;#34;Content-type:application/json&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> jq &lt;span class="s1">&amp;#39;.access.serviceCatalog[] | select((.name==&amp;#34;cloudFiles&amp;#34;) or (.name==&amp;#34;cloudFilesCDN&amp;#34;)) | {name} + .
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> endpoints[] | .publicURL&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> tr -d &lt;span class="s2">&amp;#34;\&amp;#34;&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> grep -v cdn &lt;span class="p">|&lt;/span> grep -i &lt;span class="nv">$REGION&lt;/span>&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this case we are skipping all te CDN endpoints, but you can add them if is necessary.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>With all the collected data, next step is use turbolift to delete the Cloud Files container and their data. To do it, I use a for-loop:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> i in &lt;span class="k">$(&lt;/span>curl -s -H &lt;span class="s2">&amp;#34;X-Auth-Token: &lt;/span>&lt;span class="nv">$TOKEN&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="nv">$ENDPOINT&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">do&lt;/span> turbolift -u &lt;span class="nv">$USERNAME&lt;/span> -a &lt;span class="nv">$APIKEY&lt;/span> --os-rax-auth &lt;span class="nv">$REGION&lt;/span> delete -c &lt;span class="nv">$i&lt;/span> &lt;span class="p">;&lt;/span> &lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now, you have all the Data and Cloud Files containers deleted on one region.&lt;/p>
&lt;p>😄&lt;/p></description></item><item><title>Configure SSH on a Ruckus Switch</title><link>https://portfolio.devcrumbs.com/configure-ruckus-switch/</link><pubDate>Tue, 20 Nov 2018 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/configure-ruckus-switch/</guid><description>&lt;p>I just have a Ruckus ICX 7150 Switch on my home and I&amp;rsquo;m trying to get access under ssh and web, to easy configuration and security instead of use telnet.
So, I logged in using telnet and then run the following commands to configure a username/password and begin to receive petitions over port 22(ssh) and port 443(https).
Let&amp;rsquo;s begin!&lt;/p>
&lt;ol>
&lt;li>
&lt;p>We will connect via telnet to the switch.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">telnet SWITCH_IP
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Once we are on the Switch CLI as a optional step, we can configure an IP on the switch.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">device&amp;gt; &lt;span class="nb">enable&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device# configure terminal
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># ip address IP_ADDRESS/CIDR&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># ip default-gateway IP_GATEWAY&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Now, the next steps are for generate a SSL certificate, a username/password, activate password to login and enable thw web access and ssh access.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># crypto-ssl certificate generate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># username USERNAME password PASSWORD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># aaa authentication login default local&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># aaa authentication web-server default local&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>It may take several minutes to generate the certificate key. After that, save the configuration.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">device&lt;span class="o">(&lt;/span>config&lt;span class="o">)&lt;/span>&lt;span class="c1"># write memory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now you are able to login on your switch using ssh or web.&lt;/p>
&lt;p>&lt;strong>References:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Blog with ruckus commands &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://docs.ruckuswireless.com/fastiron/08.0.50/fastiron-08050-commandref/GUID-E60DB55B-5E68-40EC-A999-73C6C071EFF7.html" target="_blank" rel="noopener">Ruckus ICX7150-C12P – Initial Configuration&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Set a hugo blog on Kubernetes</title><link>https://portfolio.devcrumbs.com/blog-hugo-docker-k8s-quay/</link><pubDate>Mon, 18 Jun 2018 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/blog-hugo-docker-k8s-quay/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#overview">Overview&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#architecture">Architecture&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#containerized">Containerized&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#dockerfile">Dockerfile&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>Since last year I been trying to become an SRE (Site Reliability Engineer), so I been involved with some emerging technologies, like ansible, docker and on this time with kubernetes.&lt;/p>
&lt;p>This time, I will try to explain how I containerized my blog using:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.docker.com/" target="_blank" rel="noopener">Docker&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/" target="_blank" rel="noopener">Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://quay.io/" target="_blank" rel="noopener">Quay&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com" target="_blank" rel="noopener">Git&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="architecture">Architecture&lt;/h3>
&lt;p>So, I take some ideas from &lt;a href="https://www.civo.com/learn/using-civo-k3s-service-to-host-your-blog-in-hugo-using-github-actions" target="_blank" rel="noopener">here&lt;/a> and I modify them and adapt the architecture described to my options.&lt;/p>
&lt;p>The principal changes that I made are:&lt;/p>
&lt;ul>
&lt;li>My Kubernetes cluster is running on 2 cloud server on Rackspace Public Cloud&lt;/li>
&lt;li>The container registry that I&amp;rsquo;m using is Quay&lt;/li>
&lt;li>Rackspace Public Cloud does not support a Kubernetes LoadBalancer service automatically,
so I simulate that behavior adding a Cloud Load Balancer manually after the Kubernetes service provide me the port.&lt;/li>
&lt;/ul>
&lt;figure id="figure-blog-hugo-architecture">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Architecture" srcset="
/media/posts/blog-hugo-docker-k8s-quay/architecture_hu8b96b5b52b85b051d387a2869880f3ab_113861_90038fb3c81eb33b4ff587d44167dbfc.webp 400w,
/media/posts/blog-hugo-docker-k8s-quay/architecture_hu8b96b5b52b85b051d387a2869880f3ab_113861_422b03095e3febbbd91dbb98eee4f1ca.webp 760w,
/media/posts/blog-hugo-docker-k8s-quay/architecture_hu8b96b5b52b85b051d387a2869880f3ab_113861_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/blog-hugo-docker-k8s-quay/architecture_hu8b96b5b52b85b051d387a2869880f3ab_113861_90038fb3c81eb33b4ff587d44167dbfc.webp"
width="760"
height="486"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Architecture
&lt;/figcaption>&lt;/figure>
&lt;h2 id="containerized">Containerized&lt;/h2>
&lt;p>I use &lt;a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo&lt;/a> to deploy my blog, I used to do it as mentioned on &lt;a href="https://d-cmst.io/deployment-hugo-site-git-hooks/" target="_blank" rel="noopener">this&lt;/a> previous post (In Spanish).&lt;/p>
&lt;p>Now, as a part of containerize the blog it make sense to me to create two stages as described &lt;a href="https://www.civo.com/learn/using-civo-k3s-service-to-host-your-blog-in-hugo-using-github-actions" target="_blank" rel="noopener">here&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>The first stage is a defined build environment containing all required build tools (hugo, pygments) and the source of the website (Git repository).&lt;/li>
&lt;li>The second stage is the build artifact (HTML and assets), from the first stage and a webserver to serve the artifact over HTTP.&lt;/li>
&lt;/ul>
&lt;h3 id="dockerfile">Dockerfile&lt;/h3>
&lt;p>Here is the Dockerfile that containerize the blog:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">FROM ubuntu:latest as STAGEONE
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># install hugo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ENV &lt;span class="nv">HUGO_VERSION&lt;/span>&lt;span class="o">=&lt;/span>0.41
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ADD https://github.com/gohugoio/hugo/releases/download/v&lt;span class="si">${&lt;/span>&lt;span class="nv">HUGO_VERSION&lt;/span>&lt;span class="si">}&lt;/span>/hugo_&lt;span class="si">${&lt;/span>&lt;span class="nv">HUGO_VERSION&lt;/span>&lt;span class="si">}&lt;/span>_Linux-64bit.tar.gz /tmp/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN tar -xf /tmp/hugo_&lt;span class="si">${&lt;/span>&lt;span class="nv">HUGO_VERSION&lt;/span>&lt;span class="si">}&lt;/span>_Linux-64bit.tar.gz -C /usr/local/bin/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># install syntax highlighting&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN apt-get update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN apt-get install -y python3-pygments
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># build site&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">COPY &lt;span class="nb">source&lt;/span> /source
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN hugo --source&lt;span class="o">=&lt;/span>/source/ --destination&lt;span class="o">=&lt;/span>/public/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">FROM nginx:stable-alpine
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN apk --update add curl bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">RUN rm /etc/nginx/conf.d/default.conf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">COPY modules/nginx.d-cmst.io.conf /etc/nginx/conf.d/d-cmst.io.conf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">COPY --from&lt;span class="o">=&lt;/span>STAGEONE /public/ /usr/share/nginx/html/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">EXPOSE &lt;span class="m">80&lt;/span> &lt;span class="m">443&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">MAINTAINER dcmst &amp;lt;dcmst@gmx.com&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="first-stage">First Stage&lt;/h4>
&lt;ul>
&lt;li>Fetch the lastest Ubuntu image and name as &lt;strong>STAGEONE&lt;/strong>&lt;/li>
&lt;li>Install the last available &lt;strong>hugo&lt;/strong> version from source.&lt;/li>
&lt;li>Install &lt;strong>pygments&lt;/strong> library to use it for highlighting.&lt;/li>
&lt;li>Build the site with &lt;strong>hugo&lt;/strong> and the output is set on &lt;strong>/public&lt;/strong> as a build artifact.&lt;/li>
&lt;/ul>
&lt;h4 id="second-stage">Second Stage&lt;/h4>
&lt;ul>
&lt;li>Fetch the lastest stable nginx alpine image.&lt;/li>
&lt;li>Update the image and install some utilities.&lt;/li>
&lt;li>Delete the &lt;strong>default&lt;/strong> nginx configuration file.&lt;/li>
&lt;li>Copy the configuration files needed from the repository root directory.&lt;/li>
&lt;li>Copy the build artifact &lt;strong>/public&lt;/strong> from the previous stage (&lt;strong>STAGEONE&lt;/strong>)&lt;/li>
&lt;/ul></description></item><item><title>Deployment de un sitio estatico con Hugo y Git Hooks</title><link>https://portfolio.devcrumbs.com/deployment-hugo-site-git-hooks/</link><pubDate>Mon, 05 Mar 2018 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/deployment-hugo-site-git-hooks/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#motivación">Motivación&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#consideraciones">Consideraciones&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#instruciones">Instruciones&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#consideraciones-técnicas">Consideraciones técnicas&lt;/a>&lt;/li>
&lt;li>&lt;a href="#autenticación-mediante-llaves-ssh">Autenticación mediante llaves SSH&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuración-sitio-con-hugo">Configuración sitio con Hugo&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuración-del-repositorio-git-en-el-servidor-de-desarrollo-1ra-parte">Configuración del repositorio Git en el servidor de desarrollo 1ra parte&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuración-del-repositorio-git-en-el-servidor-productivo">Configuración del repositorio Git en el servidor productivo&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuración-del-repositorio-git-en-el-servidor-de-desarrollo-2da-parte">Configuración del repositorio Git en el servidor de desarrollo 2da parte&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="motivación">Motivación&lt;/h2>
&lt;p>Estoy intentando escribir un poco más en mi blog, ya que noté que muchas veces no lo hacia muy a menudo
por que al llegar a la consola de administración de Wordpress, habia que dar bastantes clicks para llegar al menu de &amp;ldquo;Posts&amp;rdquo;,
además de que cada vez que entraba había un plugin diferente que actualizar, y verificar que nada se rompiera con
las nuevas actualizaciónes, en pocas palabras hay que darle bastante mantenimiento a un sitio con Wordpress,
y además de eso había que dedicarse a escribir el post.&lt;/p>
&lt;p>Otra razón por lo que opté hacer el cambio de plataforma, es que al estar tratando de convertirme en DevOps, es necesario,
desde mi punto de vista; tratar automatizar/scriptear la mayoria de tus tareas que realizas día a día, y con &lt;a href="https://gohugo.io/" title="Hugo" target="_blank" rel="noopener">Hugo&lt;/a> considero que se puede realizar este objetivo también.&lt;/p>
&lt;h3 id="consideraciones">Consideraciones&lt;/h3>
&lt;p>Una vez que decidí migrarme de Wordpress, el siguiente paso era decidir a que plataforma mudarme.
De entrada la plataforma que queria probar era un &lt;a href="https://en.wikipedia.org/wiki/Static_web_page" target="_blank" rel="noopener">Static Site Generator&lt;/a>,
aqui otro &lt;a href="https://cloudcannon.com/blog/what-is-a-static-website/" target="_blank" rel="noopener">link&lt;/a> de por que usar un Static Site Generator.&lt;/p>
&lt;p>Partiendo de lo anterior, las opciones que me parecieron interesantes fueron:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://gohugo.io" target="_blank" rel="noopener">Hugo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://jekyllrb.com" target="_blank" rel="noopener">Jekyll&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://octopress.org/" target="_blank" rel="noopener">Octopress&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://hexo.io/" target="_blank" rel="noopener">Hexo&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Cada una de las opciones tiene diferentes caracteristicas, que no vamos a discutir en este post,
sin embargo las carteristicas que me convencieron de usar &lt;a href="https://gohugo.io/" title="Hugo" target="_blank" rel="noopener">Hugo&lt;/a> por encima de las otras alternativas fueron:&lt;/p>
&lt;ul>
&lt;li>Consta solamente de un binario, que comparado con las otras posibilidades hay que instalar todo un ambiente de desarrollo/producción.&lt;/li>
&lt;li>Es bastante rápido.&lt;/li>
&lt;li>Es Multi-plataforma&lt;/li>
&lt;li>Tiene diversos &lt;a href="https://themes.gohugo.io/" target="_blank" rel="noopener">temas&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="instruciones">Instruciones&lt;/h2>
&lt;h3 id="consideraciones-técnicas">Consideraciones técnicas&lt;/h3>
&lt;p>El ambiente consta de:&lt;/p>
&lt;ul>
&lt;li>1 servidor productivo donde esta instalado hugo, git y un servidor web (apache o nginx) , haremos todos los deployments usando el usuario admin, ojo que no es el usuario root.&lt;/li>
&lt;li>1 servidor/equipo de desarrollo, de igual forma que cuenta con hugo y git, en mi caso, es mi computadora personal y mi usuario es d-cmst.&lt;/li>
&lt;li>1 cuenta de &lt;a href="https://github.com" target="_blank" rel="noopener">github.com&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="autenticación-mediante-llaves-ssh">Autenticación mediante llaves SSH&lt;/h3>
&lt;p>El primer paso es realizar el intercambio de llaves SSH entre el equipo de desarrollo y el equipo productivo. Para ello seguimos los siguientes pasos:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Generar la llave SSH, tendrás que contestar algunas preguntas, entre las cuales está si quieres ponerle un password, a lo cual deberas dejarlo en blanco para que no te pida contraseña.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ ssh-keygen
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Copiar la llave SSH hacia el equipo productivo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ ssh-copy-id admin@IP_servidor_productivo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Verificar que te puedas conectar desde tu servidor de desarrollo, con tu usuario al servidor productivo, con el usuario que realizará los deployments.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ ssh admin@162.125.2.30 hostname
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>En este caso, debera de mostrarte el hostname del servidor productivo sin pedirte el password.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="configuración-sitio-con-hugo">Configuración sitio con Hugo&lt;/h3>
&lt;p>El siguiente paso es configurar nuestro ambiente de desarrollo con Hugo y Git.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Para instalar ambos en Ubuntu o derivados debes de ejecutar:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ sudo apt install hugo git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para tener la version más actualizada de hugo puedes seguir los pasos descritos en este &lt;a href="https://gohugo.io/getting-started/installing/" target="_blank" rel="noopener">link&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Vamos a crear un directorio de trabajo para nuestro sitio estatico&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ mkdir ~/sites
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">cd&lt;/span> ~/sites
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Crearemos un nuevo sitio usando el comando hugo&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ hugo new site d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Congratulations! Your new Hugo site is created in /home/d-cmst/sites/d-cmst.io.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Just a few more steps and you&lt;span class="err">&amp;#39;&lt;/span>re ready to go:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.- Download a theme into the same-named folder.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Choose a theme from https://themes.gohugo.io/, or
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> create your own with the &lt;span class="s2">&amp;#34;hugo new theme &amp;lt;THEMENAME&amp;gt;&amp;#34;&lt;/span> command.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">2.- Perhaps you want to add some content. You can add single files
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> with &lt;span class="s2">&amp;#34;hugo new &amp;lt;SECTIONNAME&amp;gt;/&amp;lt;FILENAME&amp;gt;.&amp;lt;FORMAT&amp;gt;&amp;#34;&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">3.- Start the built-in live server via &lt;span class="s2">&amp;#34;hugo server&amp;#34;&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Visit https://gohugo.io/ &lt;span class="k">for&lt;/span> quickstart guide and full documentation.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Cuando termine de correr el comando se podra apreciar los siguientes directorios y archivos&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">cd&lt;/span> d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ ls
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">archetypes config.toml content data layouts static themes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ tree
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── archetypes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│   └── default.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── config.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── content
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── data
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── layouts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── static
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── themes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">6&lt;/span> directories, &lt;span class="m">2&lt;/span> files
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>El siguiente paso es agregar un tema, puedes encontrar uno que te guste en &lt;a href="https://themes.gohugo.io/" target="_blank" rel="noopener">https://themes.gohugo.io/&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Edit your config.toml configuration file&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># and add the new theme.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;theme = &amp;#34;ananke&amp;#34;&amp;#39;&lt;/span> &amp;gt;&amp;gt; config.toml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Como recomendación adicional en este paso, puedes realizar un fork del tema que te guste en github para poder realizar modificaciones y proponer cambios al mismo,
contribuyendo de esa forma a su desarrollo, para hacerlo, sigue los pasos:&lt;/p>
&lt;ol>
&lt;li>Realizar un fork del tema, sigue esta &lt;a href="https://docs.github.com/en/get-started/quickstart/contributing-to-projects" target="_blank" rel="noopener">guia&lt;/a> para hacerlo.&lt;/li>
&lt;li>Al realizar el fork, tendras en tus repositorios de github el tema que quieras, por lo que tendras que ejecutar los mismos comandos del punto anterior,
pero el repositorio del tema apuntara a tu usario en github&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git submodule add https://github.com/dc-mst/gohugo-theme-ananke.git themes/ananke
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Edit your config.toml configuration file&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># and add the new theme.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;theme = &amp;#34;ananke&amp;#34;&amp;#39;&lt;/span> &amp;gt;&amp;gt; config.toml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Vamos a crear un post de prueba para verificar que todo esta funcionando correctamente&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">hugo new posts/my-first-post.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Hola Mundo&amp;#34;&lt;/span> &amp;gt;&amp;gt; content/posts/my-first-post.md
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>El comando anterior creara un archivo en la ruta content/posts/my-first-post.md, y el contenido será:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;My First Post&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">date&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="ld">2018-02-28T12:02:38&lt;/span>&lt;span class="m">-06&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="m">00&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">draft&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">Hola Mundo!!!&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Finalmente, probaremos que nuestro sitio estatico con nuestro post se muestren de manera local, en nuestro servidor de desarrollo.
Cabe mencionar, que por defecto el comando &amp;lsquo;hugo server&amp;rsquo; no mostrará los posts que tengan la opción &amp;lsquo;draft: true&amp;rsquo;, por ello se agrega la bandera -D&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ hugo server -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h3 id="configuración-del-repositorio-git-en-el-servidor-de-desarrollo-1ra-parte">Configuración del repositorio Git en el servidor de desarrollo 1ra parte&lt;/h3>
&lt;p>En el paso pasado, realizamos la inicialización del repositorio dentro del directorio del sitio estatico:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">pwd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/home/d-cmst/sites/d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">On branch master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initial commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to be committed:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>use &lt;span class="s2">&amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34;&lt;/span> to unstage&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new file: .gitmodules
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new file: themes/ananke
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Untracked files:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>use &lt;span class="s2">&amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34;&lt;/span> to include in what will be committed&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> archetypes/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> config.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> content/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> themes/ananke/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ahora, para tener el repositorio publico, tenemos que &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository" target="_blank" rel="noopener">crear&lt;/a> el repositorio
en &lt;a href="https://github.com" target="_blank" rel="noopener">github.com&lt;/a> y configurarlo como un repositorio remoto&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git add *
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git commit -m &lt;span class="s2">&amp;#34;First commit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git remote add origin https://github.com/dc-mst/d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git push -u origin master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="configuración-del-repositorio-git-en-el-servidor-productivo">Configuración del repositorio Git en el servidor productivo&lt;/h3>
&lt;p>Para poder ocupar los hooks de git es necesario hacer una primera copia inicial del repositorio en el que vamos a trabajar, con la particularidad de que el repositorio clonado debe ser del tipo &lt;a href="http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/" target="_blank" rel="noopener">bare&lt;/a>.&lt;/p>
&lt;p>En nuestro servidor productivo haremos:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ mkdir sites
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ &lt;span class="nb">cd&lt;/span> sites
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ git clone --bare https://github.com/dc-mst/d-cmst.io d-cmst.io.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="configuración-del-hook">Configuración del hook&lt;/h4>
&lt;ol>
&lt;li>
&lt;p>Ya que tenemos nuestro repositorio tipo bare en el servidor productivo vamos a crear el script que mandará a llamar el hook de git.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ &lt;span class="nb">cd&lt;/span> sites/d-cmst.io.git/hooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ vim post-update
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Y agregamos algo asi:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">GIT_REPO&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$HOME&lt;/span>/d-cmst.io.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">WORKING_DIRECTORY&lt;/span>&lt;span class="o">=&lt;/span>/var/www/vhosts/d-cmst.io/working_hugo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">PUBLIC_WWW&lt;/span>&lt;span class="o">=&lt;/span>/var/www/vhosts/d-cmst.io/public_html
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">BACKUP_WWW&lt;/span>&lt;span class="o">=&lt;/span>/var/www/vhosts/d-cmst.io/backup_html
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">MY_DOMAIN&lt;/span>&lt;span class="o">=&lt;/span>d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -e
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf &lt;span class="nv">$WORKING_DIRECTORY&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rsync -aqz &lt;span class="nv">$PUBLIC_WWW&lt;/span>/ &lt;span class="nv">$BACKUP_WWW&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">trap&lt;/span> &lt;span class="s2">&amp;#34;echo &amp;#39;A problem occurred. Reverting to backup.&amp;#39;; rsync -aqz --del &lt;/span>&lt;span class="nv">$BACKUP_WWW&lt;/span>&lt;span class="s2">/ &lt;/span>&lt;span class="nv">$PUBLIC_WWW&lt;/span>&lt;span class="s2">; rm -rf &lt;/span>&lt;span class="nv">$WORKING_DIRECTORY&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> EXIT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone &lt;span class="nv">$GIT_REPO&lt;/span> &lt;span class="nv">$WORKING_DIRECTORY&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir -p &lt;span class="nv">$WORKING_DIRECTORY&lt;/span>/themes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf &lt;span class="nv">$PUBLIC_WWW&lt;/span>/*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/home/admin/bin/hugo -v -s &lt;span class="nv">$WORKING_DIRECTORY&lt;/span> -d &lt;span class="nv">$PUBLIC_WWW&lt;/span> -b &lt;span class="s2">&amp;#34;http://&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nv">MY_DOMAIN&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">trap&lt;/span> - EXIT
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Damos permisos de ejecución al script&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ chmod +x post-update
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Probamos que nuestro script funcione adecuadamente:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">admin@prod-server:~$ ~/sites/d-cmst.io.git/hooks/post-update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Cloning into &lt;span class="s1">&amp;#39;/var/www/vhosts/d-cmst.io/working_hugo&amp;#39;&lt;/span>...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">0&lt;/span> draft content
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">0&lt;/span> future content
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">4&lt;/span> pages created
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">0&lt;/span> paginator pages created
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">0&lt;/span> tags created
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">1&lt;/span> categories created
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">in &lt;span class="m">26&lt;/span> ms
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Podras verificar tu nuevo post en la URL de su sitio:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">http://production_domain_or_IP
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h3 id="configuración-del-repositorio-git-en-el-servidor-de-desarrollo-2da-parte">Configuración del repositorio Git en el servidor de desarrollo 2da parte&lt;/h3>
&lt;p>Una vez tenemos configurado nuestro repositorio en el servidor de producción, procedemos a agregarlo como repositorio remoto en nuestro servidor de desarrollo&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">cd&lt;/span> /home/d-cmst/sites/d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git remote add prod admin@IP_servidor_productivo:d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git ls-remote prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d1b0b73528ab3117170ef74e133d0194dd2bc88a HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d1b0b73528ab3117170ef74e133d0194dd2bc88a refs/heads/master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Puedes verificar los repositorios remotos con el comando:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git remote -v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">origin git@github.com:d-cmst/d-cmst.io.git &lt;span class="o">(&lt;/span>fetch&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">origin git@github.com:d-cmst/d-cmst.io.git &lt;span class="o">(&lt;/span>push&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">prod admin@IP_servidor_productivo:d-cmst.io.git &lt;span class="o">(&lt;/span>fetch&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">prod admin@IP_servidor_productivo:d-cmst.io.git &lt;span class="o">(&lt;/span>push&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ahora cada vez que realizemos un push hacia el remote llamado &amp;lsquo;prod&amp;rsquo; se llamara la función del hook.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">cd&lt;/span> /home/d-cmst/sites/d-cmst.io
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ hugo new posts/Testing-Deployment.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Deployment Test&amp;#34;&lt;/span> &amp;gt;&amp;gt; content/posts/Testing-Deployment.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git add *
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git commit -m &lt;span class="s1">&amp;#39;Deployment test with git hooks&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Este es el comando que hace la magia:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">d-cmst@dev-server:~$ git push prod master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Counting objects: 3, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Delta compression using up to &lt;span class="m">8&lt;/span> threads.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Compressing objects: 100% &lt;span class="o">(&lt;/span>3/3&lt;span class="o">)&lt;/span>, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Writing objects: 100% &lt;span class="o">(&lt;/span>3/3&lt;span class="o">)&lt;/span>, &lt;span class="m">310&lt;/span> bytes &lt;span class="p">|&lt;/span> &lt;span class="m">0&lt;/span> bytes/s, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Total &lt;span class="m">3&lt;/span> &lt;span class="o">(&lt;/span>delta 2&lt;span class="o">)&lt;/span>, reused &lt;span class="m">0&lt;/span> &lt;span class="o">(&lt;/span>delta 0&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Cloning into &lt;span class="s1">&amp;#39;/var/www/vhosts/d-cmst.io/working_hugo&amp;#39;&lt;/span>...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Cloning into &lt;span class="s1">&amp;#39;/var/www/vhosts/d-cmst.io/working_hugo/themes/hugo-future-imperfect&amp;#39;&lt;/span>...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: INFO 2018/03/01 03:12:34 Using config file: /var/www/vhosts/d-cmst.io/working_hugo/config.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Building sites … INFO 2018/03/01 03:12:34 syncing static files to /var/www/vhosts/d-cmst.io/public_html/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: &lt;span class="p">|&lt;/span> EN
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: +------------------+----+
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Pages &lt;span class="p">|&lt;/span> &lt;span class="m">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Paginator pages &lt;span class="p">|&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Non-page files &lt;span class="p">|&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Static files &lt;span class="p">|&lt;/span> &lt;span class="m">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Processed images &lt;span class="p">|&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Aliases &lt;span class="p">|&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Sitemaps &lt;span class="p">|&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Cleaned &lt;span class="p">|&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Total in &lt;span class="m">44&lt;/span> ms
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">To admin@IP_servidor_productivo:d-cmst.io.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> d5b0671..cvc4dee master -&amp;gt; master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Listo ya podemos probar nuestro sitio&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">http://d-cmst.io
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Con esto el siguiente paso que realizare es hacer el deployment de mi servidor para el blog usando Ansible.&lt;/p>
&lt;p>Nos Vemos!!!&lt;/p>
&lt;p>&lt;strong>References:&lt;/strong>
Digital Ocean blog post &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-hugo-site-to-production-with-git-hooks-on-ubuntu-14-04" target="_blank" rel="noopener">Digital Ocean&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Improve WD MyCloud performance</title><link>https://portfolio.devcrumbs.com/improve-wd-mycloud-performance/</link><pubDate>Fri, 16 Feb 2018 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/improve-wd-mycloud-performance/</guid><description>&lt;p>I&amp;rsquo;ve just noticed that my NAS a &lt;a href="https://www.westerndigital.com/products/network-attached-storage/wd-my-cloud-expert-series-ex2-ultra#WDBVBZ0040JCH-NESN" target="_blank" rel="noopener">Western Digital My Cloud EX2&lt;/a> is going slower,
so I decided to investigate about what can I do to improve its performance.&lt;/p>
&lt;p>I assume that you already configure ssh on your NAS device.
If is not configured you can follow the next instructions: &lt;a href="https://support-en.wd.com/app/answers/detailweb/a_id/12861" target="_blank" rel="noopener">https://support-en.wd.com/app/answers/detailweb/a_id/12861&lt;/a>&lt;/p>
&lt;h2 id="stop-indexing-services">Stop Indexing Services&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">/etc/init.d/wdmcserver stop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/etc/init.d/wdphotodbmerger stop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To do it forever, you should create the cronjob as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">crontab -e
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And add the following lines:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">@reboot /bin/sh /etc/init.d/wdmcserverd stop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">@reboot /bin/sh /etc/init.d/wdphotodbmerger stop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>References:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Western Digital knowledge base link&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://support-en.wd.com/app/answers/detailweb/a_id/12861" target="_blank" rel="noopener">How to enable SSH (Secure Shell) on a My Cloud EX2 device&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>OSI Model Cheat Sheet</title><link>https://portfolio.devcrumbs.com/osi-model-cheat-sheet/</link><pubDate>Wed, 13 Sep 2017 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/osi-model-cheat-sheet/</guid><description>&lt;p>If anyone need a good OSI Model cheat sheet, as me:&lt;/p>
&lt;figure id="figure-osi-model">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="OSI Model diagram" srcset="
/media/posts/osi-model-cheat-sheet/OSI-TCP-Model-v1_hu87e76766e3a8bb40ab6e0b3e53b2ee47_128999_6e7b24321fac5f8194d5d723c62d5878.webp 400w,
/media/posts/osi-model-cheat-sheet/OSI-TCP-Model-v1_hu87e76766e3a8bb40ab6e0b3e53b2ee47_128999_79bc635f9cd536c552dd2458163f92b5.webp 760w,
/media/posts/osi-model-cheat-sheet/OSI-TCP-Model-v1_hu87e76766e3a8bb40ab6e0b3e53b2ee47_128999_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/osi-model-cheat-sheet/OSI-TCP-Model-v1_hu87e76766e3a8bb40ab6e0b3e53b2ee47_128999_6e7b24321fac5f8194d5d723c62d5878.webp"
width="760"
height="525"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
OSI Model diagram
&lt;/figcaption>&lt;/figure></description></item><item><title>WordPress with Let's Encrypt SSL Certificate on a Load Balancer</title><link>https://portfolio.devcrumbs.com/wordpress-lets-encrypt-ssl-certificate-load-balancer/</link><pubDate>Sun, 03 Sep 2017 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/wordpress-lets-encrypt-ssl-certificate-load-balancer/</guid><description>&lt;p>Hi again,&lt;/p>
&lt;p>As many of you know a lot of &amp;ldquo;Production&amp;rdquo; applications need to be configured to provide High Availability.
With that in mind, a best practice architecture to your application is to add a Load Balancer as a front end who distribute your traffic between your application nodes,
as you can appreciate on the next image:&lt;/p>
&lt;figure id="figure-ha-load-balancer">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="HA Load Balancer diagram" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/LoadBalancerHA_huebbf17380e8f6fabe11a80fc093dace1_79250_35d1701724397631ee8d755949b6ae4b.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/LoadBalancerHA_huebbf17380e8f6fabe11a80fc093dace1_79250_5dad269015cb44aa479976dd0b5659d2.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/LoadBalancerHA_huebbf17380e8f6fabe11a80fc093dace1_79250_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/LoadBalancerHA_huebbf17380e8f6fabe11a80fc093dace1_79250_35d1701724397631ee8d755949b6ae4b.webp"
width="760"
height="662"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
HA Load Balancer diagram
&lt;/figcaption>&lt;/figure>
&lt;h2 id="ssl-offloading">SSL Offloading&lt;/h2>
&lt;p>In this case, my &amp;ldquo;Production&amp;rdquo; application is my blog, and I will install a SSL Certificate on the Cloud Load Balancer(CLB)
to offloading the encryption/decryption to the CLB instead of doing it on the webserver.
That way your webservers uses port 80 (HTTP), as always, and you serve your content trought port 443(HTTPS).&lt;/p>
&lt;figure id="figure-ssl-offloading">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="SSL-Offloading diagram" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/SSL-Offloading_hu8f744432393ec982cce29c1ca941e414_24258_ff5647092c335f508c65542f46c4bdb0.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/SSL-Offloading_hu8f744432393ec982cce29c1ca941e414_24258_b3cb8a94ae9c78f78469d7a1fe4e5f56.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/SSL-Offloading_hu8f744432393ec982cce29c1ca941e414_24258_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/SSL-Offloading_hu8f744432393ec982cce29c1ca941e414_24258_ff5647092c335f508c65542f46c4bdb0.webp"
width="760"
height="238"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
SSL-Offloading diagram
&lt;/figcaption>&lt;/figure>
&lt;p>Here are the what I use to configure my WordPress with SSL Certificate:&lt;/p>
&lt;ul>
&lt;li>SSL Certificate issued using Let&amp;rsquo;s Encrypt&lt;/li>
&lt;li>A Client of Let&amp;rsquo;s Encrypt called acme&lt;/li>
&lt;li>A Cloud Load Balancer&lt;/li>
&lt;li>A WordPress installation&lt;/li>
&lt;/ul>
&lt;h3 id="step-1-install-acmesh-client">Step 1: Install acme.sh client&lt;/h3>
&lt;p>There is a lot of &lt;a href="https://letsencrypt.org/docs/client-options/" target="_blank" rel="noopener">ACME clients&lt;/a> supported by Let&amp;rsquo;s Encrypt, the most popular is &lt;a href="https://certbot.eff.org" target="_blank" rel="noopener">Certbot.&lt;/a> However, I prefer to use &lt;a href="https://github.com/Neilpang/acme.sh" target="_blank" rel="noopener">acme.sh&lt;/a>.&lt;/p>
&lt;p>Let&amp;rsquo;s install it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git clone https://github.com/Neilpang/acme.sh.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> acme.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Create a data home directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo mkdir -p /opt/acme/data
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Actual command to install it&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">bash acme.sh --install --home /opt/acme --config-home /opt/acme/data --certhome /opt/acme/data/ssl-certs --accountemail your@email.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="step-2-issue-ssl-certificate">Step 2: Issue SSL Certificate&lt;/h3>
&lt;p>Once acme.sh is installed, we proceed to issue our first SSL Certificate:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">/opt/acme/acme.sh --issue -d example.com -w /var/www/vhosts/example.com/public_html
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> Creating domain key
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> The domain key is here: /opt/acme/data/ssl-certs/example.com/example.com.key
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> Single &lt;span class="nv">domain&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;example.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> Getting domain auth token &lt;span class="k">for&lt;/span> each domain
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> Getting webroot &lt;span class="k">for&lt;/span> &lt;span class="nv">domain&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;example.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:07 UTC 2017&lt;span class="o">]&lt;/span> Getting new-authz &lt;span class="k">for&lt;/span> &lt;span class="nv">domain&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;example.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:08 UTC 2017&lt;span class="o">]&lt;/span> The new-authz request is ok.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:08 UTC 2017&lt;span class="o">]&lt;/span> Verifying:example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> Success
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> Verify finished, start to sign.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> Cert success.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-----BEGIN CERTIFICATE-----
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">MIIE/zCCA+egAwIBAgISA2AIs/G8gWjkRkNOUb7zmqh1MA0GCSqGSIb3DQEBCwUA
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA4MjgwNTA0MDBaFw0x
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">NzExMjYwNTA0MDBaMBkxFzAVBgNVBAMTDmNvb2tpZWxhYnMubmV0MIIBIjANBgkq
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8/4fXH0dOHcSlyXpsBoULhwQYkz4m0J
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">MegRHU2mhyy/jfKWM6KHDxHpFWUFajLJ/ORE4uncvjmRYeSVBxgv2R2cYoZyKd6v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">txT+Cdj3jD9fBfDerfdfsdfsd6Y6mlr6Im61afKsFXIgLsprBpK22JU6HOz+0Fdo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">lan09aaF8zLPtVzdfJw9MU55K7nzerxO8j4ro2lve0PHExkMIBCrXey50wcuqQRY
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hwkbbXsm+wTES7TCn3tooSzFq6ore3JrSckxhFQ96EOea0s9CgYnw4d9rU/b3jyK
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">bFCILEJK64vgFHx0qvd0hBJFJG/HUtAXAVrFQjjlZlCmCMbnee1UTQIDAQABo4IC
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">DjCCAgowDgYDVR0pasoasoasogWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBR2KRpXKKgTorwfXpo44wgKyFUl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">QzAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRj
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">MGEwLgYIKwYBBQUHMAASdTdddHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmcvMBkGA1UdEQQSMBCCDmNvb2tpZWxhYnMubmV0MIH+BgNVHSAEgfYwgfMwCAYG
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Z4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nw
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Y2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">YW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Y3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8w
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">DQYJKoZIhvcNAQELBQADggEBAFVGs82tzyVER6U0x7p/Q+6xplDFd6ap/dVX9G6i
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">eRPf4ayGykPSH9J3ewu398LOQd3DE93oWbqc7PfEC40Z5HqvCEY3fl9auep99/IF
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rwhf36J7PXvEsPrUB6pxNFSBw9WX366Z1MP8qoIzm3XYEpp2D/SPniWY5+eQ42Pj
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">WNxxVksA4kFUF9wgKcrsCNTm0X8GZj5HUXC1OwtlopY2w42QrAMGwz1jM4nxv5Mc
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Jim+nT0zmJUhAdQi8ocDjAl2PvcfdgfmkMr9IWH3al/GJSKy3a9Cq+BaIsIUYi6E
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">8M8Mj+00ONNn1folm9aVn+FW5fVCaxYN32ir8PnoTWkOXK8&lt;span class="o">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-----END CERTIFICATE-----
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> Your cert is in /opt/acme/data/ssl-certs/example.com/example.com.cer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> Your cert key is in /opt/acme/data/ssl-certs/example.com/example.com.key
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> The intermediate CA cert is in /opt/acme/data/ssl-certs/example.com/ca.cer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>Mon Aug &lt;span class="m">25&lt;/span> 06:04:11 UTC 2017&lt;span class="o">]&lt;/span> And the full chain certs is there: /opt/acme/data/ssl-certs/example.com/fullchain.cer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Where the explained options are:&lt;/p>
&lt;p>-issue: Issue a new certificate&lt;/p>
&lt;p>-d (-domain) : Specifies a domain, used to issue, renew or revoke, etc.&lt;/p>
&lt;p>-w (-webroot) : Specifies the web root folder for web root mode. This is the DocumentRoot where your site is hosted and it is necessary to verify it by Let&amp;rsquo;s Encrypt.&lt;/p>
&lt;h3 id="step-3-install-ssl-certificate-on-cloud-load-balancer">Step 3: Install SSL Certificate on Cloud Load Balancer&lt;/h3>
&lt;p>So, at this moment we have our SSL Certificate, Private Key, and Intermediate CA Certificate ready to install on our Cloud Load Balancer (CLB)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">Your cert is in /opt/acme/data/ssl-certs/example.com/example.com.cer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your cert key is in /opt/acme/data/ssl-certs/example.com/example.com.key
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">The intermediate CA cert is in /opt/acme/data/ssl-certs/example.com/ca.cer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So we should go to &lt;a href="https://login.rackspace.com" target="_blank" rel="noopener">https://login.rackspace.com&lt;/a> -&amp;gt; Rackspace Cloud -&amp;gt; Networking -&amp;gt; Cloud Load Balancers:&lt;/p>
&lt;figure id="figure-clb-01">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace Portal - Cloud Loud Balancer" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB01_hu0c51bf85f3cc4b2d02a66a66d81aa589_40856_54a3e1d860e47c88df6fb2b14ba443b0.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB01_hu0c51bf85f3cc4b2d02a66a66d81aa589_40856_f218066512ada5e455967f465b00b323.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB01_hu0c51bf85f3cc4b2d02a66a66d81aa589_40856_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB01_hu0c51bf85f3cc4b2d02a66a66d81aa589_40856_54a3e1d860e47c88df6fb2b14ba443b0.webp"
width="760"
height="242"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace Portal - Cloud Loud Balancer
&lt;/figcaption>&lt;/figure>
&lt;p>Then, to Optional Features and Enable/Configure on &amp;ldquo;Secure Traffic SSL&amp;rdquo;&lt;/p>
&lt;figure id="figure-clb-02">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace Portal - Cloud Loud Balancer" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB02_hu7ffc5949d0d179fc2236bf5a390f623a_11064_a2285930ece3ab5f674dbcdacb01b0a4.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB02_hu7ffc5949d0d179fc2236bf5a390f623a_11064_f1299d84830e0d3fafe67ea941e04cae.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB02_hu7ffc5949d0d179fc2236bf5a390f623a_11064_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB02_hu7ffc5949d0d179fc2236bf5a390f623a_11064_a2285930ece3ab5f674dbcdacb01b0a4.webp"
width="732"
height="356"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace Portal - Cloud Loud Balancer
&lt;/figcaption>&lt;/figure>
&lt;p>Finally, we add our SSL Certificate, Private Key, and Intermediate CA Certificate to the CLB and save the configuration:&lt;/p>
&lt;figure id="figure-clb-03">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace Portal - Cloud Loud Balancer" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB03_hu67fb6ffec3d9916d394540c9ded24748_14067_5e34a2dc24277d867dd5c175629aa89a.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB03_hu67fb6ffec3d9916d394540c9ded24748_14067_c6786992a49821398553ae41e9200fb7.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB03_hu67fb6ffec3d9916d394540c9ded24748_14067_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/CLB03_hu67fb6ffec3d9916d394540c9ded24748_14067_5e34a2dc24277d867dd5c175629aa89a.webp"
width="534"
height="573"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace Portal - Cloud Loud Balancer
&lt;/figcaption>&lt;/figure>
&lt;h3 id="step-4-configure-wordpress">Step 4: Configure WordPress&lt;/h3>
&lt;p>We are almost done, at this time we already have configured our SSL on the CLB to provide WordPress over HTTPS, however, WordPress is still with HTTP, so we need to reconfigure our WordPress with SSL.&lt;/p>
&lt;h4 id="database-queries">Database queries&lt;/h4>
&lt;p>First of all, we should update the links from http to https; we are going to do it directly on the database doing the following queries:&lt;/p>
&lt;div class="alert alert-warning">
&lt;div>
Change all instances of &lt;code>example.com&lt;/code> to your own. If you have the &lt;code>www&lt;/code> as part of your WordPress Address(URL) in the WordPress Settings, add the &amp;lsquo;www&amp;rsquo;.
&lt;/div>
&lt;/div>
&lt;p>Also, if you have a custom table prefix in the WordPress database, something other than the default &amp;lsquo;wp_&amp;rsquo;, then you must change all the instances of &amp;lsquo;wp_&amp;rsquo; to your own table prefix.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Update any embedded attachments/img that use http:This one updates the src attributes that use double quotes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_posts&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;src=\&amp;#34;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;src=\&amp;#34;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%src=\&amp;#34;http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This one takes care of any src attributes that use single quotes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_posts&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;src=\&amp;#39;&lt;/span>&lt;span class="n">http&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="n">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="s1">&amp;#39;, \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="n">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%src=\&amp;#39;&lt;/span>&lt;span class="n">http&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="n">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="s1">&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Update any hard-coded URLs for links.This one updates the URL for href attributes that use double quotes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_posts&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;href=\&amp;#34;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;href=\&amp;#34;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%href=\&amp;#34;http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This one updates the URL for href attributes that use single quotes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_posts&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;href=\&amp;#39;&lt;/span>&lt;span class="n">http&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="n">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="s1">&amp;#39;, \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">post_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%href=\&amp;#39;&lt;/span>&lt;span class="n">http&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="n">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="s1">&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Update any &amp;ldquo;pinged&amp;rdquo; links:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_posts&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pinged&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pinged&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pinged&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>This step is just a confirmation step to make sure that there are no remaining http URLs for your site in the wp_posts table, except the GUID URLs.&lt;/p>
&lt;p>You must replace WP_DB_NAME, near the beginning of the query, with the name of your database.&lt;/p>
&lt;p>This will confirm that nowhere in the wp_posts table is there a remaining http URL, outside of the GUID column. This ignores URLs in the GUID column.&lt;/p>
&lt;p>This query only searches; it does not replace anything, nor make any changes. So, this is safe to run. It’s a safe and quick way to check the wp_posts table while ignoring the guid column.&lt;/p>
&lt;p>This SQL query should return an empty set. That would mean that it found no http URLs for your site. (This is all just 1 query. It’s 1 very,
very long line.)&lt;/p>
&lt;/li>
&lt;/ol>
&lt;div class="alert alert-warning">
&lt;div>
&lt;pre>&lt;code>Remember to replace WP_DB_NAME, near the beginning of the query, with the name of your database.
&lt;/code>&lt;/pre>
&lt;/div>
&lt;/div>
&lt;pre>&lt;code>```sql
SELECT * FROM `WP_DB_NAME`.`wp_posts` WHERE (CONVERT(`ID` USING utf8) LIKE \
'%%http://example.com%%' OR CONVERT(`post_author` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_date` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_date_gmt` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_content` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_title` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_excerpt` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_status` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`comment_status` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`ping_status` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_password` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_name` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`to_ping` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`pinged` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_modified` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_modified_gmt` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_content_filtered` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_parent` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`menu_order` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_type` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`post_mime_type` USING utf8) LIKE '%%http://example.com%%' \
OR CONVERT(`comment_count` USING utf8) LIKE '%%http://example.com%%');
```
&lt;/code>&lt;/pre>
&lt;ol>
&lt;li>
&lt;p>Now, we move to the wp_comments table. This changes any comment author URLs that point to the http version of your site.
This is in case you&amp;rsquo;ve ever replied to a comment while your URL was pointing to http.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_comments&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">comment_author_url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">comment_author_url&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">comment_author_url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>This updates the content of the comments on your site. If there are any links in the comments that are linking to an http URL on your site, they will be updated to https.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_comments&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">comment_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">comment_content&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">comment_content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Now we move to the wp_postmeta table. This takes care of any custom post meta that points to the http version of your site.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_postmeta&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">meta_value&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">meta_value&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;http://example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">meta_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LIKE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;%http://example.com%&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Now we move to the wp_options table. Update the &lt;strong>WordPress Address (URL)&lt;/strong> and &lt;strong>Site Address (URL)&lt;/strong>.&lt;/p>
&lt;p>For the WordPress Address URL, you may have to modify example.com.
If you have WordPress installed in some other directory, then modify this according to your own WordPress URL.
For example, some people have WordPress installed in a subdirectory named &amp;ldquo;blog&amp;rdquo;, and so their WordPress Address would be &lt;a href="https://example.com/blog" target="_blank" rel="noopener">https://example.com/blog&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_options&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">option_value&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://example.com&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_options&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">option_name&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;siteurl&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This one will update the Site Address URL (this is the home page of your site):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">UPDATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_options&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">option_value&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://example.com&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">wp_options&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">option_name&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;home&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h4 id="wordpress-control-panel">WordPress Control Panel&lt;/h4>
&lt;p>Besides, with run the queries directly on the database, we can update, or verify, the blog URLs, by going to Settings &amp;gt; General&lt;/p>
&lt;p>And updating your WordPress Address (URL) and Site Address (URL) address fields.&lt;/p>
&lt;figure id="figure-wp-change-url">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="WordPress - Change URL" srcset="
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/WP-ChangeURL_hu6e2977f116eeda53ba50094ce74f270b_11971_cd086c622daa44e7dfc8388d6c27f831.webp 400w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/WP-ChangeURL_hu6e2977f116eeda53ba50094ce74f270b_11971_a1cee76f695748cc9b27d52f28e41672.webp 760w,
/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/WP-ChangeURL_hu6e2977f116eeda53ba50094ce74f270b_11971_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/wordpress-lets-encrypt-ssl-certificate-load-balancer/WP-ChangeURL_hu6e2977f116eeda53ba50094ce74f270b_11971_cd086c622daa44e7dfc8388d6c27f831.webp"
width="760"
height="262"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
WordPress - Change URL
&lt;/figcaption>&lt;/figure>
&lt;h4 id="wordpress-config-file">WordPress Config File&lt;/h4>
&lt;p>Finally, we should add the following line to our &lt;strong>wp_config.php&lt;/strong> file&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$_SERVER&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s1">&amp;#39;HTTPS&amp;#39;&lt;/span>&lt;span class="o">]=&lt;/span>&lt;span class="s1">&amp;#39;on&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, you have configured WordPress with Let&amp;rsquo;s Encrypt SSL Certificate on a Load Balancer.&lt;/p></description></item><item><title> Build a Dynamic DNS Client with Rackspace API</title><link>https://portfolio.devcrumbs.com/build-a-dynamc-dns-client-with-rackspace-api/</link><pubDate>Mon, 11 Apr 2016 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/build-a-dynamc-dns-client-with-rackspace-api/</guid><description>&lt;p>This time I&amp;rsquo;ve want to create a homemade Server with my Raspberry Pi2 and publish it using my own sub-domain,
the main problem is that the ISP provide me an dynamic IP and we should ensure that if my IP address change the sub-domain record should point to the new IP.&lt;/p>
&lt;p>The instructions assume that you:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Have a domain&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Have already changed your NS records to point to dns1.stabletransit.com and dns2.stabletransit.com.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;ol>
&lt;li>
&lt;p>You should download the latest version of rsdns from github&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/bin/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/linickx/rsdns.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Go to your Rackspace portal &lt;a href="https://login.rackspace.com/" target="_blank" rel="noopener">https://login.rackspace.com/&lt;/a> and grab your Username &amp;amp; API key (It&amp;rsquo;s under &amp;ldquo;Your Account&amp;rdquo; -&amp;gt; &amp;ldquo;Account Settings&amp;rdquo; -&amp;gt; &amp;ldquo;API Key&amp;rdquo;)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Create a configuration file for rsdns (~/.rsdns_config) with your settings.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="nv">RSUSER&lt;/span>&lt;span class="o">=&lt;/span>dcmst
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">RSAPIKEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1234567890&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">RSPATH&lt;/span>&lt;span class="o">=&lt;/span>~/bin/rsdns/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>You need your domain created on Rackspace(It&amp;rsquo;s under &amp;ldquo;Networking&amp;rdquo; -&amp;gt; &amp;ldquo;Cloud DNS&amp;rdquo; -&amp;gt; &amp;ldquo;Create Domain&amp;rdquo;) if you don&amp;rsquo;t have your domain created you are able to created using rsdns:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">./rsdns-domain.sh -d www.d-cmst.io -e dcmst@devcrumbs.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Once you have a domain setup you need to create an A record.
To create the A record you going to need an IP address, you can use &lt;a href="http://icanhazip.com" target="_blank" rel="noopener">http://icanhazip.com&lt;/a> to get your actual current IP.
Again to create a record you are able to do it from Rackspace panel (It&amp;rsquo;s under &amp;ldquo;Networking&amp;rdquo; -&amp;gt; &amp;ldquo;Cloud DNS&amp;rdquo; -&amp;gt; YOUR_DOMAIN -&amp;gt; &amp;ldquo;Add Record&amp;rdquo;) or you can use rsdns:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">./rsdns-a.sh -n dynamic-host.d-cmst.io -i 123.123.123.123 -t &lt;span class="m">3600&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the above the TTL is set to 1hr (3600 secs), this is so that DNS caches do not keep the record too long. That&amp;rsquo;s all the pre-work done, now lets get your dynamic host setup!&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The script to update your a record is rsdns-dc.sh, and you run it like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">./rsdns-dc.sh -n dynamic-host.d-cmst.io
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The script uses icanhazip to get your current IP, it then update the A record with it.&lt;/p>
&lt;p>I never switch off my router so I have create a created a cronjob to run that script every 2 hours,
plus the 1hr TTL should mean that the record is roughly in sync with my IP without making unnecessary requests&lt;/p>
&lt;/li>
&lt;li>
&lt;p>I use CentOS, so I can simply drop the following file called rsdns-dc into /etc/cron.d/ with this&amp;hellip;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">vim /etc/cron.d/rsdns-dc
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">* */2 * * * dcmst /home/dcmst/bin/rsdns/rsdns-dc.sh -n dynamic-host.d-cmst.io &lt;span class="p">&amp;amp;&lt;/span>&amp;gt;/dev/null
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now we are done! Private Dynamic DNS on your own zone using the Rackspace API.&lt;/p></description></item><item><title>Spamassassin Error: cannot create user preferences file //.spamassassin/user_prefs: Permission denied on VestaCP - CentOS</title><link>https://portfolio.devcrumbs.com/spamassassin-error-on-vestacp-centos/</link><pubDate>Wed, 08 Apr 2015 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/spamassassin-error-on-vestacp-centos/</guid><description>&lt;p>When you configure spamassassin on VestaCP (CentOS) sometimes you might have some problems with the autolearn feature and also with the bayes plugin of spamassassin.&lt;/p>
&lt;p>The error looks like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">more /var/log/maillog
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: connection from localhost &lt;span class="o">[&lt;/span>127.0.0.1&lt;span class="o">]&lt;/span> at port &lt;span class="m">37022&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: setuid to nobody succeeded
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: creating default_prefs: //.spamassassin/user_prefs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: config: cannot create user preferences file //.spamassassin/user_prefs: No such file or directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: failed to create readable default_prefs: //.spamassassin/user_prefs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: checking message &lt;span class="p">&amp;amp;&lt;/span>lt&lt;span class="p">;&lt;/span>5520C87B.8020009@example.com&lt;span class="p">&amp;amp;&lt;/span>gt&lt;span class="p">;&lt;/span> &lt;span class="k">for&lt;/span> nobody:99
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: plugin: &lt;span class="nb">eval&lt;/span> failed: bayes: &lt;span class="o">(&lt;/span>in learn&lt;span class="o">)&lt;/span> locker: safe_lock: cannot create tmp lockfile
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/.spamassassin/bayes.lock.vestaserver01.example.com.1353 &lt;span class="k">for&lt;/span> /.spamassassin/bayes.lock: No such file or directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: clean message &lt;span class="o">(&lt;/span>-1.0/5.0&lt;span class="o">)&lt;/span> &lt;span class="k">for&lt;/span> nobody:99 in 0.2 seconds, &lt;span class="m">3138&lt;/span> bytes.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apr &lt;span class="m">5&lt;/span> 00:31:00 vestaserver01 spamd&lt;span class="o">[&lt;/span>1353&lt;span class="o">]&lt;/span>: spamd: result: . &lt;span class="m">0&lt;/span> - ALL_TRUSTED,HTML_MESSAGE &lt;span class="nv">scantime&lt;/span>&lt;span class="o">=&lt;/span>0.2,size&lt;span class="o">=&lt;/span>3138,user&lt;span class="o">=&lt;/span>nobody,uid&lt;span class="o">=&lt;/span>999,required_score&lt;span class="o">=&lt;/span>5.0,rhost&lt;span class="o">=&lt;/span>localhost,raddr&lt;span class="o">=&lt;/span>127.0.0.1,rport&lt;span class="o">=&lt;/span>37022,mid&lt;span class="o">=&lt;/span>&lt;span class="p">&amp;amp;&lt;/span>lt&lt;span class="p">;&lt;/span>5520C87B.8020009@example.com&lt;span class="p">&amp;amp;&lt;/span>gt&lt;span class="p">;&lt;/span>,autolearn&lt;span class="o">=&lt;/span>unavailable
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Basically the error are the permissions on: //.spamassassin/user_prefs&lt;/p>
&lt;p>To fix it follow the next steps:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Create the user spamd, in order to avoid to run spamassassin with the user nobody:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">groupadd -g &lt;span class="m">1001&lt;/span> spamd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">useradd -u &lt;span class="m">1001&lt;/span> -g spamd -s /sbin/nologin -d /var/lib/spamassassin spamd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir /var/lib/spamassassin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chown spamd:spamd /var/lib/spamassassin&amp;lt;/pre&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Edit the file /etc/exim/exim.conf.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">vi /etc/exim/exim.conf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Change the line:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">spam&lt;/span> &lt;span class="o">=&lt;/span> nobody:true/defer_ok
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>to&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">spam&lt;/span> &lt;span class="o">=&lt;/span> spamd:true/defer_ok
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Restart exim an spamassassin&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">/etc/init.d/exim restart
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/etc/init.d/spamassassin restart
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>After that verify that the files &lt;strong>bayes_seen, bayes_toks and user_prefs&lt;/strong> exists on the spamd home (In this case /var/lib/spamassassin)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">pwd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/var/lib/spamassassin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ls -la
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">total &lt;span class="m">40&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">drwxr-xr-x &lt;span class="m">3&lt;/span> spamd spamd &lt;span class="m">4096&lt;/span> Apr &lt;span class="m">7&lt;/span> 17:58 .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">drwxr-xr-x &lt;span class="m">36&lt;/span> root root &lt;span class="m">4096&lt;/span> Feb &lt;span class="m">25&lt;/span> 00:56 ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-rw------- &lt;span class="m">1&lt;/span> spamd spamd &lt;span class="m">12288&lt;/span> Apr &lt;span class="m">2&lt;/span> 21:34 bayes_seen
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-rw------- &lt;span class="m">1&lt;/span> spamd spamd &lt;span class="m">12288&lt;/span> Apr &lt;span class="m">2&lt;/span> 17:34 bayes_toks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-rw-r--r-- &lt;span class="m">1&lt;/span> spamd spamd &lt;span class="m">1869&lt;/span> Apr &lt;span class="m">1&lt;/span> 17:18 user_prefs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Done!&lt;/p></description></item><item><title>SFTP Jailed</title><link>https://portfolio.devcrumbs.com/sftp-jailed/</link><pubDate>Tue, 31 Mar 2015 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/sftp-jailed/</guid><description>&lt;p>To configure your server to use a jailed user on SFTP you should do:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Edit the sshd_config file&lt;/p>
&lt;p>We need to comment the following line:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">Subsystem sftp /usr/libexec/openssh/sftp-server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And add the uncomment line, your modification will be same as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Subsystem sftp /usr/libexec/openssh/sftp-server&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Subsystem sftp internal-sftp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Also, at the end of the file we should to add the next lines:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">Match Group sftponly
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ChrootDirectory %h
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">X11Forwarding no
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">AllowTCPForwarding no
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ForceCommand internal-sftp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After save all the changes, we must restart the sshd daemon&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">service sshd restart
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Add &lt;strong>sftponly&lt;/strong> group&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">groupadd sftponly
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol>
&lt;li>Add jailed user and add to &lt;strong>sftponly&lt;/strong> group&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">useradd -m USERNAME
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">passwd USERNAME
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">usermod -aG sftponly,apache USERNAME
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>IMPORTANT&lt;/strong>: Create directory and establish correct permissions&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">chown root:root /home/USERNAME
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">755&lt;/span> /home/USERNAME
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir /home/USERNAME/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chown apache:apache /home/USERNAME/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">775&lt;/span> /home/USERNAME/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir /var/www/vhost/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chown apache:apache /var/www/vhost/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">775&lt;/span> /var/www/vhost/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note: &lt;em>If you have any connection problem please double check the permissions on the folders and check the logs on /var/log/secure&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">tail -f /var/log/secure
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Mount DocumentRoot path on jailed user home directory&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">mount -o bind,noatime /var/www/vhost/TEST.DOMAIN.COM/ /home/USERNAME/TEST.DOMAIN.COM
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Make the mount point permanent, editing the fstab file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">vi /etc/fstab
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add the mount point at the end of the file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">/var/www/vhost/TEST.DOMAIN.COM/ /home/USERNAME/TEST.DOMAIN.COM none bind,noatime &lt;span class="m">0&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Save and exit&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Test connection:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sftp SERVERIP
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol></description></item><item><title>View sources IP's in Apache Logs behind a Load Balancer</title><link>https://portfolio.devcrumbs.com/view-sources-ips-apache-logs-behind-loadbalancer/</link><pubDate>Fri, 13 Feb 2015 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/view-sources-ips-apache-logs-behind-loadbalancer/</guid><description>&lt;p>When you use the Rackspace Cloud Load Balancers, it is common that the IP logged in Apache is the Private IP (ServiceNet) from the Cloud Load Balancer, however, we can fix that.&lt;/p>
&lt;p>We can view sources IP&amp;rsquo;s in Apache Logs doing some changes on Apache configuration file and also on the vhosts configuration files.&lt;/p>
&lt;p>On your Apache configuration file, you should to find the line:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">LogFormat &lt;span class="s2">&amp;#34;%h %l %u %t \&amp;#34;%r\&amp;#34; %&amp;amp;gt;s %b \&amp;#34;%{Referer}i\&amp;#34; \&amp;#34;%{User-Agent}i\&amp;#34;&amp;#34;&lt;/span> combined
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Modified to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">LogFormat &lt;span class="s2">&amp;#34;%{X-Forwarded-For}i %h %l %u %t \&amp;#34;%r\&amp;#34; %&amp;amp;gt;s %O \&amp;#34;%{Referer}i\&amp;#34; \&amp;#34;%{User-Agent}i\&amp;#34;&amp;#34;&lt;/span> combined
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And also, on your vhosts configuration files you should to change the &amp;ldquo;combined&amp;rdquo; LogFormat definition will then be called in a &amp;ldquo;CustomLog&amp;rdquo; entry specific to your VirtualHost configuration.
Here is an example VirtualHost definition to show you what I&amp;rsquo;m referring to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ServerAdmin webmaster@example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">DocumentRoot /var/www/html/example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ServerName example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ErrorLog logs/example.com-error_log
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">CustomLog logs/example.com-access_log combined
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After adding the X-Forwarded-For definition to the LogFormat definition, you can restart Apache and view the logs to notice the difference.
If all is done properly, you will see an actual public IP in the first field of your logs instead of the Cloud Load Balancer IP.&lt;/p></description></item><item><title>Yosemite stuck on boot process</title><link>https://portfolio.devcrumbs.com/yosemite-stuck-boot-process/</link><pubDate>Thu, 08 Jan 2015 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/yosemite-stuck-boot-process/</guid><description>&lt;p>Sometimes, I&amp;rsquo;m having problems with my Mac, when it&amp;rsquo;s sleep (hibernate) and I tried to &amp;ldquo;wake up&amp;rdquo; the Mac doesn&amp;rsquo;t start, and it shows me a Black Screen.
So, I&amp;rsquo;ve rebooted and after that it is stuck on the boot process.&lt;/p>
&lt;p>So, I&amp;rsquo;ve found these solution to avoid that Yosemite stuck on the boot process:&lt;/p>
&lt;p>A. Enter to Single-user or verbose mode&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Shutdown the Mac&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Press the power button to start the computer&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Immediately press and hold the Command Key and either of the following&lt;/p>
&lt;/li>
&lt;/ol>
&lt;pre>&lt;code>* the &amp;quot;s&amp;quot; key for single-user mode (Command-S)
* the &amp;quot;v&amp;quot; key for verbose mode (Command-V)
&lt;/code>&lt;/pre>
&lt;p>B. When you login on the Mac, you should run the following commands:&lt;/p>
&lt;pre>&lt;code>```shell
/sbin/mount -uw /
rm -rf /System/Library/Caches/*
rm /private/var/db/BootCache.playlsit
reboot
```
&lt;/code>&lt;/pre>
&lt;p>After the reboot, your Mac will boot as always.&lt;/p>
&lt;p>🙂&lt;/p></description></item><item><title>How to Update a ThemeForest Theme with the Envato WordPress Toolkit</title><link>https://portfolio.devcrumbs.com/update-themeforest-themes-envato-wordpress-toolkit/</link><pubDate>Mon, 10 Nov 2014 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/update-themeforest-themes-envato-wordpress-toolkit/</guid><description>&lt;p>I&amp;rsquo;ve purchased some themes on ThemeForest.com because they&amp;rsquo;re great. So this time I want to write about &amp;ldquo;How to Update ThemeForest Themes with the Envato WordPress Toolkit&amp;rdquo;.&lt;/p>
&lt;p>First of all, Envato WordPress Toolkit it is very similar to a WordPress plugin.
The installation it is the only difference. So I will explain how install the &amp;ldquo;plugin&amp;rdquo; and how to use in order to get the last update from your theme.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Envato WordPress Toolkit is NOT available on WordPress Repositories, so you will to download from Github. &lt;a href="https://github.com/envato/envato-wordpress-toolkit" target="_blank" rel="noopener">https://github.com/envato/envato-wordpress-toolkit&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>After you download the .ZIP file, you should be able to install from the WordPress Plugin Manager. Or you could upload the &lt;strong>envato-wordpress-toolkit&lt;/strong> folder to the &lt;code>/wp-content/plugins/&lt;/code> directory.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Activate the Plugin from the WordPress Plugin Manager.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>You will need to generate an API key from your Themeforest account.&lt;/p>
&lt;ol>
&lt;li>In order to get your API key from Themeforest, you should login to themeforest.com, go to your dashboard and click on &lt;strong>My Settings&lt;/strong> The API Keys screen allows you to generate a free API key.&lt;/li>
&lt;/ol>
&lt;figure id="figure-envato-api-key">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Generate Envato API Key" srcset="
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/generate-api-key_hu79f87149a8509f91806f4c36cecc87ef_48069_4eb5737a3c03bed98c53647532a3f590.webp 400w,
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/generate-api-key_hu79f87149a8509f91806f4c36cecc87ef_48069_766063b7ba80e0dd8b93f3fee0009839.webp 760w,
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/generate-api-key_hu79f87149a8509f91806f4c36cecc87ef_48069_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/update-themeforest-themes-envato-wordpress-toolkit/generate-api-key_hu79f87149a8509f91806f4c36cecc87ef_48069_4eb5737a3c03bed98c53647532a3f590.webp"
width="585"
height="493"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Generate Envato API Key
&lt;/figcaption>&lt;/figure>
&lt;/li>
&lt;li>
&lt;p>Once the API connection has been established you will see a list of themes that can be auto installed.
If you don&amp;rsquo;t see any themes and are certain you&amp;rsquo;ve done everything correct, there is a good chance the theme author has not updated their theme to be available for auto install and update.
If that&amp;rsquo;s the case, please contact the theme author and ask them to update their theme&amp;rsquo;s information.&lt;/p>
&lt;figure id="figure-envato-theme-autoupdate">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Envato Theme Autoupdate" srcset="
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/theme-autoupdate_hu268c77734e5fb68b0dd1f925fae254b4_10949_23f0595c735a2755b0781d9e01fffb7e.webp 400w,
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/theme-autoupdate_hu268c77734e5fb68b0dd1f925fae254b4_10949_e50aef30fc005b4250dd78e628dcf77e.webp 760w,
/media/posts/update-themeforest-themes-envato-wordpress-toolkit/theme-autoupdate_hu268c77734e5fb68b0dd1f925fae254b4_10949_1200x1200_fit_q90_h2_lanczos_3.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/update-themeforest-themes-envato-wordpress-toolkit/theme-autoupdate_hu268c77734e5fb68b0dd1f925fae254b4_10949_23f0595c735a2755b0781d9e01fffb7e.webp"
width="543"
height="94"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Envato Theme Autoupdate
&lt;/figcaption>&lt;/figure>
&lt;/li>
&lt;/ol>
&lt;p>This &amp;ldquo;plugin&amp;rdquo; very helpful to get your themes updated. I hope works for you as well as with me.&lt;/p></description></item><item><title>MySQL reset root password</title><link>https://portfolio.devcrumbs.com/mysql-reset-root-password/</link><pubDate>Wed, 30 Jul 2014 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/mysql-reset-root-password/</guid><description>&lt;p>Hello,&lt;/p>
&lt;p>This time I share with you the faster and more secure method to reset the root password of MySQL.&lt;/p>
&lt;p>This method is faster because the downtime is between 1 or 2 seconds (MySQL restart time) and it is more secure because the mysqld is not started without grants on the tables.&lt;/p>
&lt;p>The steps are:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Create text file /var/lib/mysql/mysql-init with the sintaxis to reset the password for user root:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">vim /var/lib/mysql/mysql-init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">SET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PASSWORD&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FOR&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;root&amp;#39;&lt;/span>&lt;span class="o">@&lt;/span>&lt;span class="s1">&amp;#39;localhost&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PASSWORD&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;new_password&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Add under the [mysqld] stanza on the file /etc/my.cnf:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">init-file&lt;span class="o">=&lt;/span>/var/lib/mysql/mysql-init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Restart the mysqld service:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">service mysqld restart
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Remove the init-file line from /etc/my.cnf&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Remove /var/lib/mysql/mysql-init&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">rm /var/lib/mysql/mysql-init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>And after that, you can access again to your mysql instance.&lt;/p>
&lt;p>😄&lt;/p></description></item><item><title>MySQL without password</title><link>https://portfolio.devcrumbs.com/mysql-without-password/</link><pubDate>Tue, 15 Apr 2014 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/mysql-without-password/</guid><description>&lt;p>The common form to log in to MySQL server, is running a mysql command with your login credentials and server&amp;rsquo;s IP address as arguments. For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">mysql -u &lt;span class="nv">$MYSQL_ROOT&lt;/span> -p&lt;span class="nv">$MYSQL_PASS&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>However, besides the inconvenience of typing extra arguments, using plain-text login credentials in a command line like above is really not a secure way to access a MySQL server.&lt;/p>
&lt;p>MySQL offers a way for you to log in to MySQL server without password, by using an external MySQL configuration file. In Linux, there are two different kinds of MySQL configuration files:&lt;/p>
&lt;ol>
&lt;li>/etc/my.cnf and&lt;/li>
&lt;li>~/.my.conf&lt;/li>
&lt;/ol>
&lt;p>While any system-wide MySQL configuration is defined in /etc/my.cnf, any user-specific MySQL configuration is stored in ~/.my.cnf.
You can leverage ~/.my.cnf, to define your MySQL login credential in the file.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">vim ~/.my.cnf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We put our MySQL user in the configuration file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>client&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">user&lt;/span>&lt;span class="o">=&lt;/span>root
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">password&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$PASSWORD_ROOT&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Make sure to have the configuration file readable to you only.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">0600&lt;/span> ~/.my.cnf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once ~/.my.cnf is created, simply typing mysql command will let you log in to the MySQL server as root, and you no longer need to provide login password separately.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">mysql
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Welcome to the MySQL monitor. Commands end with &lt;span class="p">;&lt;/span> or &lt;span class="se">\g&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your MySQL connection id is &lt;span class="m">14787&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Server version: 5.1.73 Source distribution
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Copyright &lt;span class="o">(&lt;/span>c&lt;span class="o">)&lt;/span> 2000, 2013, Oracle and/or its affiliates. All rights reserved.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Oracle is a registered trademark of Oracle Corporation and/or its
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">affiliates. Other names may be trademarks of their respective
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">owners.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Type &lt;span class="s1">&amp;#39;help;&amp;#39;&lt;/span> or &lt;span class="s1">&amp;#39;\h&amp;#39;&lt;/span> &lt;span class="k">for&lt;/span> help. Type &lt;span class="s1">&amp;#39;\c&amp;#39;&lt;/span> to clear the current input statement.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mysql&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>I'm a Racker</title><link>https://portfolio.devcrumbs.com/im-a-racker/</link><pubDate>Mon, 31 Mar 2014 00:00:00 +0000</pubDate><guid>https://portfolio.devcrumbs.com/im-a-racker/</guid><description>&lt;p>Since January 6th I working on &lt;a href="http://www.rackspace.com/" target="_blank" rel="noopener">Rackspace&lt;/a>, the Open Cloud Company, so I&amp;rsquo;m a Racker almost 3 months ago and I&amp;rsquo;m loving every minute of it.&lt;/p>
&lt;figure id="figure-rackspace-kickoff">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Kickoff" srcset="
/media/posts/im-a-racker/Rackspace_2014_hu97f9df69980c815709b56b744b2afe31_1277016_c4223cd27b6efc378912441740b16a45.webp 400w,
/media/posts/im-a-racker/Rackspace_2014_hu97f9df69980c815709b56b744b2afe31_1277016_8a88b10b1d9db7b6f37fbf0b1d1054b5.webp 760w,
/media/posts/im-a-racker/Rackspace_2014_hu97f9df69980c815709b56b744b2afe31_1277016_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_2014_hu97f9df69980c815709b56b744b2afe31_1277016_c4223cd27b6efc378912441740b16a45.webp"
width="760"
height="567"
loading="lazy" data-zoomable class=" img-light" />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Kickoff
&lt;/figcaption>&lt;/figure>
&lt;h2 id="previous">Previous&lt;/h2>
&lt;p>Everything stared on November 2013 when a Technical Recruiter contact me and started a proceess with some long tough interviews, ability tests, paperwork, etc;
I have accepted a position as a Linux System Administrator I in the LATAM Team for Rackspace, so, I got to work for one of the most dynamic, fanatic, and fun tech companies in the world!&lt;/p>
&lt;p>So, I was very excited, nervous, happy, all together.&lt;/p>
&lt;h2 id="the-castle">The Castle&lt;/h2>
&lt;p>Since I came to The Castle, everything was wonderful, I have met nice, friendly, smart and fanatical people,
like &lt;a href="https://twitter.com/rackersugarbear" target="_blank" rel="noopener">@SugarBear&lt;/a>, a Rackspace Ambassador of Culture, or &lt;a href="https://twitter.com/gweston" target="_blank" rel="noopener">Graham Weston&lt;/a>, Rackspace&amp;rsquo;s Chairman and Co-Funder.
I met them at the Rookie Orientation (a.k.a Rookie&amp;rsquo;O), where I spend time with other Rookies learning about Rackspace history, culture and future plans.&lt;/p>
&lt;p>On the Rookie&amp;rsquo;O, I was surprised and admired with all the energy that is transmitted between the new Rackers, it was awesome!&lt;/p>
&lt;p>And I was inspired by the Rackspace Core Values:&lt;/p>
&lt;ul>
&lt;li>Fanatical Support® in all we do.&lt;/li>
&lt;li>Results first, substance over flash.&lt;/li>
&lt;li>Committed to Greatness&lt;/li>
&lt;li>Full Disclosure and Transparency&lt;/li>
&lt;li>Passion for our Work&lt;/li>
&lt;li>Treat fellow Rackers like Friends and Family&lt;/li>
&lt;/ul>
&lt;p>Which from my point of view I can applied to my personal life, and having great results.&lt;/p>
&lt;p>Also is very comfortable to have a Coffe Shop, a soda machine or microwaves inside the Castle. It is pretty nice!&lt;/p>
&lt;p>In general the first week in Rackspace, on the Rookie&amp;rsquo;O, I was a great experience, I can say that is one of my best experiences in my life.&lt;/p>
&lt;figure id="figure-rackspace-rookieo">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Rookie O" srcset="
/media/posts/im-a-racker/Rackspace_RookieO_hub2cbc3c35f6b27d4fa638699f196141b_1144827_83441913fe5094c92cc43a4a93d9d62b.webp 400w,
/media/posts/im-a-racker/Rackspace_RookieO_hub2cbc3c35f6b27d4fa638699f196141b_1144827_83e5529f91857c862ba240bbc2cc3f3d.webp 760w,
/media/posts/im-a-racker/Rackspace_RookieO_hub2cbc3c35f6b27d4fa638699f196141b_1144827_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_RookieO_hub2cbc3c35f6b27d4fa638699f196141b_1144827_83441913fe5094c92cc43a4a93d9d62b.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Rookie O
&lt;/figcaption>&lt;/figure>
&lt;figure id="figure-rackspace-fanatical-jacket">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Fanatical Jacket" srcset="
/media/posts/im-a-racker/Rackspace_FanaticalJacket_hudeb9d70ed5efd832c64e119d2afbeec5_1023967_bd8f432fa4ed8d48a10e07964d0d3953.webp 400w,
/media/posts/im-a-racker/Rackspace_FanaticalJacket_hudeb9d70ed5efd832c64e119d2afbeec5_1023967_6952966d7f090d8228b9daeccef9c879.webp 760w,
/media/posts/im-a-racker/Rackspace_FanaticalJacket_hudeb9d70ed5efd832c64e119d2afbeec5_1023967_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_FanaticalJacket_hudeb9d70ed5efd832c64e119d2afbeec5_1023967_bd8f432fa4ed8d48a10e07964d0d3953.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Fanatical Jacket
&lt;/figcaption>&lt;/figure>
&lt;figure id="figure-rackspace-fuel-station">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Fuel station" srcset="
/media/posts/im-a-racker/Rackspace_FuelStation_hu95fdeae0c2a58edd0978a06ff5980105_1202391_2a9d6c0c5227b27d1d6860fbd5158a6a.webp 400w,
/media/posts/im-a-racker/Rackspace_FuelStation_hu95fdeae0c2a58edd0978a06ff5980105_1202391_5845109cc2d61713020f973889b8847a.webp 760w,
/media/posts/im-a-racker/Rackspace_FuelStation_hu95fdeae0c2a58edd0978a06ff5980105_1202391_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_FuelStation_hu95fdeae0c2a58edd0978a06ff5980105_1202391_2a9d6c0c5227b27d1d6860fbd5158a6a.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Fuel station
&lt;/figcaption>&lt;/figure>
&lt;figure id="figure-rackspace-slide">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Slide" srcset="
/media/posts/im-a-racker/Rackspace_Slide_huaf8ccd0b3599f98acb0ed36076f7e8d0_1090662_b29aa89fad82bfc348634750d954650c.webp 400w,
/media/posts/im-a-racker/Rackspace_Slide_huaf8ccd0b3599f98acb0ed36076f7e8d0_1090662_003d657ee6df1c7721b971541395fe83.webp 760w,
/media/posts/im-a-racker/Rackspace_Slide_huaf8ccd0b3599f98acb0ed36076f7e8d0_1090662_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_Slide_huaf8ccd0b3599f98acb0ed36076f7e8d0_1090662_b29aa89fad82bfc348634750d954650c.webp"
width="567"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Slide
&lt;/figcaption>&lt;/figure>
&lt;figure id="figure-rackspace-groundtown">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - Coffee Shop" srcset="
/media/posts/im-a-racker/Rackspace_GroundTown_hud1582ace60fd2f0d9e0195d009292ecd_990215_afa2d6a82ab5f4d476901aefa013c422.webp 400w,
/media/posts/im-a-racker/Rackspace_GroundTown_hud1582ace60fd2f0d9e0195d009292ecd_990215_4ed151ce6b383af8a88dd4a05032b807.webp 760w,
/media/posts/im-a-racker/Rackspace_GroundTown_hud1582ace60fd2f0d9e0195d009292ecd_990215_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_GroundTown_hud1582ace60fd2f0d9e0195d009292ecd_990215_afa2d6a82ab5f4d476901aefa013c422.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - Coffee Shop
&lt;/figcaption>&lt;/figure>
&lt;h2 id="my-goals">My Goals&lt;/h2>
&lt;p>This is a new big challenge, because means:&lt;/p>
&lt;ul>
&lt;li>Relocation in other country, specifically in San Antonio, TX, USA.&lt;/li>
&lt;li>Leave my family in Mexico City, that means that I see my parents only for Skype or FaceTime :).&lt;/li>
&lt;li>Know other culture, the &amp;ldquo;American&amp;rdquo; culture, with the Breakfast Tacos or Tex-Mex food
(I really hate the Tex-Mex food yiack!) or the Lunch at noon, people do not always says &amp;ldquo;Good morning&amp;rdquo; and
some details that I don&amp;rsquo;t understand but here is common.&lt;/li>
&lt;li>Improve my skills in other language (English) event though I&amp;rsquo;m in the Rackspace LATAM team all the communications like emails or meetings are in English, so, it is very important for my job.&lt;/li>
&lt;li>And the most important challenge for me is still learn about Linux, get my Red Hat Certifications, do my best at job and take advantage of this great opportunity. All of that to try to be a DevOps Engineer&lt;/li>
&lt;/ul>
&lt;figure id="figure-rackspace-latam">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - LATAM Section" srcset="
/media/posts/im-a-racker/Rackspace_LATAM_hu95949b8097d407b309e20f2abb4e91dd_856072_f04077c8aa573be5541aeebf10e7385a.webp 400w,
/media/posts/im-a-racker/Rackspace_LATAM_hu95949b8097d407b309e20f2abb4e91dd_856072_1582c54ea8945af1d9628ad9d5d34921.webp 760w,
/media/posts/im-a-racker/Rackspace_LATAM_hu95949b8097d407b309e20f2abb4e91dd_856072_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_LATAM_hu95949b8097d407b309e20f2abb4e91dd_856072_f04077c8aa573be5541aeebf10e7385a.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - LATAM Section
&lt;/figcaption>&lt;/figure>
&lt;figure id="figure-rackspace-desk">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Rackspace - My Desk" srcset="
/media/posts/im-a-racker/Rackspace_MyDesk_hu58e0dbb86868380bf1fe6ae7ac59baa2_1047595_fa1427fe85442c7c2361d116b4dd0c3e.webp 400w,
/media/posts/im-a-racker/Rackspace_MyDesk_hu58e0dbb86868380bf1fe6ae7ac59baa2_1047595_6360e43c5f07718ee67bd1dc73be9a27.webp 760w,
/media/posts/im-a-racker/Rackspace_MyDesk_hu58e0dbb86868380bf1fe6ae7ac59baa2_1047595_1200x1200_fit_q90_h2_lanczos.webp 1200w"
src="https://portfolio.devcrumbs.com/media/posts/im-a-racker/Rackspace_MyDesk_hu58e0dbb86868380bf1fe6ae7ac59baa2_1047595_fa1427fe85442c7c2361d116b4dd0c3e.webp"
width="760"
height="567"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Rackspace - My Desk
&lt;/figcaption>&lt;/figure>
&lt;p>I will be working on, providing Fanatical Support for our customers, resolving LATAM customer issues with Linux and working with remote teams from all around the world.&lt;/p>
&lt;p>Summarizing, I&amp;rsquo;m a happy Racker 🙂&lt;/p></description></item></channel></rss>