<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ SSL - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ SSL - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:25:01 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ssl/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Self-host a Container Registry ]]>
                </title>
                <description>
                    <![CDATA[ A container registry is a storage catalog from where you can push and pull container images. There are many public and private registries available to developers such as Docker Hub, Amazon ECR, and Google Cloud Artifact Registry. But sometimes, inste... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-self-host-a-container-registry/</link>
                <guid isPermaLink="false">670ea63e203bba3017cc96ff</guid>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ containers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nginx ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Pliutau ]]>
                </dc:creator>
                <pubDate>Tue, 15 Oct 2024 17:28:30 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728918386211/cf6fd053-453e-4257-abcd-16942c345845.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A container registry is a storage catalog from where you can push and pull container images.</p>
<p>There are many public and private registries available to developers such as <a target="_blank" href="https://hub.docker.com/">Docker Hub</a>, <a target="_blank" href="https://aws.amazon.com/ecr/">Amazon ECR</a>, and <a target="_blank" href="https://cloud.google.com/artifact-registry/docs">Google Cloud Artifact Registry</a>. But sometimes, instead of relying on an external vendor, you might want to host your images yourself. This gives you more control over how the registry is configured and where the container images are hosted.</p>
<p>This article is a hands-on tutorial that’ll teach you how to self-host a Container Registry.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-container-image">What is a Container Image?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-container-registry">What is a Container Registry?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-you-might-want-to-self-host-a-container-registry">Why you might want to self-host a Container Registry</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-self-host-a-container-registry">How to self-host a Container Registry</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-install-docker-and-docker-compose-on-the-server">Step 1: Install Docker and Docker Compose on the server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-configure-and-run-the-registry-container">Step 2: Configure and run the registry container</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-run-nginx-for-handling-tls">Step 3: Run NGINX for handling TLS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ready-to-go">Ready to go!</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-other-options">Other options</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>You will get the most out of this article if you’re already familiar with the tools like Docker and NGINX, and have a general understanding of what a container is.</p>
<h2 id="heading-what-is-a-container-image">What is a Container Image?</h2>
<p>Before we talk about container registries, let's first understand what a container image is. In a nutshell, a container image is a package that includes all of the files, libraries, and configurations to run a container. They are composed of <a target="_blank" href="https://docs.docker.com/get-started/docker-concepts/building-images/understanding-image-layers/">layers</a> where each layer represents a set of file system changes that add, remove, or modify files.</p>
<p>The most common way to create a container image is to use a <strong>Dockerfile</strong>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># build an image</span>
docker build -t pliutau/hello-world:v0 .

<span class="hljs-comment"># check the images locally</span>
docker images
<span class="hljs-comment"># REPOSITORY    TAG       IMAGE ID       CREATED          SIZE</span>
<span class="hljs-comment"># hello-world   latest    9facd12bbcdd   22 seconds ago   11MB</span>
</code></pre>
<p>This creates a container image that is stored on your local machine. But what if you want to share this image with others or use it on a different machine? This is where container registries come in.</p>
<h2 id="heading-what-is-a-container-registry">What is a Container Registry?</h2>
<p>A container registry is a storage catalog where you can push and pull container images from. The images are grouped into repositories, which are collections of related images with the same name. For example, on Docker Hub registry, <a target="_blank" href="https://hub.docker.com/_/nginx">nginx</a> is the name of the repository that contains different versions of the NGINX images.</p>
<p>Some registries are public, meaning that the images hosted on them are accessible to anyone on the Internet. Public registries such as <a target="_blank" href="https://hub.docker.com/">Docker Hub</a> are a good option to host open-source projects.</p>
<p>On the other hand, private registries provide a way to incorporate security and privacy into enterprise container image storage, either hosted in cloud or on-premises. These private registries often come with advanced security features and technical support.</p>
<p>There is a growing list of private registries available such as <a target="_blank" href="https://aws.amazon.com/ecr/">Amazon ECR</a>, <a target="_blank" href="https://cloud.google.com/artifact-registry/docs">GCP Artifact Registry</a>, <a target="_blank" href="https://github.com/features/packages">GitHub Container Registry</a>, and Docker Hub also offers a private repository feature.</p>
<p>As a developer, you interact with a container registry when using the <code>docker push</code> and <code>docker pull</code> commands.</p>
<pre><code class="lang-bash">docker push docker.io/pliutau/hello-world:v0

<span class="hljs-comment"># In case of Docker Hub we could also skip the registry part</span>
docker push pliutau/hello-world:v0
</code></pre>
<p>Let's look at the anatomy of a container image URL:</p>
<pre><code class="lang-bash">docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
                |            |            |          |
                ↓            ↓            ↓          ↓
             registry    repository      tag       digest
</code></pre>
<h2 id="heading-why-you-might-want-to-self-host-a-container-registry">Why You Might Want to Self-host a Container Registry</h2>
<p>Sometimes, instead of relying on a provider like AWS or GCP, you might want to host your images yourself. This keeps your infrastructure internal and makes you less reliant on external vendors. In some heavily regulated industries, this is even a requirement.</p>
<p>A self-hosted registry runs on your own servers, giving you more control over how the registry is configured and where the container images are hosted. At the same time it comes with a cost of maintaining and securing the registry.</p>
<h2 id="heading-how-to-self-host-a-container-registry">How to Self-host a Container Registry</h2>
<p>There are several open-source container registry solutions available. The most popular one is officially supported by Docker, called <a target="_blank" href="https://hub.docker.com/_/registry">registry</a>, with its implementation for storing and distributing of container images and artifacts. This means that you can run your own registry inside a container.</p>
<p>Here are the main steps to run a registry on a server:</p>
<ul>
<li><p>Install Docker and Docker Compose on the server.</p>
</li>
<li><p>Configure and run the <strong>registry</strong> container.</p>
</li>
<li><p>Run <strong>NGINX</strong> for handling TLS and forwarding requests to the registry container.</p>
</li>
<li><p>Setup SSL certificates and configure a domain.</p>
</li>
</ul>
<h3 id="heading-step-1-install-docker-and-docker-compose-on-the-server">Step 1: Install Docker and Docker Compose on the server</h3>
<p>You can use any server that supports Docker. For example, you can use a DigitalOcean Droplet with Ubuntu. For this demo I used Google Cloud Compute to create a VM with Ubuntu.</p>
<pre><code class="lang-bash">neofetch

<span class="hljs-comment"># OS: Ubuntu 20.04.6 LTS x86_64</span>
<span class="hljs-comment"># CPU: Intel Xeon (2) @ 2.200GHz</span>
<span class="hljs-comment"># Memory: 3908MiB</span>
</code></pre>
<p>Once we're inside our VM, we should install Docker and Docker Compose. Docker Compose is optional, but it makes it easier to manage multi-container applications.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install docker engine and docker-compose</span>
sudo snap install docker

<span class="hljs-comment"># verify the installation</span>
docker --version
docker-compose --version
</code></pre>
<h3 id="heading-step-2-configure-and-run-the-registry-container">Step 2: Configure and run the registry container</h3>
<p>Next we need to configure our registry container. The following <strong>compose.yaml</strong> file will create a registry container with a volume for storing the images and a volume for storing the password file.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">registry:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">registry:latest</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">REGISTRY_AUTH:</span> <span class="hljs-string">htpasswd</span>
      <span class="hljs-attr">REGISTRY_AUTH_HTPASSWD_REALM:</span> <span class="hljs-string">Registry</span> <span class="hljs-string">Realm</span>
      <span class="hljs-attr">REGISTRY_AUTH_HTPASSWD_PATH:</span> <span class="hljs-string">/auth/registry.password</span>
      <span class="hljs-attr">REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY:</span> <span class="hljs-string">/data</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-comment"># Mount the password file</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./registry/registry.password:/auth/registry.password</span>
      <span class="hljs-comment"># Mount the data directory</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./registry/data:/data</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">5000</span>
</code></pre>
<p>The password file defined in <strong>REGISTRY_AUTH_HTPASSWD_PATH</strong> is used to authenticate users when they push or pull images from the registry. We should create a password file using the <strong>htpasswd</strong> command. We should also create a folder for storing the images.</p>
<pre><code class="lang-yaml"><span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">./registry/data</span>

<span class="hljs-comment"># install htpasswd</span>
<span class="hljs-string">sudo</span> <span class="hljs-string">apt</span> <span class="hljs-string">install</span> <span class="hljs-string">apache2-utils</span>

<span class="hljs-comment"># create a password file. username: busy, password: bee</span>
<span class="hljs-string">htpasswd</span> <span class="hljs-string">-Bbn</span> <span class="hljs-string">busy</span> <span class="hljs-string">bee</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">./registry/registry.password</span>
</code></pre>
<p>Now we can start the registry container. If you see this message, than everything is working as it should:</p>
<pre><code class="lang-yaml"><span class="hljs-string">docker-compose</span> <span class="hljs-string">up</span>

<span class="hljs-comment"># successfull run should output something like this:</span>
<span class="hljs-comment"># registry | level=info msg="listening on [::]:5000"</span>
</code></pre>
<h3 id="heading-step-3-run-nginx-for-handling-tls">Step 3: Run NGINX for handling TLS</h3>
<p>As mentioned earlier, we can use NGINX to handle TLS and forward requests to the registry container.</p>
<p>The Docker Registry requires a valid trusted SSL certificate to work. You can use something like <a target="_blank" href="https://letsencrypt.org/">Let's Encrypt</a> or obtain it manually. Make sure you have a domain name pointing to your server (<strong>registry.pliutau.com</strong> in my case). For this demo I already obtained the certificates using <a target="_blank" href="https://certbot.eff.org/">certbot</a> and put it in the <strong>./nginx/certs</strong> directory.</p>
<p>Since we're running our Docker Registry in a container, we can run NGINX in a container as well by adding the following service to the <strong>compose.yaml</strong> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">registry:</span>
    <span class="hljs-comment"># ...</span>
  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:latest</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">registry</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-comment"># mount the nginx configuration</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx/nginx.conf:/etc/nginx/nginx.conf</span>
      <span class="hljs-comment"># mount the certificates obtained from Let's Encrypt</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx/certs:/etc/nginx/certs</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"443:443"</span>
</code></pre>
<p>Our <strong>nginx.conf</strong> file could look like this:</p>
<pre><code class="lang-yaml"><span class="hljs-string">worker_processes</span> <span class="hljs-string">auto;</span>

<span class="hljs-string">events</span> {
    <span class="hljs-string">worker_connections</span> <span class="hljs-number">1024</span><span class="hljs-string">;</span>
}

<span class="hljs-string">http</span> {
    <span class="hljs-string">upstream</span> <span class="hljs-string">registry</span> {
        <span class="hljs-string">server</span> <span class="hljs-string">registry:5000;</span>
    }

    <span class="hljs-string">server</span> {
        <span class="hljs-string">server_name</span> <span class="hljs-string">registry.pliutau.com;</span>
        <span class="hljs-string">listen</span> <span class="hljs-number">443</span> <span class="hljs-string">ssl;</span>

        <span class="hljs-string">ssl_certificate</span> <span class="hljs-string">/etc/nginx/certs/fullchain.pem;</span>
        <span class="hljs-string">ssl_certificate_key</span> <span class="hljs-string">/etc/nginx/certs/privkey.pem;</span>

        <span class="hljs-string">location</span> <span class="hljs-string">/</span> {
            <span class="hljs-comment"># important setting for large images</span>
            <span class="hljs-string">client_max_body_size</span>                <span class="hljs-string">1000m;</span>

            <span class="hljs-string">proxy_pass</span>                          <span class="hljs-string">http://registry;</span>
            <span class="hljs-string">proxy_set_header</span>  <span class="hljs-string">Host</span>              <span class="hljs-string">$http_host;</span>
            <span class="hljs-string">proxy_set_header</span>  <span class="hljs-string">X-Real-IP</span>         <span class="hljs-string">$remote_addr;</span>
            <span class="hljs-string">proxy_set_header</span>  <span class="hljs-string">X-Forwarded-For</span>   <span class="hljs-string">$proxy_add_x_forwarded_for;</span>
            <span class="hljs-string">proxy_set_header</span>  <span class="hljs-string">X-Forwarded-Proto</span> <span class="hljs-string">$scheme;</span>
            <span class="hljs-string">proxy_read_timeout</span>                  <span class="hljs-number">900</span><span class="hljs-string">;</span>
        }
    }
}
</code></pre>
<h3 id="heading-ready-to-go">Ready to go!</h3>
<p>After these steps we can run our registry and Nginx containers.</p>
<pre><code class="lang-bash">docker-compose up
</code></pre>
<p>Now, on the client side, you can push and pull the images from your registry. But first we need to login to the registry.</p>
<pre><code class="lang-bash">docker login registry.pliutau.com

<span class="hljs-comment"># Username: busy</span>
<span class="hljs-comment"># Password: bee</span>
<span class="hljs-comment"># Login Succeeded</span>
</code></pre>
<p>Time to build and push our image to our self-hosted registry:</p>
<pre><code class="lang-bash">docker build -t registry.pliutau.com/pliutau/hello-world:v0 .

docker push registry.pliutau.com/pliutau/hello-world:v0
<span class="hljs-comment"># v0: digest: sha256:a56ea4... size: 738</span>
</code></pre>
<p>On your server you can check the uploaded images in the data folder:</p>
<pre><code class="lang-bash">ls -la ./registry/data/docker/registry/v2/repositories/
</code></pre>
<h3 id="heading-other-options">Other options</h3>
<p>Following the example above, you can also run the registry on Kubernetes. Or you could use a managed registry service like <a target="_blank" href="https://goharbor.io/">Harbor</a>, which is an open-source registry that provides advanced security features and is compatible with Docker and Kubernetes.</p>
<p>Also, if you want to have a UI for your self-hosted registry, you could use a project like <a target="_blank" href="https://github.com/Joxit/docker-registry-ui">joxit/docker-registry-ui</a> and run it in a separate container.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Self-hosted Container Registries allow you to have complete control over your registry and the way it's deployed. At the same time it comes with a cost of maintaining and securing the registry.</p>
<p>Whatever your reasons for running a self-hosted registry, you now know how it's done. From here you can compare the different options and choose the one that best fits your needs.</p>
<p>You can find the full source code for this demo on <a target="_blank" href="https://github.com/plutov/packagemain/tree/master/26-self-hosted-container-registry">GitHub</a>. Also, you can watch it as a video on <a target="_blank" href="https://www.youtube.com/watch?v=TGLfQZ9qRaI">our YouTube channel</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Provision a Home Lab with Oracle Cloud and Ansible ]]>
                </title>
                <description>
                    <![CDATA[ Imagine for a moment that you been working hard to setup a website, protected with SSL, and then your hardware fails. This means that unless you have a perfect backup of your machine, you will need to install all the software and configuration files ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/provision-home-lab-with-oracle-cloud-and-ansible/</link>
                <guid isPermaLink="false">66d85145e9c1a2c18adec0be</guid>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ servers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jose Vicente Nunez ]]>
                </dc:creator>
                <pubDate>Tue, 15 Nov 2022 21:52:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/pexels-pixabay-210158.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine for a moment that you been working hard to setup a website, protected with SSL, and then your hardware fails. This means that unless you have a perfect backup of your machine, you will need to install all the software and configuration files by hand.</p>
<p>What if it's not just one server but many? The amount of time you will need to fix all of them will grow exponentially – and because is a manual process it will be more error-prone.</p>
<p>And then the nightmare scenario: You don't have an up-to-date backup, or you have incomplete backups. Or the worst – there are no backups at all. This last case is more common than you think, especially in home labs where you are tinkering and playing around with stuff by yourself.</p>
<p>In this tutorial, I'll show you how you can do a full infrastructure provisioning of a pair of web servers on a Cloud provider, with <a target="_blank" href="https://www.cloudflare.com/learning/ssl/what-is-ssl/">SSL</a> certificates and monitoring metrics with <a target="_blank" href="https://prometheus.io/docs/introduction/overview/">Prometheus</a>.</p>
<h2 id="heading-what-you-need-for-this-setup">What You Need for This Setup</h2>
<p>The first thing you need is a cloud provider. <a target="_blank" href="https://cloud.oracle.com/">Oracle Cloud</a> offers a <em>Free Tier version</em> of their cloud services, which allows you to setup virtual machines for free. This is great for a home lab with lots of rich features that you can use to try new tools and techniques.</p>
<p>You'll also need an automation tool. I used <a target="_blank" href="https://www.ansible.com/">Ansible</a> because its doesn't have many requirements (you only need an SSH daemon and public key authentication to get things going). I also like it because it works equally well regardless of the cloud environment you are trying to provision.</p>
<p>In this tutorial we will use the <a target="_blank" href="https://github.com/ansible/ansible">Open Source version</a> of this tool, as it is more than sufficient for our purposes.</p>
<h3 id="heading-whats-included-in-the-ansible-playbook">What's included in the Ansible playbook</h3>
<p>An <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.htmlhttps://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html">Ansible playbook</a> is nothing more than a set of instructions you define to execute <em>tasks</em> that will change the status of a host. These actions are carried out on an <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html">inventory of hosts</a> you define.</p>
<p>Here, you are going to learn about the following:</p>
<ul>
<li><p>How to <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-dynamic-inventories">clean inventory sources</a> by using the proper layout in your playbooks.</p>
</li>
<li><p>How to provision two <a target="_blank" href="https://nginx.org/en/">NGINX</a> instances, with the request of their proper free SSL certificates using <a target="_blank" href="https://certbot.eff.org/instructions?ws=nginx&amp;os=pip">Certbot</a>.</p>
</li>
<li><p>How to set up the local Linux firewalls and add a Prometheus node_exporter agent and one scraper to collect that data.</p>
</li>
<li><p>Concepts like variables, roles (with task inclusion), and conditional execution.</p>
</li>
<li><p>Important techniques like task tagging, debug messages, and static validation with <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-lint-YAML">ansible-lint</a>.</p>
</li>
</ul>
<p>All the code can be found in this <a target="_blank" href="https://github.com/josevnz/OracleCloudHomeLab">GitHub repository</a>.</p>
<h2 id="heading-what-you-should-know-before-trying-this">What You Should Know Before Trying This</h2>
<p>Because we will cover several tasks here, you will probably need to be familiar with several things (I'll provide links as we go along):</p>
<ul>
<li><p>This is not an <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-introduction">introductory course on Ansible</a> but more of a "how all things fit together" with a more detailed, but not too complex, playbook.</p>
</li>
<li><p>An <a target="_blank" href="https://www.oracle.com/cloud/free/">OCI Cloud Free Tier</a> account</p>
</li>
<li><p>Privileged account, most likely <a target="_blank" href="https://www.sudo.ws/">SUDO</a></p>
</li>
<li><p>Basic knowledge of <a target="_blank" href="https://www.redhat.com/sysadmin/firewalld-rules-and-scenarios">TCP/IP and firewalls with firewalld</a></p>
</li>
<li><p>How to use <a target="_blank" href="https://www.redhat.com/sysadmin/how-manage-packages">RPM</a> and how to <a target="_blank" href="https://www.redhat.com/sysadmin/package-linux-applications-rpm">package</a> applications (we will not do that here, but it helps to understand when an RPM is better than a complex task in Ansible)</p>
</li>
</ul>
<h3 id="heading-what-is-not-included-here">What is not included here</h3>
<p>OCI Cloud has a <a target="_blank" href="https://docs.oracle.com/en-us/iaas/api/#/en/network-firewall/20211001/NetworkFirewallPolicy/UpdateNetworkFirewallPolicy">complete REST API</a> to manage a lot of aspects of their cloud environment. <a target="_blank" href="https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm#SDK_and_CLI_Configuration_File">Their setup page</a> (specifically the SDK) is also very detailed.</p>
<h2 id="heading-youll-probably-do-things-differently-in-production">You'll Probably Do Things Differently in Production.</h2>
<h3 id="heading-installing-the-oci-metrics-datasource-instead-of-prometheus-agents-on-a-virtual-machine">Installing the OCI-Metrics-datasource instead of Prometheus agents on a virtual machine</h3>
<p>You can go to <a target="_blank" href="https://grafana.com/grafana/plugins/oci-metrics-datasource/?tab=installation">this page</a> to install it on your Grafana instance (Bare metal or Cloud). Also you need to <a target="_blank" href="https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/grafana.htm">setup your credentials and permissions as explained here</a>.</p>
<p>This is probably the most efficient way to monitor your resources as you do not need to run agents on your virtual machines. But I will install instead a <a target="_blank" href="https://github.com/prometheus/node_exporter">Prometheus node_exporter agent</a> and <a target="_blank" href="https://github.com/prometheus/prometheus">scraper</a> that will be visible from a <a target="_blank" href="https://grafana.com/">Grafana Cloud</a> instance.</p>
<h3 id="heading-an-exposed-prometheus-on-the-internet-endpoint-is-not-a-good-idea">An exposed Prometheus on the Internet endpoint is not a good idea</h3>
<p>It is very clear, I'm exposing my Prometheus scraper to the Internet so Grafana cloud can reach it. On an Intranet with a private cloud and your local Grafana, this is not an issue – but here, a Prometheus agent pushing data to Grafana would be a better option.</p>
<p>Still, Grafana provides a <a target="_blank" href="https://grafana.com/docs/grafana-cloud/reference/allow-list/">list of public IP addresses</a> that you can use to setup your allow list.</p>
<p>So the following will work:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/oracle_cloud_ingress_rules.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Oracle Cloud Ingress Rules</em></p>
<p>But it is not the best. Instead, you want to restrict the specific IP addresses that can pull data from your exposed services. The prometheus exporter can be completely hidden from Grafana on port 9100. Instead we only need to expose the Prometheus scraper that listens on port 9000.</p>
<p>For this home lab, it is not a big deal having such services fully exposed. But if you have a server with sensitive data, you must restrict who can reach the service!</p>
<p>An alternative to the Prometheus endpoint is to push the data to Grafana <a target="_blank" href="https://grafana.com/docs/agent/latest/">by using a Grafana agent</a> but I will not cover that option here.</p>
<h1 id="heading-playbook-analysis">Playbook Analysis</h1>
<p>Ansible lets you have a single file with the playbook instructions, but eventually you will find that such a structure is difficult to maintain.</p>
<p>For my playbook I decided to keep the suggested structure:</p>
<pre><code class="lang-shell">tree -A 
.
├── inventory
│   └── cloud.yaml
├── oracle.yaml
├── roles
│   └── oracle
│       ├── files
│       │   ├── logrotate_prometheus-node-exporter
│       │   ├── prometheus-node-exporter
│       │   └── requirements_certboot.txt
│       ├── handlers
│       │   └── main.yaml
│       ├── meta
│       ├── tasks
│       │   ├── controller.yaml
│       │   ├── main.yaml
│       │   ├── metrics.yaml
│       │   └── nginx.yaml
│       ├── templates
│       │   ├── prometheus-node-exporter.service
│       │   ├── prometheus.service
│       │   └── prometheus.yaml
│       └── vars
│           └── main.yaml
└── site.yaml
</code></pre>
<p>Below is a brief description of how the content is organized:</p>
<ol>
<li><p>You can have more than one site. You control that inside the [site.yaml](file:///home/josevnz/OracleCloudHomeLab/site.yaml) file.</p>
</li>
<li><p>The host list is inside the inventory directory. You can have more than one inventory file or scripts to generate the hostlist, or a combination of both.</p>
</li>
<li><p>The roles/oracle group the tasks. We only have one role called 'oracle' because that's the cloud provider I'm focusing on here.</p>
</li>
<li><p>Our playbook uses metadata in the form of variables, with each one defined on the 'vars' directory. That way we can customize the behaviour of the playbook in multiple places:</p>
</li>
</ol>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-comment"># Common variables for my Oracle Cloud environments</span>
<span class="hljs-attr">controller_host:</span> <span class="hljs-string">XXXX.com</span>
<span class="hljs-attr">ssl_maintainer_email:</span> <span class="hljs-string">YYYYYY@ZZZZ.com</span>
<span class="hljs-attr">architecture:</span> <span class="hljs-string">arm64</span>
<span class="hljs-attr">prometheus_version:</span> <span class="hljs-number">2.38</span><span class="hljs-number">.0</span>
<span class="hljs-attr">prometheus_port:</span> <span class="hljs-number">9090</span>
<span class="hljs-attr">prometheus_node_exporter_nodes:</span> <span class="hljs-string">"['X-server1:<span class="hljs-template-variable">{{ node_exporter_port }}</span>', 'Y-server2:<span class="hljs-template-variable">{{ node_exporter_port }}</span>' ]"</span>
<span class="hljs-attr">node_exporter_version:</span> <span class="hljs-number">1.4</span><span class="hljs-number">.0</span>
<span class="hljs-attr">node_exporter_port:</span> <span class="hljs-number">9100</span>
<span class="hljs-attr">internal_network:</span> <span class="hljs-string">QQ.0.0.0/24</span>
</code></pre>
<p>The roles/oracle files directory contains files that can be copied as is to the remote directory. The templates' directory is similar, but the files in there can be customized for each host by using the <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html">Jinja templating language</a>.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># A template for the prometheus scraper configuration file</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">global:</span>
    <span class="hljs-attr">scrape_interval:</span> <span class="hljs-string">30s</span>
    <span class="hljs-attr">evaluation_interval:</span> <span class="hljs-string">30s</span>
    <span class="hljs-attr">scrape_timeout:</span> <span class="hljs-string">10s</span>
    <span class="hljs-attr">external_labels:</span>
        <span class="hljs-attr">monitor:</span> <span class="hljs-string">'oracle-cloud-metrics'</span>

<span class="hljs-attr">scrape_configs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">job_name:</span> <span class="hljs-string">'node-exporter'</span>
    <span class="hljs-attr">static_configs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">targets:</span> {{ <span class="hljs-string">prometheus_node_exporter_nodes</span> }}
    <span class="hljs-attr">tls_config:</span>
      <span class="hljs-attr">insecure_skip_verify:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>The 'tasks' directory is where we store our tasks, that is the actions that will modify the server state. Note that Ansible will not execute tasks if it's not necessary. The idea is that you can re-run a playbook as many times as needed and the final state will be the same.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Fragment of the nginx tasks file. See how we notify a handler to restart nginx after the SSL certificate is renewed.</span>
<span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">requirements</span> <span class="hljs-string">file</span>
  <span class="hljs-attr">ansible.builtin.copy:</span>
    <span class="hljs-attr">src:</span> <span class="hljs-string">requirements_certboot.txt</span>
    <span class="hljs-attr">dest:</span> <span class="hljs-string">/opt/requirements_certboot.txt</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_requirements</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Certbot</span>
  <span class="hljs-attr">pip:</span>
    <span class="hljs-attr">requirements:</span> <span class="hljs-string">/opt/requirements_certboot.txt</span>
    <span class="hljs-attr">virtualenv:</span> <span class="hljs-string">/opt/certbot/</span>
    <span class="hljs-attr">virtualenv_site_packages:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">virtualenv_command:</span> <span class="hljs-string">/usr/bin/python3</span> <span class="hljs-string">-m</span> <span class="hljs-string">venv</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_env</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Get</span> <span class="hljs-string">SSL</span> <span class="hljs-string">certificate</span>
  <span class="hljs-attr">command:</span>
    <span class="hljs-attr">argv:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/opt/certbot/bin/certbot</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nginx</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--agree-tos</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">-m</span> {{ <span class="hljs-string">ssl_maintainer_email</span> }}
      <span class="hljs-bullet">-</span> <span class="hljs-string">-d</span> {{ <span class="hljs-string">inventory_hostname</span> }}
      <span class="hljs-bullet">-</span> <span class="hljs-string">--non-interactive</span>
  <span class="hljs-attr">notify:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Restart</span> <span class="hljs-string">Nginx</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_install</span>
</code></pre>
<p>There is one special directory called 'handlers'. There we define actions that must happen if a task changes the state of our host.</p>
<p>We now have a picture of how all the pieces work together, so let's talk about some specific details.</p>
<h3 id="heading-firewall-provisioning">Firewall provisioning</h3>
<p>With Ansible, you can replace a sequence of commands like this:</p>
<pre><code class="lang-python">sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
</code></pre>
<p>With a <a target="_blank" href="https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html">firewalld module</a>:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Enable</span> <span class="hljs-string">HTTP</span> <span class="hljs-string">at</span> <span class="hljs-string">the</span> <span class="hljs-string">Linux</span> <span class="hljs-string">firewall</span>
  <span class="hljs-attr">firewalld:</span>
    <span class="hljs-attr">zone:</span> <span class="hljs-string">public</span>
    <span class="hljs-attr">service:</span> <span class="hljs-string">http</span>
    <span class="hljs-attr">permanent:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">enabled</span>
    <span class="hljs-attr">immediate:</span> <span class="hljs-literal">yes</span>
  <span class="hljs-attr">notify:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Reload</span> <span class="hljs-string">firewall</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">firewalld_https</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Enable</span> <span class="hljs-string">HTTPS</span> <span class="hljs-string">at</span> <span class="hljs-string">the</span> <span class="hljs-string">Linux</span> <span class="hljs-string">firewall</span>
  <span class="hljs-attr">firewalld:</span>
    <span class="hljs-attr">zone:</span> <span class="hljs-string">public</span>
    <span class="hljs-attr">service:</span> <span class="hljs-string">https</span>
    <span class="hljs-attr">permanent:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">enabled</span>
    <span class="hljs-attr">immediate:</span> <span class="hljs-literal">yes</span>
  <span class="hljs-attr">notify:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Reload</span> <span class="hljs-string">firewall</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">firewalld_https</span>
</code></pre>
<h3 id="heading-common-tasks-have-nice-replacements"><strong>Common tasks have nice replacements</strong></h3>
<p>So instead of running SUDO with a privileged command:</p>
<pre><code class="lang-python">sudo dnf install -y nginx
sudo systemctl enable nginx.service --now
</code></pre>
<p>You can have something like this:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># oracle.yaml file, which tells which roles to call, included from site.yaml</span>
<span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">hosts:</span> <span class="hljs-string">oracle</span>
  <span class="hljs-attr">serial:</span> <span class="hljs-number">2</span>
  <span class="hljs-attr">remote_user:</span> <span class="hljs-string">opc</span>
  <span class="hljs-attr">become:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">become_user:</span> <span class="hljs-string">root</span>
  <span class="hljs-attr">roles:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">oracle</span>
<span class="hljs-comment"># NGINX task (roles/oracle/tasks/nginx.yaml)</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Ensure</span> <span class="hljs-string">nginx</span> <span class="hljs-string">is</span> <span class="hljs-string">at</span> <span class="hljs-string">the</span> <span class="hljs-string">latest</span> <span class="hljs-string">version</span>
  <span class="hljs-attr">dnf:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">nginx</span> <span class="hljs-string">&gt;=</span> <span class="hljs-number">1.14</span><span class="hljs-number">.1</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">present</span>
    <span class="hljs-attr">update_cache:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">install_nginx</span>
<span class="hljs-comment"># And a handler that will restart NGINX after it gets modified (handlers/main.yaml)</span>
<span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Restart</span> <span class="hljs-string">Nginx</span>
  <span class="hljs-attr">ansible.builtin.service:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">restarted</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Reload</span> <span class="hljs-string">firewall</span>
  <span class="hljs-attr">ansible.builtin.systemd:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">firewalld.service</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">reloaded</span>
</code></pre>
<h2 id="heading-how-to-run-the-playbooks">How to Run the Playbooks</h2>
<p>Normally you don't wait to have the whole playbook written, but you run the pieces you need in the proper order. At some point you will have your whole playbook finished and ready to go.</p>
<h3 id="heading-make-sure-the-playbook-behaves-properly-with-check-before-making-any-changes">Make sure the playbook behaves properly with <code>--check</code> before making any changes</h3>
<p>The very first step is to check your playbook file for errors. For that you can use yamllint:</p>
<pre><code class="lang-shell">yamllint roles/oracle/tasks/main.yaml
</code></pre>
<p>But doing this for every yaml file in your playbook can be tedious an error-prone. As an alternative, you can run the playbook in a 'dry-run' mode, to see what will happen without actually making any changes:</p>
<p><a target="_blank" href="https://asciinema.org/a/537302"><img src="https://asciinema.org/a/537302.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<p>Another way to gradually test a complex playbook is by executing a specific task by using a tag or group of tags. That way you can do controlled execution of your playbook:</p>
<p><em>Keep in mind that this will not execute any dependencies that you may have defined on you playbook, tough</em>:</p>
<p><a target="_blank" href="https://asciinema.org/a/537303"><img src="https://asciinema.org/a/537303.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<h3 id="heading-use-ansible-lint-when-ansible-playbook-check-is-not-good-enough"><strong>Use Ansible-lint when ansible-playbook --check is not good enough</strong></h3>
<p>Some errors are more subtle and will not get caught with <code>ansible-playbook --check</code>. To get a more complete check on your playbooks before minor issues become a headache you can use <a target="_blank" href="https://ansible-lint.readthedocs.io/philosophy/">ansible-lint</a>. So let's get it installed:</p>
<pre><code class="lang-shell">python3 -m venv ~/virtualenv/ansiblelint &amp;&amp; . ~/virtualenv/ansiblelint/bin/activate
pip install --upgrade pip
pip install --upgrade wheel
pip install ansible-lint
</code></pre>
<p>Now we can check the playbook:</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible-lint site.yaml 
WARNING  Overriding detected file kind 'yaml' with 'playbook' for given positional argument: site.yaml
WARNING  Listing 1 violation(s) that are fatal
syntax-check[specific]: couldn't resolve module/action 'firewalld'. This often indicates a misspelling, missing collection, or incorrect module path.
roles/oracle/tasks/nginx.yaml:2:3
</code></pre>
<p>Strange, firewalld is available on our Ansible installation. What else was installed by ansible-lint?</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible --version
ansible [core 2.14.0]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/josevnz/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/josevnz/virtualenv/ansiblelint/lib64/python3.9/site-packages/ansible
  ansible collection location = /home/josevnz/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/josevnz/virtualenv/ansiblelint/bin/ansible
  python version = 3.9.9 (main, Nov 19 2021, 00:00:00) [GCC 10.3.1 20210422 (Red Hat 10.3.1-1)] (/home/josevnz/virtualenv/ansiblelint/bin/python3)
  jinja version = 3.1.2
  libyaml = True
</code></pre>
<p>Ansible-lint installed its own ansible [core], and firewalld is part of <a target="_blank" href="https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html">ansible.posix collection</a>. We will use <a target="_blank" href="https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html">Ansible Galaxy</a> to install it:</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ which ansible-galaxy
~/virtualenv/ansiblelint/bin/ansible-galaxy
(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible-galaxy collection install ansible.posix
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/download/ansible-posix-1.4.0.tar.gz to /home/josevnz/.ansible/tmp/ansible-local-18099xpw_8usc/tmp8msc9uf5/ansible-posix-1.4.0-_f17f525
Installing 'ansible.posix:1.4.0' to '/home/josevnz/.ansible/collections/ansible_collections/ansible/posix'
ansible.posix:1.4.0 was installed successfully
</code></pre>
<p>Running it again:</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible-lint site.yaml 
WARNING  Overriding detected file kind 'yaml' with 'playbook' for given positional argument: site.yaml
WARNING  Listing 50 violation(s) that are fatal
name[play]: All plays should be named. (warning)
oracle.yaml:2

fqcn[action-core]: Use FQCN for builtin module actions (service).
roles/oracle/handlers/main.yaml:2 Use `ansible.builtin.service` or `ansible.legacy.service` instead.

fqcn[action-core]: Use FQCN for builtin module actions (command).
roles/oracle/handlers/main.yaml:6 Use `ansible.builtin.command` or `ansible.legacy.command` instead.
</code></pre>
<p>Some warnings are pedantic ('Use FQCN for builtin module actions (command)') and others require attention (Commands should not change things if nothing needs doing.).</p>
<p>Ansible-lint found many smells on the playbook, there is one option to re-write the files and correct some of these errors automatically:</p>
<p><a target="_blank" href="https://asciinema.org/a/538053"><img src="https://asciinema.org/a/538053.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<p>There are some guidelines you can <a target="_blank" href="https://ansible-lint.readthedocs.io/profiles/#production">follow to correct these issues</a>. Below are some that can be directly applied to the warnings we got earlier:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/ansible_error_fixes.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note that all the errors are easy to solve. Some commands decide on their own if they should make changes or not but have a hard time communicating back to Ansible:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Get</span> <span class="hljs-string">SSL</span> <span class="hljs-string">certificate</span>
  <span class="hljs-attr">ansible.builtin.shell:</span>
    <span class="hljs-attr">argv:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/opt/certbot/bin/certbot</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nginx</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--agree-tos</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">-m</span> <span class="hljs-string">"<span class="hljs-template-variable">{{ ssl_maintainer_email }}</span>"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">-d</span> <span class="hljs-string">"<span class="hljs-template-variable">{{ inventory_hostname }}</span>"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--non-interactive</span>
  <span class="hljs-attr">notify:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Restart</span> <span class="hljs-string">Nginx</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_install</span>
</code></pre>
<p>In our case, certboot prints a message if the certificate is not yet due for renewal. If that output is missing then we trigger the Nginx restart (see <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#defining-changed">defining changed</a>):</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Get</span> <span class="hljs-string">SSL</span> <span class="hljs-string">certificate</span>
  <span class="hljs-attr">ansible.builtin.shell:</span>
    <span class="hljs-attr">argv:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/opt/certbot/bin/certbot</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nginx</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--agree-tos</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">-m</span> {{ <span class="hljs-string">ssl_maintainer_email</span> }}
      <span class="hljs-bullet">-</span> <span class="hljs-string">-d</span> {{ <span class="hljs-string">inventory_hostname</span> }}
      <span class="hljs-bullet">-</span> <span class="hljs-string">--non-interactive</span>
  <span class="hljs-attr">register:</span> <span class="hljs-string">certbot_output</span> <span class="hljs-comment"># Registers the certbot output.</span>
  <span class="hljs-attr">changed_when:</span> 
    <span class="hljs-bullet">-</span> <span class="hljs-string">'"Certificate not yet due for renewal" not in certbot_output.stdout'</span>
  <span class="hljs-attr">notify:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Restart</span> <span class="hljs-string">Nginx</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_install</span>
</code></pre>
<p>I do want to use shell, as I need to expand the variable for certbot, but ansible-lint is still not happy:</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible-lint site.yaml
WARNING  Overriding detected file kind 'yaml' with 'playbook' for given positional argument: site.yaml
WARNING  Listing 1 violation(s) that are fatal
command-instead-of-shell: Use shell only when shell functionality is required.
roles/oracle/tasks/nginx.yaml:47 Task/Handler: Get SSL certificate

You can skip specific rules or tags by adding them to your configuration file:
# .config/ansible-lint.yml
warn_list:  # or 'skip_list' to silence them completely
  - command-instead-of-shell  # Use shell only when shell functionality is required.

                   Rule Violation Summary                    
 count tag                      profile rule associated tags 
     1 command-instead-of-shell basic   command-shell, idiom 

Failed after min profile: 1 failure(s), 0 warning(s) on 8 files.
</code></pre>
<p>Time to treat this error as a warning, as I know they are not issues, by creating a <code>.config/ansible-lint.yml</code>:</p>
<pre><code class="lang-shell">(ansiblelint) [josevnz@dmaf5 OracleCloudHomeLab]$ ansible-lint site.yaml
WARNING  Overriding detected file kind 'yaml' with 'playbook' for given positional argument: site.yaml
WARNING  Listing 1 violation(s) that are fatal
command-instead-of-shell: Use shell only when shell functionality is required. (warning)
roles/oracle/tasks/nginx.yaml:47 Task/Handler: Get SSL certificate


                        Rule Violation Summary                         
 count tag                      profile rule associated tags           
     1 command-instead-of-shell basic   command-shell, idiom (warning) 

Passed with min profile: 0 failure(s), 1 warning(s) on 8 files.
</code></pre>
<p>Much better now, the warning is not treated as an error.</p>
<h3 id="heading-jinja-best-practices"><strong>Jinja best practices</strong></h3>
<p>If you plan to use variables and Jinja templates, make sure you quote them (example: "dest: /opt/prometheus-{{ prometheus_version }}.linux-{{ architecture }}.tar.gz")</p>
<h3 id="heading-constrain-where-the-playbook-runs-with-limit-and-tags">Constrain where the playbook runs with <code>--limit</code> and <code>--tags</code></h3>
<p>Say that you are only interested in running your playbook on a certain host. In that case, you can also do that by using the <code>--limit</code> flag:</p>
<pre><code class="lang-shell">ansible-playbook --inventory inventory --limit fido.yourcompany.com --tags certbot_renew site.yaml
</code></pre>
<p><a target="_blank" href="https://asciinema.org/a/537304"><img src="https://asciinema.org/a/537304.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<p>Here we did run only a task tagged certbot_renew on the host fido.yourcompany.com.</p>
<h3 id="heading-how-to-deal-with-a-real-issue">How to deal with a real issue</h3>
<p>Let's make this interesting: say that I was eager to update one of my requirements for certboot, and I changed versions if pip to '22.3.1':</p>
<pre><code class="lang-text">pip==22.3.1
wheel==0.38.4
certbot==1.32.0
certbot-nginx==1.32.0
</code></pre>
<p>When I run the playbook we have a failure:</p>
<p><a target="_blank" href="https://asciinema.org/a/537318"><img src="https://asciinema.org/a/537318.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<p>This is an issue with the versions if specified on the <a target="_blank" href="https://github.com/josevnz/OracleCloudHomeLab/blob/main/roles/oracle/files/requirements_certboot.txt">requirements_certboot.txt</a> file. When you install a Python library using a virtual environment you can specify versions like this:</p>
<p>pip==22.3.1 wheel==0.38.1 certbot==1.23.0 certbot-nginx==1.23.0</p>
<p>To fix the issue, we will revert the versions used on the file and then re-run the requirements file and Certbot installation task:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Certbot</span>
  <span class="hljs-attr">pip:</span>
    <span class="hljs-attr">requirements:</span> <span class="hljs-string">/opt/requirements_certboot.txt</span>
    <span class="hljs-attr">virtualenv:</span> <span class="hljs-string">/opt/certbot/</span>
    <span class="hljs-attr">virtualenv_site_packages:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">virtualenv_command:</span> <span class="hljs-string">/usr/bin/python3</span> <span class="hljs-string">-m</span> <span class="hljs-string">venv</span>
    <span class="hljs-attr">state:</span> <span class="hljs-string">forcereinstall</span>
  <span class="hljs-attr">tags:</span> <span class="hljs-string">certbot_env</span>
</code></pre>
<pre><code class="lang-shell">ansible-playbook --inventory inventory --tags certbot_env site.yaml
</code></pre>
<p>See it in action:</p>
<p><a target="_blank" href="https://asciinema.org/a/537320"><img src="https://asciinema.org/a/537320.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<h3 id="heading-how-to-run-the-whole-playbook">How to run the whole playbook</h3>
<pre><code class="lang-shell">ansible-playbook --inventory inventory site.yaml
</code></pre>
<p>It is time to run the whole playbook:</p>
<p><a target="_blank" href="https://asciinema.org/a/537322"><img src="https://asciinema.org/a/537322.svg" alt="asciicast" width="600" height="400" loading="lazy"></a></p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>This tutorial only touches the surface of what you can do with Ansible. So below are a few more resources you should explore to learn more:</p>
<ul>
<li><p>Improving inventories: <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-dynamic-inventories">How to create dynamic inventory files in Ansible</a>, <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-dynamic-inventory-python">How to write a Python script to create dynamic Ansible inventories</a>, <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-plugin-inventory-files">How to write an Ansible plugin to create inventory files</a></p>
</li>
<li><p>Sometimes your playbooks will run slow, and you may need to <a target="_blank" href="https://www.redhat.com/sysadmin/ansible-callback-plugins-metrics">Assess resource consumption with Ansible callback plugins</a>.</p>
</li>
<li><p>And there will be a time <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_debugger.html">when deeper debugging</a> is needed.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Common Attacks on SSL/TLS – and How to Protect Your System ]]>
                </title>
                <description>
                    <![CDATA[ By Megan Kaczanowski The SSL and TLS protocols are frequently attacked. And understanding past attacks can inform your knowledge as a defender and help you secure current systems. It can also help you predict the direction of future attacks. So here'... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/attacks-on-ssl-tls-and-how-to-protect-your-system/</link>
                <guid isPermaLink="false">66d46043a326133d12440a3d</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #infosec ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TLS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 29 Aug 2022 21:17:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/cybersecurity-by-Christiaan-Colen-creative-commons-free-to-use.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Megan Kaczanowski</p>
<p>The SSL and TLS protocols are frequently attacked. And understanding past attacks can inform your knowledge as a defender and help you secure current systems. It can also help you predict the direction of future attacks.</p>
<p>So here's a summary of some of the most famous attacks targeting these protocols:</p>
<h2 id="heading-browser-exploit-against-ssltls-beast">Browser Exploit Against SSL/TLS (BEAST):</h2>
<p>BEAST (disclosed in 2011) allowed a man-in-the-middle attacker to discover encrypted information from an SSL/TLS session. It impacted SSL 3.0 and TLS 1.0.</p>
<p>This attack depended on the implementation of the block cipher used by TLS. The implementation used CBC, Cipher Block Chaining mode. This involves XORing each block of plaintext (except the first) with the previous block of ciphertext, then using the encryption algorithm on the block.</p>
<p>The first block is XORed with an IV (initialization vector). Much of the mode's security depends on the IV being truly random. But TLS 1.0 didn't randomly generate IVs – it just used the last block of ciphertext from the previous message. That meant that anyone able to snoop on the encrypted traffic had a copy of the IV.</p>
<p>An attacker who could snoop on the encrypted traffic could launch a chosen plaintext attack by guessing a block of data, XORing it with the (known) IV and the previous block of ciphertext, and injecting the created block into the session. This allowed the attacker to check if the entire block was correct.</p>
<p>Given this, the flaw was seen as largely theoretical until BEAST was released. BEAST found a way to shift the cipher block boundaries to isolate one byte of a message at a time until it had been guessed.</p>
<p>That, and the fact that HTTP messages are typically standardized so that an attacker would know where in the message sensitive information (like the session cookie) was transmitted, allowed an attacker to brute force compromise a session cookie.</p>
<p>While the attack was theoretically extremely interesting, and generated a lot of interest, it only works if the attacker can insert malicious code into a page and violate the same-origin policy. If the attacker had this much access to your system, they would also have a number of attacks they could attempt, many of which are far less complicated to execute.</p>
<h3 id="heading-mitigation-measures-for-ssltls-attacks">Mitigation Measures for SSL/TLS Attacks:</h3>
<ol>
<li><p>(Safest) Only allow TLS 1.1 or 1.2 since they addressed the vulnerability. However, at the time, most websites and browsers didn't support TLS 1.1. or 1.2.</p>
</li>
<li><p>As TLS supported both a block cipher and a stream cipher, switch to the stream cipher (RC4). However, in 2013 it was demonstrated that RC4 was insecure, and in 2015 it was officially banned (by the Internet Engineering Task Force, or IETF).</p>
</li>
<li><p>Use a different block cipher mode. Unfortunately, TLS 1.0 didn't support any other modes.</p>
</li>
<li><p>Insert packets of length 0. Essentially, as a packet of length 0 would be padded to the block size, it becomes a packet of just padding for the sender, but is immediately discarded by the recipient. These blocks would be used as IVs for the next message, solving the problem of insecure IVs. This option was largely unused as it caused interoperability issues with some SSL stacks, notably including Internet Explorer 6.0. OpenSSL implemented this, but disabled it by default.</p>
</li>
<li><p>Practice defense in depth to prevent attackers from getting man-in-the-middle access to a victim network.</p>
</li>
</ol>
<h3 id="heading-sourcesfurther-information">Sources/Further Information:</h3>
<ul>
<li><p><a target="_blank" href="https://www.netsparker.com/blog/web-security/how-the-beast-attack-works/">How the BEAST Attack Works</a></p>
</li>
<li><p><a target="_blank" href="https://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art027">An Illustrated Guide to the BEAST Attack</a></p>
</li>
<li><p><a target="_blank" href="https://vnhacker.blogspot.com/2011/09/beast.html">Original Write Up of BEAST</a></p>
</li>
<li><p><a target="_blank" href="https://www.nccgroup.com/us/our-research/attacks-on-ssl/">A Comprehensive Study of BEAST, CRIME, TIME, BREACH, LUCKY 13 &amp; RC4 Biases</a></p>
</li>
</ul>
<h2 id="heading-heartbleed-vulnerability">Heartbleed Vulnerability:</h2>
<p>Heartbleed (introduced in 2012/disclosed in April 2014) was a vulnerability in the heartbeat extension of the OpenSSL library (this is used to keep a connection opened).</p>
<p>This library is used largely for servers running Apache and NGINX (at the time of disclosure, roughly 17% of the internet's 'secure' (using SSL/TLS) websites were vulnerable), but impacted any server which depended on the vulnerable version of OpenSSL.</p>
<p>Essentially, the client sends a message to the server which contains the response it requests and the size of the response. The server would respond with the requested data in the size it was requested (see below for an explanation from xkcd).</p>
<p><img src="https://megankaczanowski.com/content/images/2020/12/Screen-Shot-2020-12-29-at-4.16.21-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The vulnerability was that the server would not check that the request was actually the same size as its stated size. If the user sent a requested response (for example 'bird') which was shorter than the requested length (500 letters), the server would 'pad' the response with data from its memory to meet the length requirement, potentially leaking sensitive memory information.</p>
<p><img src="https://megankaczanowski.com/content/images/2020/12/Screen-Shot-2020-12-29-at-4.16.31-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://megankaczanowski.com/content/images/2020/12/Screen-Shot-2020-12-29-at-4.16.38-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>https://xkcd.com/1354/</em></p>
<p>This leaked data would be unencrypted and could contain anything – sensitive credentials, documents, and so on.</p>
<p>But in order to successfully exploit this bug, several things needed to happen: the site had to have implemented SSL, it needed to be running a vulnerable version of OpenSSL (the vulnerable versions were between 1.0.1 and 1.0.1f), the attacker needed to have had access to the environment between finding out the bug exists and it being patched, and there needed to have been something useful in memory at the time the attacker carried out the attack. This is relatively more difficult, though far from impossible.</p>
<p>Unfortunately, since the exploitation doesn't leave any abnormal traces in logs, it's hard to know if or how often this bug was actually exploited.</p>
<p>Also, this doesn't account for the danger of an attacker having previous pcaps of traffic and pulling the site's private key in an attack. This means they could have decrypted large amounts of sensitive data, causing a serious breach.</p>
<p>If intelligence agencies were able to pull off this type of attack, it's likely it would never be publicly released.</p>
<h3 id="heading-mitigation-measures-for-heartbleed">Mitigation Measures for Heartbleed:</h3>
<ul>
<li>Upgrade OpenSSL to the latest version, patching the vulnerability (the vulnerable versions were between 1.0.1 and 1.0.1f).</li>
</ul>
<h3 id="heading-sourcesfurther-reading">Sources/Further Reading:</h3>
<ul>
<li><p><a target="_blank" href="https://blog.malwarebytes.com/exploits-and-vulnerabilities/2019/09/everything-you-need-to-know-about-the-heartbleed-vulnerability/">5 Years Later, Heartbleed Vulnerability Still Unpatched</a></p>
</li>
<li><p><a target="_blank" href="https://xkcd.com/1354/">XKCD Heartbleed</a></p>
</li>
<li><p><a target="_blank" href="https://www.troyhunt.com/everything-you-need-to-know-about3/">Everything you need to know about the Heartbleed Bug</a></p>
</li>
</ul>
<h2 id="heading-padding-oracle-on-downgraded-legacy-encryption-poodle">Padding Oracle On Downgraded Legacy Encryption (POODLE):</h2>
<p>POODLE (disclosed in September 2014) took advantage of a flaw in SSL3.0. In order to support legacy systems, some systems continued to offer support for SSL 3.0, even though it had been replaced by newer versions.</p>
<p>For the attack to be successful, the attacker needed to be able to control parts of the client side of the SSL connection and needed to have visibility of the resulting ciphertext (the most common way to have this access is to act as a man-in-the-middle).</p>
<p>This attack, while powerful, does require a separate attack to gain this access.</p>
<p>During a typical handshake negotiation, the client and server will work together to find a protocol which works for both to communicate. They'll start with the highest protocol they both offer and work down (so the client may offer TLS 1.2, and the server may respond with TLS 1.1).</p>
<p>But if the connection fails (either due to an attacker or a network connection problem), the client server will downgrade to the lowest protocol they offer, likely SSL 3.0. This is a 'feature' offered so that servers and clients at different stages of advancement can communicate.</p>
<p>SSL3.0 uses either RC4 (stream cipher) or a block cipher in CBC mode for encryption. RC4 was well-known, even at the time, for having a number of flaws, including that if the same secret (like a cookie) was sent repeatedly, more and more information about it would leak.</p>
<p>CBC mode requires that the message length is a multiple of the block size or that padding is used to fulfill the length condition. This means that padding is frequently used, and in the SSL 3.0 implementation it isn't verified that it hasn't changed in transit.</p>
<p>Essentially, while the message is hashed before sending and at the receiving end, and the re-compiled hash is compared to ensure message integrity, the padding is not included.</p>
<p>The only specification for padding is that the last byte needs to be the padding length. Therefore, an attacker can replace the padding and it will still be accepted, as long as they get the last digit correct.</p>
<p>If an attacker knows the location of the data they're trying to decrypt (for example an HTTP session cookie, which is typically sent in the same part of the block each time and is therefore easy to locate), they can copy it over into the final block, replacing the padding.</p>
<p>Then, the receiver will XOR the padded block with the previous block's ciphertext (which the attacker can see) and will only accept the data if the last byte matches the padding's length.</p>
<p>Essentially this attack makes brute-forcing SSL feasible. Whereas it would be practically impossible to brute force SSL without any information, this attack allows for recovering each byte after a maximum of 256 attempts per byte. That means that, in a few minutes, an attacker could compromise a session cookie or other sensitive information.</p>
<h3 id="heading-mitigation-measures-for-poodle">Mitigation Measures for POODLE:</h3>
<ul>
<li><p>Disabling SSL 3.0 is the only complete mitigation of POODLE. However, some sites only supported SSL 3.0.</p>
</li>
<li><p>An alternative is to use the TLS_FALLBACK_SCV cipher suite. This suite allows a server to fall back to earlier protocols, but rather than dropping immediately to SSL 3.0, the client can specify a preference. One problem with this suite is that it wasn't broadly supported when it was introduced (limited to largely Google services). Additionally, if the only option the server supports is SSL 3.0, POODLE attacks are still possible. However, it means that an attacker can't force a downgrade on a connection with a server which supports alternative protocols.</p>
</li>
<li><p>Practice defense in depth to prevent attackers from getting man-in-the-middle access to a victim network. While the attack is dangerous, it requires man-in-the-middle access, making it much harder to exploit than the remotely exploitable Heartbleed.</p>
</li>
</ul>
<h3 id="heading-sourcesfurther-information-1">Sources/Further Information:</h3>
<ul>
<li><p><a target="_blank" href="https://www.troyhunt.com/everything-you-need-to-know-about/">Everything you need to know about the POODLE bug</a></p>
</li>
<li><p><a target="_blank" href="https://templatelab.com/ssl-poodle/">This POODLE Bites: Exploiting the SSL 3.0 Fallback</a></p>
</li>
<li><p><a target="_blank" href="https://www.acunetix.com/blog/web-security-zone/what-is-poodle-attack/">What is the POODLE Attack?</a></p>
</li>
<li><p><a target="_blank" href="https://us-cert.cisa.gov/ncas/alerts/TA14-290A">CISA SSL 3.0 Protocol Vulnerability</a></p>
</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Understanding past attacks on TLS and SSL can both inform your knowledge as a defender and help you secure your systems.</p>
<p>Often systems are out of date, or legacy applications may require use of outdated protocols. This means that even older attacks may be successful if defenses aren't applied appropriately.</p>
<p>In many cases, working in corporate security requires having enough information to make informed decisions and recommendations. If, for example, a legacy app requires using an outdated protocol, knowledge of attacks like POODLE and Heartbleed can help you make effective recommendations about how to secure that application, rather than making general recommendations like 'update to a newer protocol' (which might be impossible).</p>
<p>Typically, as a security analyst, you're trying to balance business needs with technical capabilities, and making recommendations based on the organization's risk level. That might mean saying that a legacy app shouldn't be run anymore, or it may mean making recommendations on how to secure the application as much as possible, given that it needs to use an insecure protocol.</p>
<p>Understanding past TLS/SSL attacks can also help you predict the direction of future attacks. Since Heartbleed and POODLE (in 2014), we've seen attacks like FREAK and Logjam in 2015 and Sweet32 in 2016. We'll likely continue to see additional attacks.</p>
<p>Understanding the fundamentals of how TLS and SSL work, and how they've been attacked in the past can help you predict or understand future attacks.</p>
<p>Cover photo: "cybersecurity" by Christian Colen</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Your Connection is Not Private Error – How to Fix in Chrome ]]>
                </title>
                <description>
                    <![CDATA[ If you log on to a website and your browser shows the “Your connection is not private” error, the browser is trying to warn you to stay off the website. In that case, the browser has run a check on the SSL (secure socket layer) certificate and found... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/your-connection-is-not-private-error-how-to-fix-in-chrome/</link>
                <guid isPermaLink="false">66adf297f452caf50fb1fe2b</guid>
                
                    <category>
                        <![CDATA[ browser ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Chrome ]]>
                    </category>
                
                    <category>
                        <![CDATA[ privacy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Thu, 07 Jul 2022 16:03:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/castle-1290860_1280.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you log on to a website and your browser shows the “Your connection is not private” error, the browser is trying to warn you to stay off the website.
<img src="https://www.freecodecamp.org/news/content/images/2022/07/Annotation-2022-07-06-111823-1.png" alt="Annotation-2022-07-06-111823-1" width="600" height="400" loading="lazy"></p>
<p>In that case, the browser has run a check on the SSL (secure socket layer) certificate and found a problem with it – the SSL could have expired or might not have been installed at all.</p>
<p>In some cases, the problem could be because of your browser and not the website. So, in this article, I will show you how to fix the “Your connection is not private” error on a Chrome browser.</p>
<h2 id="heading-what-well-cover">What We'll Cover</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-fix-the-your-connection-is-not-private-error-on-a-chrome-browser">How to Fix the “Your connection is not private” Error on a Chrome Browser</a><ul>
<li><a class="post-section-overview" href="#heading-reload-the-web-page">Reload the Web Page</a> </li>
<li><a class="post-section-overview" href="#heading-clear-chromes-cache">Clear Chrome’s Cache</a></li>
<li><a class="post-section-overview" href="#heading-make-sure-your-computers-date-and-time-are-correct">Make Sure your Computer’s Date and Time are Correct</a></li>
<li><a class="post-section-overview" href="#heading-disable-your-antivirus-and-vpn">Disable your Antivirus and VPN</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></li>
</ul>
<h2 id="heading-how-to-fix-the-your-connection-is-not-private-error-on-a-chrome-browser">How to Fix the “Your connection is not private” Error on a Chrome Browser</h2>
<h3 id="heading-reload-the-web-page">Reload the Web Page</h3>
<p>The first thing I would advise you do is to reload the page.</p>
<p>Reloading the web page is the old trick everyone tries if there is a problem with that web page. </p>
<p>In addition, there are chances that SSL-related work is going on with the website, so if you wait a while and reload the page, the issue could disappear.</p>
<p>If reloading doesn’t fix the issue for you, proceed to other solutions in this article.</p>
<h3 id="heading-clear-chromes-cache">Clear Chrome’s Cache</h3>
<p>The SSL data of the website in your Chrome browser cache might have expired. So if you clear the cache, the error may go away.</p>
<p>Follow the steps below to clear your Chrome browser cache:</p>
<p><strong>Step 1</strong>: Click the 3 vertical dots on the top-right corner and select Settings:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss10-1.png" alt="ss10-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2</strong>: Click the “Privacy and Security” tab on the left sidebar and select “Clear browsing data”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss11-1.png" alt="ss11-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3</strong>: Select Cache and Cookies, then click “Clear data”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss12-1.png" alt="ss12-1" width="600" height="400" loading="lazy"></p>
<h3 id="heading-make-sure-your-computers-date-and-time-are-correct">Make Sure your Computer’s Date and Time are Correct</h3>
<p>If your computer clock is behind or ahead, your browser will show you a “Your connection is not secure” error.</p>
<p>These days, the error message has become more accurate in Chrome:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/Annotation-2022-06-06-072807.png" alt="Annotation-2022-06-06-072807" width="600" height="400" loading="lazy"></p>
<p>In this case, you should set your date and time to the correct one and make it automatic, so nothing readjusts it again:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss.png" alt="ss" width="600" height="400" loading="lazy"></p>
<h3 id="heading-disable-your-antivirus-and-vpn">Disable your Antivirus and VPN</h3>
<p>Some Antivirus programs with SSL scanning features can make your browser show the “Your connection is not private” error if they detect any irregularity with the SSL certificate of a website.</p>
<p>In the same vein, a VPN (virtual private network) conceals your IP address and other information. The problem is that the privacy a VPN gives you could have a negative effect on some sites' SSL.</p>
<p>Due to this, you should consider disabling your antivirus and VPN programs, at least temporarily, to see if that fixes the error.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Other fixes that might get rid of the “Your connection is not private” error for you include:</p>
<ul>
<li>Trying to access the web page in incognito mode. In Chrome, you can open an incognito tab by pressing <code>CTRL</code> + <code>SHIFT</code> + <code>N</code>.</li>
<li>Restarting your Router</li>
<li>Restarting your computer</li>
<li>Updating your OS</li>
</ul>
<p>If all the fixes fail to work, the problem could be from the website. This means there is a problem with the website’s SSL certificate. So, try to contact the site admin. </p>
<p>If you find no admin to contact, you should stay off that website and make sure you don’t share sensitive information with the site.</p>
<p>If you’re a site admin and your users complain about this error, I wrote <a target="_blank" href="https://www.freecodecamp.org/news/an-ssl-error-has-occurred-how-to-fix-certificate-verification-error/#howtofixsslerrorasasiteowner">an article on how you can restore your site’s SSL</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An SSL Error Has Occurred – How to Fix Certificate Verification Error ]]>
                </title>
                <description>
                    <![CDATA[ If you’re surfing the net and an SSL error occurs on a website you're trying to visit, your browser will warn you by showing you an error messages or signal. This error is mostly caused by an expired or bad SSL certificate. It also occurs when the br... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-ssl-error-has-occurred-how-to-fix-certificate-verification-error/</link>
                <guid isPermaLink="false">66adf0727550d4f37c201997</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Windows ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 06 Jul 2022 17:51:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/ssl.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’re surfing the net and an SSL error occurs on a website you're trying to visit, your browser will warn you by showing you an error messages or signal.</p>
<p>This error is mostly caused by an expired or bad SSL certificate. It also occurs when the browser can’t verify the legitimacy of a website’s SSL certificate.</p>
<p>That error message could be a giant one like this:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/Annotation-2022-07-06-111823.png" alt="Annotation-2022-07-06-111823" width="600" height="400" loading="lazy"></p>
<p>The browser could also show you a signal in the address bar like this: 
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss1-1.png" alt="ss1-1" width="600" height="400" loading="lazy"></p>
<p>In this article, I will show you what an SSL certificate is. I will also show you how to fix SSL errors as a site owner and as a user.</p>
<h2 id="heading-what-well-cover">What We'll Cover</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-ssl-and-why-is-it-used">What is SSL and Why is it Used?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-fix-ssl-error-as-a-site-owner">How to Fix SSL Error as a Site Owner</a><ul>
<li><a class="post-section-overview" href="#heading-purchase-an-ssl-certificate">Purchase an SSL Certificate</a></li>
<li><a class="post-section-overview" href="#heading-make-sure-you-turn-on-ssl-on-your-website">Make sure you Turn on SSL on your Website</a></li>
<li><a class="post-section-overview" href="#heading-if-your-website-is-hosted-on-github-pages">If your website is hosted on Github pages…</a></li>
<li><a class="post-section-overview" href="#heading-if-your-website-is-hosted-on-netlify">If your website is hosted on Netlify…</a></li>
<li><a class="post-section-overview" href="#heading-if-your-website-is-a-wordpress-website">If your website is a WordPress website…</a></li>
<li><a class="post-section-overview" href="#heading-contact-your-hosting-provider">Contact your Hosting Provider</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-fix-ssl-error-as-a-user">How to Fix SSL Error as a User</a><ul>
<li><a class="post-section-overview" href="#heading-make-sure-your-date-and-time-are-correct">Make Sure your Date and Time are Correct </a></li>
<li><a class="post-section-overview" href="#heading-clear-saved-ssls-on-your-computer">Clear Saved SSLs on your Computer</a></li>
<li><a class="post-section-overview" href="#heading-clear-your-browsers-cache-and-cookies">Clear your Browser’s Cache and Cookies</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a><h2 id="heading-what-is-ssl-and-why-is-it-used">What is SSL and Why is it Used?</h2>
</li>
</ul>
<p>SSL stands for secure socket layer. It is the international standard security technology for keeping the sharing of information safe between a website and its users.</p>
<p>In the Chrome browser, when a website has a valid SSL, a locked padlock is shown in the address bar – indicating that any information the user shares with that website is encrypted.
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss2-1.png" alt="ss2-1" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-fix-ssl-error-as-a-site-owner">How to Fix SSL Error as a Site Owner</h2>
<p>If you are a site owner and your users are complaining that your website shows SSL errors, you can fix the issue with any of the methods explained below:</p>
<h3 id="heading-purchase-an-ssl-certificate">Purchase an SSL Certificate</h3>
<p>If your website doesn’t have an SSL certificate installed, any modern browser your user is using will alert them your site is not secure.</p>
<p>In this case, you should purchase an SSL certificate from any of the providers out there.</p>
<p>By the way, you can buy an SSL certificate from companies that sell domain names. You can also buy an SSL from <a target="_blank" href="https://sectigo.com/">Sectigo</a> or <a target="_blank" href="https://www.ssls.com/">SSLs</a>.</p>
<h3 id="heading-make-sure-you-turn-on-ssl-on-your-website">Make sure you Turn on SSL on your Website</h3>
<p>If you’ve purchased and installed an SSL but your website still shows SSL errors, it could happen because you unknowingly didn’t turn on SSL.</p>
<h3 id="heading-if-your-website-is-hosted-on-github-pages">If your website is hosted on Github pages…</h3>
<p><strong>Step 1</strong>: Navigate to your site repo and click Settings:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss3-1.png" alt="ss3-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2</strong>: Click on Pages on the left sidebar:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss4-1.png" alt="ss4-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3</strong>: Tick “Enforce HTTPS”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss5-1.png" alt="ss5-1" width="600" height="400" loading="lazy"></p>
<p>This is required for sites using GitHub’s default domain (example.github.io). </p>
<p>Even if you’re using a custom domain, make sure that box is ticked.</p>
<h3 id="heading-if-your-website-is-hosted-on-netlify">If your website is hosted on Netlify…</h3>
<p><strong>Step 1</strong>: Click on the site with an SSL error:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss6-1.png" alt="ss6-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2</strong>: Click on “Site Settings”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss7-1.png" alt="ss7-1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3</strong>: Click “Domain Management”, and then HTTPS on the left sidebar. Make sure there’s the message “Your site has HTTPS enabled”.
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss8-1.png" alt="ss8-1" width="600" height="400" loading="lazy"></p>
<h3 id="heading-if-your-website-is-a-wordpress-website">If your website is a WordPress website…</h3>
<p>If you have a WordPress website with an SSL error, install the <a target="_blank" href="https://wordpress.org/plugins/wp-force-ssl/">Force SSL plugin</a> on your website
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss9-1.png" alt="ss9-1" width="600" height="400" loading="lazy"></p>
<h3 id="heading-contact-your-hosting-provider">Contact your Hosting Provider</h3>
<p>If every method discussed above fails to work for you, then you should contact the customer service of your hosting provider.</p>
<h2 id="heading-how-to-fix-ssl-error-as-a-user">How to Fix SSL Error as a User</h2>
<p>If you visit a website and you’re getting any SSL-related errors, there are some things you can do as a user. That’s because the problem is not always caused by the website – as long as an SSL certificate is installed on the website.</p>
<h3 id="heading-make-sure-your-date-and-time-are-correct">Make Sure your Date and Time are Correct</h3>
<p>If your computer’s date and time are ahead or behind, the browser might show an SSL-related error. </p>
<p>This is because SSLs have expiration dates. So, when your computer’s date and time are behind or ahead, the check your browser runs to see if the SSL certificate of that website is valid will fail.  </p>
<p>In this case, the browser will suggest that you change your date and time.</p>
<h3 id="heading-clear-saved-ssls-on-your-computer">Clear Saved SSLs on your Computer</h3>
<p>Clearing the SSL certificates stored by your computer can fix the issue for you. </p>
<p>When next you visit that website with the SSL error, your browser will run another check to revalidate the SSL installed on that website.</p>
<p>To clear the SSLs, hit the Windows button on your keyboard, search for “Internet Options” and click the Internet Options search result:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss13.png" alt="ss13" width="600" height="400" loading="lazy"></p>
<p>Switch to the content tab and click “Clear SSL state”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss14.png" alt="ss14" width="600" height="400" loading="lazy"></p>
<h3 id="heading-clear-your-browsers-cache-and-cookies">Clear your Browser’s Cache and Cookies</h3>
<p>The SSL info of a website in your browser’s cache and cookies might have expired, so if you clear both records, it could fix the issue for you.</p>
<p>To clear Chrome’s cache and cookies, click the 3 vertical dots on the top-right corner and select Settings:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss10.png" alt="ss10" width="600" height="400" loading="lazy"></p>
<p>Switch to the Privacy and Security tab on the left sidebar and select “Clear browsing data”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss11.png" alt="ss11" width="600" height="400" loading="lazy"></p>
<p>Select Cache and Cookies, then click “Clear data”:
<img src="https://www.freecodecamp.org/news/content/images/2022/07/ss12.png" alt="ss12" width="600" height="400" loading="lazy"></p>
<p>If you’re using another browser that is not Chrome, clear the browser’s cache and cookies.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>As a web administrator or owner, it's very important to make sure SSL is installed and properly working on your website. Otherwise, it might not just affect your website alone, but also your business.</p>
<p>If you’re a user, too, make sure any website you’re visiting shows the padlock icon on the address bar. If that’s not the case, make sure you don’t share sensitive information like card details and passwords with the website.</p>
<p>Thank you for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Validate SSL Certificates in Go ]]>
                </title>
                <description>
                    <![CDATA[ By Umesh Yadav Recently, I came across a SaaS product that validates SSL certificates for your website. I wanted to try writing the same thing in Go – and it turns out that it's pretty straightforward (just 17 lines of code). You will need to perform... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-validate-ssl-certificates-in-go/</link>
                <guid isPermaLink="false">66d852bebdc56847ac959f53</guid>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 03 Nov 2020 20:11:08 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/S3MQd1604428653.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Umesh Yadav</p>
<p>Recently, I came across a SaaS product that validates SSL certificates for your website. I wanted to try writing the same thing in Go – and it turns out that it's pretty straightforward (just 17 lines of code).</p>
<p>You will need to perform three major checks on your website.</p>
<ol>
<li>First, check to see whether your site has an SSL certificate or not. You'll also need to know if your website is using a self-signed SSL certificate which is not considered a valid certificate (it needs to be signed by a certificate authority).</li>
<li>Second, to see if the SSL certificate has the correct hostname.</li>
<li>And third, you need to know the expiration date of the server certificate.</li>
</ol>
<p>Prerequisites:</p>
<ul>
<li>You should have <code>go</code> setup on your computer.</li>
</ul>
<h3 id="heading-step-1-check-if-your-website-has-an-ssl-certificate">Step 1: Check if your website has an SSL certificate</h3>
<p>First, we will try to check if the website has an SSL certificate or not. </p>
<p>To do this we need to establish a TLS connection with the website. If that succeeds it means the website has a valid TLS certificate. </p>
<p>To establish a TLS connection we can use the Go <code>crypto/tls</code> package. We'll use the <code>Dial</code> method to connect to the website, like this:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/tls"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    conn, err := tls.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"example.com:80"</span>, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Server doesn't support SSL certificate err: "</span> + err.Error())
    }
}
</code></pre>
<p>We will try to run our test on <code>example.com</code>. When you run the above code, you should get the following error:</p>
<pre><code>$ go run main.go
<span class="hljs-attr">panic</span>: Server doesn<span class="hljs-string">'t support SSL certificate err: tls: first record does not look like a TLS handshake

goroutine 1 [running]:
main.main()
        /Users/umesh/personal/spike/main.go:99 +0x2ca
exit status 2</span>
</code></pre><p>Basically it tried to establish the connection but failed. The <code>Dial</code> method succeeds only when the website has a valid certificate (it will fail if the certificate is self-signed).</p>
<p>Now try the same code on a website that has SSL enabled. I am using my own website's URL as an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/tls"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    conn, err := tls.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"blog.umesh.wtf:443"</span>, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Server doesn't support SSL certificate err: "</span> + err.Error())
    }
}
</code></pre>
<p>This time, we should be able to successfully establish the connection without the code panic.</p>
<p>In production you should not use panic, but rather should handle the error gracefully.</p>
<h3 id="heading-step-2-check-whether-the-ssl-certificate-and-website-hostname-match">Step 2: Check whether the SSL certificate and website hostname match</h3>
<p>To verify the hostname we will need to call <code>VerifyHostname</code> on the <code>conn</code> return by <code>Dial</code>. This method tries to match the common name or subject alt name specified in the certificate with the domain passed as a parameter.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/tls"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    conn, err := tls.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"blog.umesh.wtf:443"</span>, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Server doesn't support SSL certificate err: "</span> + err.Error())
    }

    err = conn.VerifyHostname(<span class="hljs-string">"blog.umesh.wtf"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Hostname doesn't match with certificate: "</span> + err.Error())
    }
}
</code></pre>
<p>This will successfully execute without any error as the certificate's common name and hostname are the same.</p>
<h3 id="heading-step-3-verify-the-expiration-date-of-the-servers-ssl-certificate">Step 3: Verify the expiration date of the server's SSL certificate</h3>
<p>We can get the certificate chain using <code>conn.ConnectionState().PeerCertificates</code>. We can then use this certificate to get the expiration date of the server certificate. </p>
<p>We will use the first certificate from the list of certificates and try to get the expiration date using the field <code>NotAfter</code>.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/tls"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    conn, err := tls.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"blog.umesh.wtf:443"</span>, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Server doesn't support SSL certificate err: "</span> + err.Error())
    }

    err = conn.VerifyHostname(<span class="hljs-string">"blog.umesh.wtf"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(<span class="hljs-string">"Hostname doesn't match with certificate: "</span> + err.Error())
    }
    expiry := conn.ConnectionState().PeerCertificates[<span class="hljs-number">0</span>].NotAfter
    fmt.Printf(<span class="hljs-string">"Issuer: %s\nExpiry: %v\n"</span>, conn.ConnectionState().PeerCertificates[<span class="hljs-number">0</span>].Issuer, expiry.Format(time.RFC850))
}
</code></pre>
<p>The output should contain the certificate's expiration date and Issuer Name.</p>
<pre><code>$ go run main.go
<span class="hljs-attr">Issuer</span>: CN=Let<span class="hljs-string">'s Encrypt Authority X3, O=Let'</span>s Encrypt, C=US
<span class="hljs-attr">Expiry</span>: Wednesday, <span class="hljs-number">16</span>-Dec<span class="hljs-number">-20</span> <span class="hljs-number">16</span>:<span class="hljs-number">20</span>:<span class="hljs-number">00</span> UTC
</code></pre><p>Now we have successfully validated the site's certificate.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>You can also get detailed information like root CA, the date the certificate was issued, and all the chained certificates. </p>
<p>This tool was just written using the core libraries of Go (and no external libraries). Do let me know what do you think about it!</p>
<p>If you liked this article, you can head over to <a target="_blank" href="https://umesh.dev/blog">my personal blog</a> to see more stuff I've written. </p>
<p>I regularly write about programming and software, so do subscribe to my newsletter and get the latest posts from me delivered straight into your inbox. You can also get in touch with me on <a target="_blank" href="https://twitter.com/imumesh18">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An introduction to HTTP: everything you need to know ]]>
                </title>
                <description>
                    <![CDATA[ By Goran Aviani In this article, I will walk you through how the world wide web works at a fundamental level. The core technology is HTTP - Hypertext Transfer Protocol. It's the communication protocol you use when you browse the web. At a fundamental... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/http-and-everything-you-need-to-know-about-it/</link>
                <guid isPermaLink="false">66d45eeb36c45a88f96b7cd7</guid>
                
                    <category>
                        <![CDATA[ http ]]>
                    </category>
                
                    <category>
                        <![CDATA[ https ]]>
                    </category>
                
                    <category>
                        <![CDATA[ internet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 11 Sep 2019 15:23:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/08/slik.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Goran Aviani</p>
<p>In this article, I will walk you through how the world wide web works at a fundamental level.</p>
<p>The core technology is HTTP - Hypertext Transfer Protocol. It's the communication protocol you use when you browse the web.</p>
<p>At a fundamental level, when you visit a website, your browser makes an HTTP request to a server. Then that server responds with a resource (an image, video, or the HTML of a web page) -  which your browser then displays for you.</p>
<p>This is HTTP's message-based model. Every HTTP interaction includes a request and a response. </p>
<p>By its nature, HTTP is stateless.</p>
<p><strong>Stateless</strong> means that all requests are separate from each other. So each request from your browser must contain enough information on its own for the server to fulfill the request. That also means that each transaction of the message based model of HTTP is processed separately from the others.</p>
<h2 id="heading-urls">URLs</h2>
<p>The URL (Uniform Resource Locator) is probably the most known concept of the Web. It is also one of most important and useful concepts. A URL is a web address used to identify resources on the Web.</p>
<p>The idea of the web is structured around resources. From its beginnings the Web was the platform for sharing text/HTML files, documents, images etc, and as such it can be considered a collection of resources.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/0-DTR8JpFZo31ht-Kd.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Example of an URL</em></p>
<p><strong>Protocol</strong> — Most often they are HTTP (or HTTPS for a secure version of HTTP).</p>
<p>Other notable protocols are:</p>
<ul>
<li>File Transfer Protocol (FTP) — is a standard protocol used for transferring files between a client and a server over a network.</li>
<li>Simple Mail Transfer Protocol (SMTP) is a standard for email transmission.</li>
</ul>
<p><strong>Domain</strong> — Name that is used to identify one or more IP addresses where the resource is located.</p>
<p><strong>Path</strong> —Specifies the resource location on the server. It uses the same logic as a resource location used on the device where you are reading this article (i.e. /search/cars/VWBeetle.pdf or C:/my cars/VWBeetle.pdf).</p>
<p><strong>Parameters</strong> — Additional data used to identify or filter the resource on the server.</p>
<p><strong>Note</strong>: When searching for articles and more information about HTTP, you may encounter the term URI (or uniform resource identifier). URI is sometimes being used instead of URL but mostly in formal specifications and by people who want to show off. :)</p>
<h2 id="heading-http-requests">HTTP Requests</h2>
<p>In HTTP, every request must have an URL address. Additionally, the request needs a method. The four main HTTP methods are:</p>
<ul>
<li>GET</li>
<li>PUT</li>
<li>POST</li>
<li>DELETE</li>
</ul>
<p>I will explain these methods, and more, in the HTTP Methods section of this article.</p>
<p>And these methods directly correspond to actions:</p>
<ul>
<li>read</li>
<li>update</li>
<li>create</li>
<li>delete</li>
</ul>
<p>All HTTP messages have one or more headers, followed by an optional message body. The body contains the data that will be sent with the request or the data received with the response.</p>
<p>The first part of every HTTP request holds three items:</p>
<p>Example:</p>
<ul>
<li>GET /adds/search-result?item=vw+beetle HTTP/1.1</li>
</ul>
<p><em>When a URL contains a “?” sign, it means it contains a query. That means it sends parameters of the requested resource.</em></p>
<ol>
<li>The first part is a method which tells which HTTP method is used. Most commonly used is the GET method. GET method retrieves a resource from the web server and since GET doesn’t have a message body nothing after the header is needed.</li>
<li>The second part is a requested URL.</li>
<li>The third part is a HTTP version being used. Version 1.1. is the most common version for most browsers, however, version 2.0 is taking over.</li>
</ol>
<p>There are also some other interesting things in an HTTP request:</p>
<p><strong>Referer header</strong> — tells the URL from where the request has originated.</p>
<p><strong>User-Agent header</strong> — additional information about the browser being used to generate the request.</p>
<p><strong>Host header</strong> — uniquely identifies a host name; it is necessary when multiple web pages are hosted on the same server.</p>
<p><strong>Cookie header</strong> — submits additional parameters to the client.</p>
<h2 id="heading-http-responses">HTTP Responses</h2>
<p>Just like in HTTP requests, HTTP responses also consist of three items:</p>
<p>Example:</p>
<p>HTTP/1.1 200 OK</p>
<ol>
<li>The first part is the HTTP version being used.</li>
<li>The second part is the numeric code of the result for the request.</li>
<li>The third part is a textual description of the second part.</li>
</ol>
<p>There are some other interesting things in an HTTP response:</p>
<p><strong>Server header</strong> — information about which web server software is being used.</p>
<p><strong>Set-Cookie header</strong> — issues the cookie to the browser.</p>
<p><strong>Message body</strong> — it is common for an HTTP response to hold a message body.</p>
<p><strong>Content-Length header</strong> — tells the size of the message body in bytes.</p>
<h2 id="heading-http-methods">HTTP Methods</h2>
<p>The most common methods are GET and POST. But there are a few others, too.</p>
<p><strong>GET</strong> —  You use this method to request data from a specified resource where data is not modified it in any way. GET requests do not change the state of resource.</p>
<p><strong>POST</strong> — You use this method to send data to a server to create a resource.</p>
<p><strong>PUT —</strong> You use this method to update the existing resource on a server by using the content in the body of the request. Think of this as a way to "edit" something.</p>
<p><strong>HEAD</strong> —  You use this method the same way you use GET, but with the distinction that the return of a HEAD method should not contain body in the response. But the return will contain same headers as if GET was used. You use the HEAD method to check whether the resource is present prior of making a GET request.</p>
<p><strong>TRACE —</strong> You use this method for diagnostic purposes. The response will contain in its body the exact content of the request message.</p>
<p><strong>OPTIONS</strong> — You use this method to describe the communication options (HTTP methods) that are available for the target resource.</p>
<p><strong>PATCH —</strong>  You use this method to apply partial modifications to a resource.</p>
<p><strong>DELETE —</strong>You use this method to delete the specified resource.</p>
<h2 id="heading-rest">REST</h2>
<p>Representational state transfer (REST) is an architecture style where requests and responses contain representations of the current state of the systems resource.</p>
<p>“Regular” way:</p>
<ul>
<li><a target="_blank" href="http://carapp.com/search?make=wv&amp;model=beetle">http://carapp.com/search?make=wv&amp;model=beetle</a></li>
</ul>
<p>REST-style:</p>
<ul>
<li><a target="_blank" href="http://carapp.com/search/vw/beetle">http://carapp.com/search/vw/beetle</a></li>
</ul>
<p>You can <a target="_blank" href="https://www.freecodecamp.org/news/how-the-web-works-part-iii-http-rest-e61bc50fa0a/">learn more about REST here if you're curious</a>.</p>
<h2 id="heading-http-headers">HTTP Headers</h2>
<p>There are three main components that make up the request/response structure. These include:</p>
<ul>
<li>First line</li>
<li>Headers</li>
<li>Body/Content</li>
</ul>
<p>We already talked about the first line in HTTP requests and responses, and body function was mentioned too. Now we'll talk about HTTP headers.</p>
<p>The HTTP headers are added after the first line and are defined as name:value pairs separated by a colon. HTTP headers are used to send additional parameters along with the request or response.</p>
<p>As I already said, the body of the message includes the data to be sent with the request or the data received along with the response.</p>
<p>There are different types of headers that are grouped based on their usage into 4 broad categories:</p>
<ul>
<li><strong>General header</strong> — Headers that can be used in both requests and response messages and that are independent of the data being exchanged.</li>
<li><strong>Request header</strong> — These headers define parameters for the data requested or parameters that give important information about the client making the request.</li>
<li><strong>Response header</strong> — These headers contain information about the incoming response.</li>
<li><strong>Entity header</strong> — The entity headers describe the content that makes up the body of the message.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/0-0BI1BEJpajUiJ_4R.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Types of headers</em></p>
<h2 id="heading-http-status-codes">HTTP status codes</h2>
<p>Browsing the web, you may have encountered "404 error: not found" pages or "500 errors: server is not responding" pages.</p>
<p>These are HTTP status codes.</p>
<p>Every HTTP response message must contain an HTTP status code in its first line, telling us the result of the request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/Steve_Losh_on_Twitter___HTTP_status_ranges_in_a_nutshell__1xx__hold_on_2xx__here_you_go_3xx__go_away_4xx__you_fucked_up_5xx__I_fucked_up_.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There are five groups of status codes which are grouped by the first digit:</p>
<ul>
<li>1xx — Informational.</li>
<li>2xx — The request was successful.</li>
<li>3xx — The client is redirected to a different resource.</li>
<li>4xx — The request contains an error of some kind.</li>
<li>5xx — The server encountered an error fulfilling the request.</li>
</ul>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">Here's a full list of HTTP Status Response Codes</a> and their explanation.</p>
<h2 id="heading-https-hypertext-transfer-protocol-secure">HTTPS (Hypertext Transfer Protocol Secure)</h2>
<p>The secure version of HTTP protocol is HyperText Transfer Protocol Secure (HTTPS). HTTPS provides encrypted communication between a browser (client) and the website (server).</p>
<p>In HTTPS, the communication protocol is encrypted using Transport Layer Security (TLS) or Secure Sockets Layer (SSL).</p>
<p>The protocol is therefore also often called HTTP over TLS, or HTTP over SSL.</p>
<p>Both the TLS and SSL protocols use an asymmetric encryption system. Asymmetric encryption systems use a public key (encryption key) and a private key (decryption keys) to encrypt a message. </p>
<p>Anyone can use the public key to encrypt a message. However, private keys are secret, and that means that only the intended receiver can decrypt the message.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/0-pB_y5GVIF_O_z4lw.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Example of asymmetric encryption system</em></p>
<h4 id="heading-ssltls-handshake">SSL/TLS handshake</h4>
<p>When you request a HTTPS connection to a website, the website sends its SSL certificate to your browser. That process where your browser and website initiate communication is called the “SSL/TLS handshake.” </p>
<p>The SSL/TLS handshake involves a series of steps where browser and website validate each other and start communication through the SSL/TLS tunnel.</p>
<p>As you probably noticed, when a trusted secure tunnel is used during in a HTTPS connection, the green padlock icon is displayed in the browsers address bar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/0-g7q-rF8JTGp7fs19.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example of one of my secure pages</em></p>
<h4 id="heading-benefits-of-https"><strong>Benefits of HTTPS</strong></h4>
<p>The major benefits of a HTTPS are:</p>
<ul>
<li>Customer information, like credit card numbers and other sensitive information, is encrypted and cannot be intercepted.</li>
<li>Visitors can verify you are a registered business and that you own the domain.</li>
<li>Customers know they are not suppose to visit sites without HTTPS, and therefore, they are more likely to trust and complete purchases from sites that use HTTPS.</li>
</ul>
<p>Thank you for reading! Check out more articles like this <a target="_blank" href="https://www.freecodecamp.org/news/author/goran/">on my freeCodeCamp profile</a>. And check out other fun stuff I build <a target="_blank" href="https://github.com/GoranAviani">on my GitHub page</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Host your Static Website with AWS - A Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ When I created my first portfolio last year, I based it on what I had learned from freeCodeCamp (HTML, CSS and a little JavaScript). At that point, I had only viewed my portfolio on localhost by viewing the files on my local computer. I didn’t know a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-beginners-guide-on-how-to-host-a-static-site-with-aws/</link>
                <guid isPermaLink="false">66d4608a47a8245f78752a99</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Hosting ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Phoebe Voong-Fadel ]]>
                </dc:creator>
                <pubDate>Thu, 08 Aug 2019 11:48:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/08/undraw_blogging_vpvv.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When I created my first <a target="_blank" href="https://thecodinghamster.com/">portfolio</a> last year, I based it on what I had learned from <a target="_blank" href="https://www.freecodecamp.org/">freeCodeCamp</a> (HTML, CSS and a little JavaScript).</p>
<p>At that point, I had only viewed my portfolio on localhost by viewing the files on my local computer. I didn’t know anything about how to host a website online.</p>
<p>Learning how to host my first website wasn’t easy but it was a great learning experience. If you're an aspiring web developer or just interested in launching your own static website, then I hope you will find this guide useful.</p>
<h4 id="heading-who-is-this-guide-for"><strong>Who is this guide for?</strong></h4>
<p>This guide is aimed at <strong>complete beginners</strong> who want to host a static website (a site with fixed content). I will provide a how-to-guide for the following:</p>
<ol>
<li><p>How to buy a domain.</p>
</li>
<li><p>How to configure your domain for an external hosting provider.</p>
</li>
<li><p>How to host your website with Amazon Web Services (AWS).</p>
</li>
<li><p>How to make your website secure (SSL certification) using Amazon Certification Manager.</p>
</li>
</ol>
<p>There might be some terminology that’s new to you. Please go ahead and look up terms that are not familiar. I’ve put in useful links and explanations where I thought appropriate.</p>
<h4 id="heading-what-is-a-domain-name-and-dns-domain-name-system"><strong>What is a domain name and DNS (Domain Name System)?</strong></h4>
<p>A domain name is your website address. For example thecodinghamster.com. But for a computer, a domain name is actually a series of numbers (an IP address). An IP address looks like this: 123.321.0.1</p>
<p>It’s not easy for us to remember a long string of numbers. So your computer refers to a <strong>DNS</strong> to translate a text based website address into an IP address which it can then understand. A DNS is like a directory.</p>
<p>I watched this great video which explains domain name, DNS and how this works in under five minutes. Please watch the first five minutes of the video if you're interested:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/e2xLV7pCOLI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-where-can-you-buy-your-domain-name">Where can you buy your domain name?</h3>
<p>You can buy a domain name from a domain name registrar. Prices start from a few dollars. Your domain name is unique. Each domain name registrar offers different levels of services/support. But you can register your domain with any registrar.</p>
<h4 id="heading-what-is-a-hosting-provider"><strong>What is a hosting provider?</strong></h4>
<blockquote>
<p>“An <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_hosting_service">Internet hosting service</a> is a service that runs Internet servers, allowing organizations and individuals to serve content to the Internet. There are various levels of service and various kinds of services offered.”</p>
</blockquote>
<p>When I was looking for a hosting provider for my website, I explored different options. The prices ranged from £2.00 — £5.00 per month with various storage options from 0.5GB to 10GB. The prices seemed reasonable but all I wanted to do was host a static website. It had a few images, HTML, CSS and JavaScript files. No dynamic content.</p>
<h4 id="heading-why-aws"><strong>Why AWS?</strong></h4>
<p>After some further research, I found AWS. AWS offers a <a target="_blank" href="https://aws.amazon.com/free/?nc2=h_ql_pr">free tier option</a>. Essentially, you get lots of free products. Some of them expire after 12 months and others are free in perpetuity. The only cost that you will incur for hosting a static website is the cost of setting up a hosted zone. This cost $0.50 per month. So I went with AWS and set up my account.</p>
<p>The great thing about AWS is the price and it’s a reliable hosting provider. But one thing to bear in mind is that you’re reliant on their documentation. As I started reading about what services AWS offered, it quickly became confusing! I used the official AWS <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html">guide provided</a> for setting up static websites. But I found myself getting lost with clicking on a link to another link and so forth. I started researching other guides to make up for knowledge gaps.</p>
<p>I found this this excellent <a target="_blank" href="https://victoria.dev/verbose/hosting-your-static-site-with-aws-s3-route-53-and-cloudfront/">guide by Victoria Drake</a>.</p>
<p>I followed Victoria Drake’s guide alongside the AWS one and managed to muddle through. But there were still a few things that were not explained which I hope to flesh out.</p>
<p>Before we proceed, here is your to do list:</p>
<ul>
<li><p>Do some research on domain registrars and buy your domain name.</p>
</li>
<li><p>Sign up for a free account with AWS.</p>
</li>
<li><p>Have both the <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html">documentation from AWS</a> and <a target="_blank" href="https://victoria.dev/verbose/hosting-your-static-site-with-aws-s3-route-53-and-cloudfront/">Victoria Drake’s guide open</a>. Use my guide to guide you through the documentation (hope that makes sense!).</p>
</li>
</ul>
<p>Here we go!</p>
<h4 id="heading-aws-create-a-hosted-zone-on-route-53"><strong>AWS: Create a Hosted Zone on Route 53.</strong></h4>
<p>Route 53 is where all your DNS requests are handled.</p>
<p>The first thing you must set up is your hosted zone with Route 53. This is really easy if you bought your domain through AWS. A hosted zone is created automatically once you’ve purchase it. If you’ve done this then just skip to the next section (<strong>Set up your S3 Buckets</strong>).</p>
<p>However, if you were like me and bought your domain name via another registrar then please do the following.</p>
<p><strong>This next part is how to create a Hosted Zone on Route 53 if you haven’t bought your domain name from AWS:</strong></p>
<ol>
<li><a target="_blank" href="https://console.aws.amazon.com/route53/home?#hosted-zones:">Go to Route 53</a> in your console and click on “Create Hosted Zone”. Fill in your domain address, comment is optional and choose a “Public Hosted Zone”. Click on “Create”.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/hostedzone1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>Once your hosted zone is created, you need your NS (Name Servers) records:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/hostedzone2-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="3">
<li>Go to your domain name registrar and login. Depending on your registrar, you should find a section in your settings called "Nameservers" which you can edit. You need to copy across the AWS NS records and change the existing NS records in your domain settings.</li>
</ol>
<p>Please note, don't copy the full stop/period at the end of the NS record. For example, is should be “ns-63.awsdns-07.com”, not “ns-63.awsdns-07.com.”</p>
<p><strong>It will take up to 24 hours to propagate.</strong></p>
<h3 id="heading-set-up-your-s3-buckets"><strong>Set up your S3 Buckets</strong></h3>
<p>In the meantime you can set up your S3 Buckets. The S3 Bucket is the storage for your files such as your index.html.</p>
<p>You must configure two buckets for your website: 1) yourdomainname.com and 2) www.yourdomainname.com.</p>
<p>The first bucket is your main bucket where you will upload all your documents, such as your index.html. The second bucket redirects to the first bucket. To set up your S3 Buckets, please follow the AWS documentation on how to set up your S3 bucket ( <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html#root-domain-walkthrough-s3-tasks">2: Create and Configure Buckets and Upload Data</a>).</p>
<p>In addition to the documentation, there are a few things to note:</p>
<ul>
<li><p>In section 2.1 (part 2): click on the link <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-bucket.html">How Do I Create an S3 Bucket?</a> This is a step by step guide and explain all the settings you need to choose.</p>
</li>
<li><p>In section 2.1 (part 3): you don’t have to upload your website files yet. You can add a test index.html in the meantime.</p>
</li>
</ul>
<p>Take note of your <strong>endpoint</strong>. You can find this in your S3 bucket &gt; “Properties” tab &gt; “Static Web Hosting” box. It should look something like this: http://yourdomainname.com.s3-website.eu-west-2.amazonaws.com</p>
<h3 id="heading-add-the-aliasa-records-in-route-53"><strong>Add the Alias/“A” records in Route 53</strong></h3>
<p>Finally go back to Route 53 and open your hosted zone to set up your Alias records. You can follow <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html#root-domain-walkthrough-add-arecord-to-hostedzone">the documentation</a> on “Step 3: Add Alias Records for example.com and www.example.com”. It is quite straightforward.</p>
<p>Once the NS settings have propagated, <strong>your site is live</strong>! You’ll be able to visit your site at the domain address e.g. yourdomainname.com</p>
<p>However, please note that it won’t be secure and you’ll see a <strong>http://</strong> prefix in the address bar. I’ll get to that in the next section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/undraw_security_o890.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-make-your-website-secure-and-what-is-a-ssl-certificate"><strong>How to make your website secure and what is a SSL certificate?</strong></h3>
<p>It’s very important to make your website secure and to do this you’ll need to get an SSL certificate. SSL stands for <a target="_blank" href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Secure Sockets Layer</a> and it uses encryption to securely transfer data between a user and site. Google will also give a rankings boost for websites with HTTPS.</p>
<p>If you secure the website with an SSL certificate, you’ll see <strong>https://</strong> and a padlock symbol in your address bar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-19-at-01.05.23.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There are different types of SSL certificates: <a target="_blank" href="https://en.wikipedia.org/wiki/Extended_Validation_Certificate">Extended Validation Certificate</a> and a <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-validated_certificate">Domain validated certificate</a>. For a personal website or blog, only a domain validated certificate is required. You also won’t see the name of your company on the left of the bar like the example above. You only get this if you have an Extended Validation Certificate which is more for large companies/enterprises.</p>
<h3 id="heading-how-much-does-it-cost-for-an-ssl-certificate"><strong>How much does it cost for an SSL certificate?</strong></h3>
<p>I’ve seen a range of ways of getting an SSL certificate. You can pay a premium for a service that will do this on your behalf or you can do it for free with <a target="_blank" href="https://letsencrypt.org/getting-started/">Let’s Encryp</a>t. Let’s Encrypt is an official Certificate Authority (CA). But you have to renew your certificate every three months and the process is quite complicated.</p>
<p>I didn’t want to pay a premium or want the hassle of renewing every three months. Conveniently, AWS can issue SSL certificates for a <a target="_blank" href="https://aws.amazon.com/certificate-manager/pricing/">very small fee</a>. You pay $0.75 for each certificate issued and it lasts for one year.</p>
<p>If you choose not to go with AWS, make sure you do your research and choose a <a target="_blank" href="https://www.geckoandfly.com/24460/free-trusted-ssl-certificate/">trusted CA</a>!</p>
<h3 id="heading-how-do-you-get-an-ssl-certificate-with-aws"><strong>How do you get an SSL certificate with AWS?</strong></h3>
<p>Log into your AWS console and navigate to the <a target="_blank" href="https://aws.amazon.com/certificate-manager/">AWS Certificate Manager</a> (ACM).</p>
<p><strong>Make sure you change the region from the default (Ohio) to N. Virginia.</strong> This is not explicit in the guides and only the N. Virginia region can issue certificates. I learned the hard way and wasted a lot of time!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-19-at-01.23.52.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then click on “Get Started” under “Provision Certificates”.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-18-at-14.55.14.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Follow the <a target="_blank" href="https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html">documentation with AWS</a> (“Requesting a public certificate using the console”) and use <a target="_blank" href="https://vickylai.com/verbose/hosting-your-static-site-with-aws-s3-route-53-and-cloudfront/">Victoria Drake’s guide</a> (under “SSL certificate”).</p>
<p><strong>In addition to the guides</strong> there are few things that weren’t fully explained:</p>
<ul>
<li><p>You’ll need to <strong>validate your domain ownership</strong> by email or directly with DNS. I would suggest to always verify ownership by <a target="_blank" href="https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html"><strong>DNS validation</strong></a>.</p>
</li>
<li><p>Once you’ve requested your certificate you’ll get something like this (except the status will be pending). Click on the “Export DNS Configuration file”:</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/acm.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It’s an Excel spreadsheet which will contain something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-18-at-15.28.11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ul>
<li><p>You’ll need to add these records to your DNS settings with your registrar. Log in and go to DNS settings. The interface varies with different registrars but you’re looking for your Host records under your DNS settings.</p>
</li>
<li><p>Click on “Add Record” &gt; record type is <strong>CNAME</strong>:</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-18-at-15.48.11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You need to add two records: 1) Hostname should be “@” and Target Name should be the Record value from the DNS configuration file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-18-at-16.01.07.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>Hostname should be * (asterisk) and Target Name should be the Record value from the DNS configuration file.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-18-at-16.01.31.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want more information about the CNAME and record types, I found this <a target="_blank" href="https://help.hover.com/hc/en-us/articles/217282457-How-to-Edit-DNS-records-A-AAAA-CNAME-MX-TXT-SRV-">helpful article</a>.</p>
<p>It's quite long, but I've pulled out the useful part:</p>
<blockquote>
<p>“Note: Hostname refers to the prefix before the domain name. To create a Blank record, use an @ in the Hostname field. This represents an empty prefix (so the name exactly matches the domain name; for example divapirate.com). The @ hostname is also referred to as the the root of the domain. An * (asterisk) in the Hostname is a wildcard, and represents any prefix. For example, creating a record for *.divapirate.com will point .divapirate.com at the IP address provided.”</p>
</blockquote>
<p>You just need to wait for the verification. For me, this took about an hour.</p>
<h3 id="heading-how-do-you-add-your-ssl-certificate"><strong>How do you add your SSL certificate?</strong></h3>
<p>With AWS you can add SSL certificate to your website through setting up <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-cloudfront-walkthrough.html"><strong>CloudFront</strong></a>. CloudFront is great for speeding up your website. I used the <a target="_blank" href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https.html">AWS documentation</a> and <a target="_blank" href="https://victoria.dev/verbose/hosting-your-static-site-with-aws-s3-route-53-and-cloudfront/">Victoria Drake’s guide</a> (look out for her useful tips).</p>
<p>Please note, when you create your CloudFront distribution, there’s a drop down menu to add your SSL certificate. If you have been issued with an SSL certificate already, it will be pre-populated in the drop down menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/Screen-Shot-2019-01-19-at-01.36.02-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Your state in your CloudFront dashboard should changed to “Enabled”. This isn’t instant and takes a little time.</p>
<h3 id="heading-almost-there"><strong>Almost there…</strong></h3>
<p>Finally, you need to get your <strong>Domain Name</strong> from the CloudFront distribution. It should be something like this dsfdser83543.<strong>cloudfront.net</strong>.</p>
<p>Go back to Route 53 &gt; hosted zone &gt; change both Alias records (Alias Target) to the CloudFront Domain Name.</p>
<p>Voila! You have hosted your first <strong>secure static website</strong> with AWS.</p>
<hr>
<p>Hope you found this useful. If you have any questions or just want to say hello, find me on Twitter <a target="_blank" href="https://twitter.com/PhoebeVF">@PhoebeVF</a></p>
<p>A big thank you to Victoria Drake for her guide. For a more advanced tutorial on this topic, please check out Victoria's article: <a target="_blank" href="https://victoria.dev/verbose/hosting-your-static-site-with-aws-s3-route-53-and-cloudfront/">"Hosting your static site with AWS S3, Route 53, and CloudFront"</a>.</p>
<p>Illustrations courtesy of <a target="_blank" href="https://undraw.co/">https://undraw.co</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to redirect HTTP to HTTPS Using .htaccess ]]>
                </title>
                <description>
                    <![CDATA[ Chrome and Firefox have started showing insecure warnings on sites without SSL certificates. Without SSL, your website will show insecure to the visitors. Therefore, using an SSL-encrypted connection for safety, accessibility or PCI compliance reason... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-redirect-http-to-https-using-htaccess/</link>
                <guid isPermaLink="false">66d84e1ee86088251dd27bb7</guid>
                
                    <category>
                        <![CDATA[ http ]]>
                    </category>
                
                    <category>
                        <![CDATA[ https ]]>
                    </category>
                
                    <category>
                        <![CDATA[ openssl ]]>
                    </category>
                
                    <category>
                        <![CDATA[ servers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bolaji Ayodeji ]]>
                </dc:creator>
                <pubDate>Thu, 13 Jun 2019 12:10:15 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca210740569d1a4ca5257.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Chrome and Firefox have started showing insecure warnings on sites without <a target="_blank" href="https://www.instantssl.com/ssl.html">SSL certificates</a>. Without SSL, your website will show insecure to the visitors. Therefore, using an SSL-encrypted connection for safety, accessibility or PCI compliance reasons is necessary. It becomes very important to redirect from HTTP to HTTPS.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*wUTFJrRSM2vh1H7v.jpg" alt="Image" width="800" height="289" loading="lazy"></p>
<h3 id="heading-what-is-ssl">What is SSL?</h3>
<p>SSL (Secure Sockets Layer) is a standard security protocol for establishing encrypted links between a web server and a browser in an online communication.</p>
<p>The usage of SSL technology ensures that all data transmitted between the web server and browser remains encrypted.</p>
<p>An <strong>SSL certificate</strong> is necessary to create SSL connection. You would need to give all details about the identity of your website and your company as and when you choose to activate SSL on your web server. Following this, two cryptographic keys are created — a Private Key and a Public Key.</p>
<p><a target="_blank" href="https://www.sslrenewals.com/blog/why-is-ssl-important-benefits-of-using-ssl-certificate"><em>Learn More: Why SSL is Critical?</em></a></p>
<p>In order to force your web traffic to use HTTPS, edit the codes in the <strong>.htaccess file.</strong></p>
<p>Before we move onto redirecting HTTP to HTTPS, here’s how you can edit .htaccess file. If you already know skip to Redirection steps.</p>
<h3 id="heading-editing-htaccess-file">Editing .htaccess File</h3>
<p>There are instructions/directives in the .htaccess file that tell the server how to act in certain scenarios and directly affects how your website functions. Common directives in .htaccess file:</p>
<ul>
<li><p>Redirects</p>
</li>
<li><p>Rewriting URLs</p>
</li>
</ul>
<p><strong>Ways to edit an .htaccess file:</strong></p>
<ol>
<li><p>Edit the file on your computer and upload it to the server using FTP.</p>
</li>
<li><p>Use “Edit” mode in FTP program that allows you to edit a file remotely.</p>
</li>
<li><p>Use a text editor and SSH to edit the file.</p>
</li>
<li><p>Use the File Manager in <strong>cPanel</strong> to edit the file.</p>
</li>
</ol>
<h3 id="heading-editing-htaccess-in-cpanel-file-manager">Editing .htaccess in cPanel File Manager</h3>
<p><strong>Note:</strong> Backup your website in case something goes wrong.</p>
<ol>
<li><p>Login to cPanel</p>
</li>
<li><p>Files &gt; File Manager &gt; Document Root for:</p>
</li>
<li><p>Now select the domain name you want to access</p>
</li>
<li><p>Check “Show Hidden Files (dotfiles)”</p>
</li>
<li><p>Click “Go”</p>
</li>
<li><p>After a new tab or window opens, look for the .htaccess file.</p>
</li>
<li><p>Right click on the .htaccess file and click on “Code Edit” on the menu.</p>
</li>
<li><p>A dialogue box may pop up asking about encoding. Click “Edit” button to continue.</p>
</li>
<li><p>Edit the file</p>
</li>
<li><p>“Save Changes” when done.</p>
</li>
<li><p>Test your website to make sure it is done correctly. In case, there is an error, restore to the previous version and try again.</p>
</li>
<li><p>Once you are done, click “Close” to close the window.</p>
</li>
</ol>
<h3 id="heading-redirecting-http-to-https">Redirecting HTTP to HTTPS</h3>
<h4 id="heading-1-redirect-all-web-traffic">1. Redirect All Web Traffic</h4>
<p>If you have existing code in your .htaccess, add the following:</p>
<pre><code class="lang-python">RewriteEngine On
RewriteCond %{SERVER_PORT} <span class="hljs-number">80</span>
RewriteRule ^(.*)$ https://www.yourdomain.com/$<span class="hljs-number">1</span> [R,L]
</code></pre>
<h4 id="heading-2-redirect-only-a-specific-domain">2. Redirect Only a Specific Domain</h4>
<p>For redirecting a specific domain to use HTTPS, add the following:</p>
<pre><code class="lang-python">RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteCond %{SERVER_PORT} <span class="hljs-number">80</span>
RewriteRule ^(.*)$ https://www.yourdomain.com/$<span class="hljs-number">1</span> [R,L]
</code></pre>
<h4 id="heading-3-redirect-only-a-specific-folder">3. Redirect Only a Specific Folder</h4>
<p>Redirecting to HTTPS on a specific folder, add the following:</p>
<pre><code class="lang-python">RewriteEngine On
RewriteCond %{SERVER_PORT} <span class="hljs-number">80</span>
RewriteCond %{REQUEST_URI} folder
RewriteRule ^(.*)$ https://www.yourdomain.com/folder/$<span class="hljs-number">1</span> [R,L]
</code></pre>
<p>Note: Replace <code>“yourdomain”</code> with your actual domain name wherever required. Also, in case of the folder, replace <code>/folder</code> with the actual folder name.</p>
<p>Think it was helpful? Share this article to help others come on HTTPS.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*P6EKtlMMzyIXNRMw.png" alt="Image" width="670" height="240" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to add an SSL certificate and custom Namecheap domain to a GitLab Pages site ]]>
                </title>
                <description>
                    <![CDATA[ By Erica Pisani Adding an SSL certificate and custom Namecheap domain to a GitLab Pages site can be a bit more challenging than it seems. Crucial pieces of the setup information live in sometimes dense documentation across different sites. It can be ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-an-ssl-certificate-and-custom-namecheap-domain-to-a-gitlab-pages-site-323f8f3ce642/</link>
                <guid isPermaLink="false">66c34ed8465d1b2f886ba417</guid>
                
                    <category>
                        <![CDATA[ GitLab ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 30 Oct 2018 16:57:08 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*9QSXL-RF1rxq9xyoPZjFKw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Erica Pisani</p>
<p>Adding an SSL certificate and custom Namecheap domain to a GitLab Pages site can be a bit more challenging than it seems.</p>
<p>Crucial pieces of the setup information live in sometimes dense documentation across different sites. It can be hard to tell if you’ve set things up correctly given that you have to wait hours to confirm your changes have propagated.</p>
<p>Even when you know something is wrong, you can’t always tell what. This makes debugging the problem frustrating and challenging to fix.</p>
<p>This guide aims to make the process a bit more straightforward and less frustrating. It assumes that you’ve:</p>
<ul>
<li>Already set up your project on GitLab Pages and are able to access it by entering <code>&lt;your-username&gt;.gitlab.io/&lt;your-proj</code>ect-name&gt; in your browser</li>
<li>Have purchased a custom domain name along with an SSL certificate through Namecheap</li>
</ul>
<h3 id="heading-step-1-activate-the-ssl-certificate"><strong>Step 1: Activate the SSL certificate</strong></h3>
<p>In Namecheap, go to the ‘Product List’ &gt; ‘SSL Certificates’ page. You should see a list of SSL certificates that you have purchased, but have not yet activated. Click ‘Activate’ on the SSL certificate that you wish to activate for your site.</p>
<h3 id="heading-step-2-generate-the-ssl-certificate-request"><strong>Step 2: Generate the SSL certificate request</strong></h3>
<p>You should have been brought to a page that looks like the following:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*u9hG-Wrtm22y9byC5SmQTA.png" alt="Image" width="800" height="438" loading="lazy"></p>
<p>In order to generate a CSR, you’ll need to run the following command in your terminal: <code>openssl req -new -newkey rsa:2048 -nodes -keyout &lt;your-domain-name&gt;.key -out &lt;your-domain-n</code>ame&gt;.csr.</p>
<p>A private key will be generated as a result of that command. <strong>DO NOT LOSE THIS KEY.</strong> You will need it later on when you go to install your certificate on GitLab. Should you lose it, you will have to submit another CSR request.</p>
<p>You can read the nitty-gritty details <a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/9446/0/apache-opensslmodsslnginx">here</a> about generating a CSR if you wish, but the TL;DR is:</p>
<ul>
<li>It’s strongly encouraged that you fill out all the required fields. Your CSR could be rejected during activation of you do not. If you are filling this CSR out for a personal or hobby site, you can enter <code>NA</code> for the ‘Organization’ and ‘Organization Unit’ fields.</li>
<li>If the certificate is being issued for a specific subdomain, you need to specify the subdomain in the ‘Common Name’ field. Example: <code>subdomain.ssl-certificate-host.com</code></li>
<li>If the certificate is meant to be a wildcard certificate, the domain should start with an asterisk. Example: <code>*.ssl-certificate-host.com</code></li>
</ul>
<p>For the purposes of this guide, the assumption will be made that you are getting the certificate for something like <code>&lt;example-domain&amp;g</code>t;.com .</p>
<p>Once you’ve run the command, you should have a <code>.csr</code> and <code>.key</code> file in your working directory. Open the <code>.csr</code> file, and copy the contents in it. It should have the header <code>----- BEGIN CERTIFICATE REQUEST -----</code>.</p>
<p>Paste the contents of the file into the <code>Enter CSR</code> field. The page will automatically fill out the domain field on the form based on the information in the CSR.</p>
<p>Once you click ‘Next’, you should see the following page:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*VYlKqYMsnvyaF0smz4q_8w.png" alt="Image" width="800" height="355" loading="lazy"></p>
<p>Check that the information is correct, and then click ‘Next’ again to go to the ‘Confirm you own the domain’ step.</p>
<h3 id="heading-step-3-confirm-you-own-the-domain"><strong>Step 3: Confirm you own the domain</strong></h3>
<p>There are a few different options that are available to you in order to do this:</p>
<ul>
<li>Email</li>
<li>HTTP-based</li>
<li>DNS-based</li>
</ul>
<p>I personally have had issues validating through email, so for the purposes of this guide, select ‘DNS-based’. This requires you to set up a <code>CNAME</code> value in your domain’s DNS settings, which we will cover later on in this guide.</p>
<p>For now, click ‘Next’ after selecting ‘DNS-based’, but if you change your mind about this form of validation later on, it’s possible to change it.</p>
<h3 id="heading-step-4-specify-who-will-receive-the-ssl-file"><strong>Step 4: Specify who will receive the SSL file</strong></h3>
<p>Confirm that the email in the field is correct. This is the email that will receive the certificate once it’s been activated.</p>
<h3 id="heading-step-5-review-and-submit"><strong>Step 5: Review and Submit</strong></h3>
<p>Confirm the information shown is correct, and then click ‘Submit’.</p>
<h3 id="heading-step-6-set-up-the-cname-record-for-validating-ownership-of-the-domain"><strong>Step 6: Set up the <code>CNAME</code> record for validating ownership of the domain</strong></h3>
<p>Once you submit the form, you will be redirected to a page showing the SSL certificate details with a helpful notification window that looks like the following:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*rBxGLLFzyBqDRe1ROxYaTw.png" alt="Image" width="800" height="147" loading="lazy"></p>
<p>Click on the link for the DNS-based DCV method. You’ll be brought to a page that shows information that you entered earlier, such as:</p>
<ul>
<li>The domain name</li>
<li>The type of web server that will have the certificate installed (should be Apache, Nginx, cPanel, or other)</li>
<li>DCV Methods In Use</li>
</ul>
<p>Access the dropdown options for the ‘Edit Methods’ button to the right of ‘DCV Methods in Use’ in order to access and click the ‘Get Record’ option.</p>
<p>A popover will appear showing the <code>CNAME</code> record you need to set up in order to confirm ownership of the domain. Copy these values to an empty text file as you’ll need to go to the ‘Advanced DNS’ page for your domain. This is accessible through ‘Dashboard’ or ‘Domain List’ &gt; ‘Manage’ (besides your domain in the list) &gt; ‘Advanced DNS’.</p>
<p>Under the ‘Host Records’ section:</p>
<ul>
<li>Click ‘Add New Record’</li>
<li>Select ‘CNAME Record’.</li>
<li>Paste the values that you copied earlier from the ‘Get Record’ popover into the corresponding fields.</li>
</ul>
<p>Before you save those values though, there’s a bit of a ‘gotcha’.</p>
<p>As Namecheap points out in their <a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/9637/68/how-can-i-complete-the-domain-control-validation-dcv-for-my-SSL-certificate#dns">documentation</a>, they “add the domain name automatically to the values submitted during record creation”. This means that the domain name that appears in the ‘host’ value is a duplicated value. Remove <code>&lt;your-custom-domain&amp;g</code>t;.com at the end of the ‘host’ value and you’ll be good to go.</p>
<p>After you save that record, it’ll take a bit of time before the certificate is issued. Once you receive the certificate in your email, proceed to step 8. If you haven’t already though, let’s set up the additional records needed in order to send people to <code>&lt;your-username&gt;.gitlab.io/&lt;your</code>-project&gt; when <code>they enter &lt;your-cus</code>tom-domain&gt;.com.</p>
<h3 id="heading-step-7-set-up-your-host-records-in-namecheap"><strong>Step 7: Set up your host records in Namecheap</strong></h3>
<p>As outlined in GitLab’s <a target="_blank" href="https://docs.gitlab.com/ee/user/project/pages/getting_started_part_three.html#dns-txt-record">docs</a>, you’ll also need to prove on GitLab’s end of things that you own the custom domain that you want to serve your GitLab Pages site on.</p>
<p>As mentioned earlier, this guide assumes that you are just looking to use <code>example.com</code> (or <code>www.example.com</code>), so you’ll want to add the following host records:</p>
<ul>
<li>Type <code>A Record</code>, Host <code>@</code>, Value <code>35.185.44.232</code> (this is the current GitLab Pages IP at the time of writing)</li>
<li>Type <code>CNAME Record</code>, Host <code>www</code> , Value <code>example.com</code> (this ensures that people who enter the 'www’ subdomain (i.e: <code>www.example.com</code>) still reach your site)</li>
<li><em>Note: You won’t be able to enter this one until you’ve added the domain through the ‘New Pages Domain’ flow outlined in Step 8.</em> Type <code>TXT Record</code>, Host <code>@</code> , Value <code>gitlab-pages-verification-code=11112222aaaabbbb</code></li>
</ul>
<h3 id="heading-step-8-install-the-certificate-in-gitlab"><strong>Step 8: Install the certificate in GitLab</strong></h3>
<p>Head on over to the ‘Pages’ page of your GitLab project that you’re trying to set up (under ‘Settings’ &gt; ‘Pages’ in the sidebar).</p>
<p>To add your custom domain that GitLab serves your Pages site on, click on the ‘New Domain’ button on the top right. You should see something like the following:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*tjmYJy0dsUrhDJH0Re4PRw.png" alt="Image" width="800" height="401" loading="lazy"></p>
<p>Enter your custom domain (<code>example.com</code>) in the domain field, and then the next part is where it gets interesting.</p>
<p>If you try just to enter your certificate (<code>example_com.crt</code>) and your private key (generated when you initially sent the certificate request) in the fields, you’ll likely get a ‘Certificate is missing intermediates’ error.</p>
<p>This is because GitLab is using something like NGINX to receive requests on it’s Pages IP before routing the request to the correct site. Namecheap, in their <a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/9474/69/how-do-i-create-a-pem-file-from-the-certificates-i-received-from-you">documentation</a>, calls out that “it is required to combine your certificate with CA certificates in a single file”.</p>
<p>What this means for you is that you need to combine the text found in your <code>example_com.crt</code> and <code>example_com.ca-bundle</code> files in the ‘certificate field’. In the end you should have something like:</p>
<p>Add the private key to the last field, and you’re done. It will take time for the changes to propagate. If you check back in a few hours, you should see an indication beside your address in the URL bar showing that your connection to your site is now secure.</p>
<h3 id="heading-resourcesreferences"><strong>Resources/References</strong></h3>
<ul>
<li><a target="_blank" href="https://about.gitlab.com/features/pages/">https://about.gitlab.com/features/pages/</a></li>
<li><a target="_blank" href="https://docs.gitlab.com/ee/user/project/pages/getting_started_part_three.html#dns-txt-record">https://docs.gitlab.com/ee/user/project/pages/getting_started_part_three.html#dns-txt-record</a></li>
<li><a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/9474/69/how-do-i-create-a-pem-file-from-the-certificates-i-received-from-you">https://www.namecheap.com/support/knowledgebase/article.aspx/9474/69/how-do-i-create-a-pem-file-from-the-certificates-i-received-from-you</a></li>
<li><a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/9637/68/how-can-i-complete-the-domain-control-validation-dcv-for-my-SSL-certificate#dns">https://www.namecheap.com/support/knowledgebase/article.aspx/9637/68/how-can-i-complete-the-domain-control-validation-dcv-for-my-SSL-certificate#dns</a></li>
<li><a target="_blank" href="https://stackoverflow.com/a/49124195/2719852">https://stackoverflow.com/a/49124195/2719852</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to get valid SSL certificates for local development ]]>
                </title>
                <description>
                    <![CDATA[ By Alex Nadalin A few weeks ago I bumped into mkcert, a tool written by Filippo. He is the same guy behind the popular heartbleed test tool. The tool in question answers one simple need: By creating a local root CA file that gets installed in your s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-valid-ssl-certificates-for-local-development-ca228240fad2/</link>
                <guid isPermaLink="false">66c35275bc39b1419091be4f</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 25 Sep 2018 14:51:35 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*1iaTVIFNnW0CVKg4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alex Nadalin</p>
<p>A few weeks ago I bumped into <a target="_blank" href="https://github.com/FiloSottile/mkcert">mkcert</a>, a tool written by <a target="_blank" href="https://github.com/FiloSottile">Filippo</a>. He is the same guy behind the popular <a target="_blank" href="https://filippo.io/Heartbleed/">heartbleed test tool</a>.</p>
<p>The tool in question answers one simple need:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/a8JOFa6GmZeaIcFSW4JfMoYzng0RzdPqqGUo" alt="Image" width="630" height="689" loading="lazy"></p>
<p>By creating a local root CA file that gets installed in your system, it makes all certificates issued by <code>mkcert</code> trusted.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ctZ7Wp94F3ICQ2g5C-1QUjWj9S9NRzLpUWuH" alt="Image" width="637" height="150" loading="lazy"></p>
<p>After downloading the latest release from GitHub, you can simply “install” it by running <code>mkcert -install</code>. Once that is done, you can create your first, trusted (by your own system) certificate:</p>
<pre><code class="lang-bash">$ mkcert somedomain.local

Using the <span class="hljs-built_in">local</span> CA at <span class="hljs-string">"/home/alex/.local/share/mkcert"</span> ✨

Created a new certificate valid <span class="hljs-keyword">for</span> the following names ?
 - <span class="hljs-string">"somedomain.local"</span>

The certificate is at <span class="hljs-string">"./somedomain.local.pem"</span> and the key at <span class="hljs-string">"./somedomain.local-key.pem"</span> ✅
</code></pre>
<p>For example, here’s how it would look like if you had to boot a Node server with SSL support:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>)

<span class="hljs-keyword">const</span> options = {
  <span class="hljs-attr">key</span>: fs.readFileSync(__dirname + <span class="hljs-string">'/somedomain.local-key.pem'</span>),
  <span class="hljs-attr">cert</span>: fs.readFileSync(__dirname + <span class="hljs-string">'/somedomain.local.pem'</span>)
};

<span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>).createServer(options, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.writeHead(<span class="hljs-number">200</span>)
  res.end(<span class="hljs-string">`Got SSL?`</span>)
}).listen(<span class="hljs-number">443</span>)
</code></pre>
<p>Pretty neat, eh?</p>
<p>What <code>mkcert</code> does is to simply add another CA file in your system.(I guess under <code>/etc/ssl/certs/ca-certificates.crt</code>, but I’m not entirely sure). Browsers consider these certificates trusted — a nice workaround to trick any HTTP client.</p>
<p>That’s it for today! Adios!</p>
<p>_Originally published at <a target="_blank" href="https://odino.org/valid-ssl-certificates-for-local-development/">odino.org</a> (<em>1st September 2018</em>)._<br>_You can follow me on <a target="_blank" href="https://twitter.com/_odino_">Twitter</a> — rants are welcome!_ ?</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to get HTTPS working on your local development environment in 5 minutes ]]>
                </title>
                <description>
                    <![CDATA[ By Daksh Shah Almost any website you visit today is protected by HTTPS. If yours isn’t yet, it should be. Securing your server with HTTPS also means that you can’t send requests to this server from one that isn’t protected by HTTPS. This poses a pro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-https-working-on-your-local-development-environment-in-5-minutes-7af615770eec/</link>
                <guid isPermaLink="false">66d45e00a326133d124409dd</guid>
                
                    <category>
                        <![CDATA[ development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ https ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 19 Jan 2018 23:09:37 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9cb0e5740569d1a4cab759.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Daksh Shah</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*8XwjYNPlrj0paEvIjn0Dcw.png" alt="Image" width="800" height="224" loading="lazy"></p>
<p>Almost any website you visit today is protected by HTTPS. If yours isn’t yet, <a target="_blank" href="https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https">it should be</a>. Securing your server with HTTPS also means that you can’t send requests to this server from one that isn’t protected by HTTPS. This poses a problem for developers who use a local development environment because all of them run on <code>http://localhost</code> out-of-the-box.</p>
<p>At the startup I’m a part of, we decided to secure our AWS Elastic Load Balancer endpoints with HTTPS as part of a move to enhance security. I ran into a situation where my local development environment’s requests to the server started getting rejected.</p>
<p>A quick Google search later, I found several articles like <a target="_blank" href="https://devcenter.heroku.com/articles/ssl-certificate-self">this</a>, <a target="_blank" href="https://www.kevinleary.net/self-signed-trusted-certificates-node-js-express-js/">this</a> or <a target="_blank" href="https://blog.praveen.science/securing-your-localhost/">this one</a> with detailed instructions on how I could implement HTTPS on <code>localhost</code>. None of these instructions seemed to work even after I followed them religiously. Chrome always threw a <code>NET::ERR_CERT_COMMON_NAME_INVALID</code> error at me.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*cQyGAORXHxsrhs5KRRBOgQ.png" alt="Image" width="800" height="424" loading="lazy"></p>
<h3 id="heading-the-problem">The problem</h3>
<p>All the detailed instructions I had found were correct for the time they were written. Not anymore.</p>
<p>After a ton of Googling, I discovered that the reason for my local certificate getting rejected was that <a target="_blank" href="https://groups.google.com/a/chromium.org/forum/m/#!topic/security-dev/IGT2fLJrAeo">Chrome had deprecated support for commonName matching in certificates</a>, in effect, requiring a subjectAltName since January 2017.</p>
<h3 id="heading-the-solution">The solution</h3>
<p>We’ll be using <a target="_blank" href="https://www.openssl.org/">OpenSSL</a> to generate all of our certificates.</p>
<h4 id="heading-step-1-root-ssl-certificate">Step 1: Root SSL certificate</h4>
<p>The first step is to create a Root Secure Sockets Layer (SSL) certificate. This root certificate can then be used to sign any number of certificates you might generate for individual domains. If you aren’t familiar with the SSL ecosystem, this <a target="_blank" href="https://support.dnsimple.com/articles/what-is-ssl-root-certificate/">article from DNSimple</a> does a good job of introducing Root SSL certificates.</p>
<p>Generate a RSA-2048 key and save it to a file <code>rootCA.key</code>. This file will be used as the key to generate the Root SSL certificate. You will be prompted for a pass phrase which you’ll need to enter each time you use this particular key to generate a certificate.</p>
<pre><code class="lang-bash">openssl genrsa -des3 -out rootCA.key 2048
</code></pre>
<p>You can use the key you generated to create a new Root SSL certificate. Save it to a file named<code>rootCA.pem</code>. This certificate will have a validity of 1,024 days. Feel free to change it to any number of days you want. You’ll also be prompted for other optional information.</p>
<pre><code class="lang-bash">openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*76xehIse7mPGF094ojiBBw.png" alt="Image" width="800" height="590" loading="lazy"></p>
<h4 id="heading-step-2-trust-the-root-ssl-certificate">Step 2: Trust the root SSL certificate</h4>
<p>Before you can use the newly created Root SSL certificate to start issuing domain certificates, there’s one more step. You need to to tell your Mac to trust your root certificate so all individual certificates issued by it are also trusted.</p>
<p>Open Keychain Access on your Mac and go to the Certificates category in your System keychain. Once there, import the <code>rootCA.pem</code> using File &gt; Import Items. Double click the imported certificate and change the “When using this certificate:” dropdown <strong>to Always Tr</strong>ust in the Trust section.</p>
<p>Your certificate should look something like this inside Keychain Access if you’ve correctly followed the instructions till now.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*NWwMb0yV9ClHDj87Kug9Ng.png" alt="Image" width="800" height="514" loading="lazy"></p>
<h4 id="heading-step-2-domain-ssl-certificate">Step 2: Domain SSL certificate</h4>
<p>The root SSL certificate can now be used to issue a certificate specifically for your local development environment located at <code>localhost</code>.</p>
<p>Create a new OpenSSL configuration file <code>server.csr.cnf</code> so you can import these settings when creating a certificate instead of entering them on the command line.</p>
<pre><code class="lang-bash">[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=US
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost
</code></pre>
<p>Create a <code>v3.ext</code> file in order to create a <a target="_blank" href="https://en.wikipedia.org/wiki/X.509">X509 v3 certificate</a>. Notice how we’re specifying <code>subjectAltName</code> here.</p>
<pre><code class="lang-bash">authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
</code></pre>
<p>Create a certificate key for <code>localhost</code> using the configuration settings stored in <code>server.csr.cnf</code>. This key is stored in <code>server.key</code>.</p>
<pre><code class="lang-bash">openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config &lt;( cat server.csr.cnf )
</code></pre>
<p>A certificate signing request is issued via the root SSL certificate we created earlier to create a domain certificate for <code>localhost</code>. The output is a certificate file called <code>server.crt</code>.</p>
<pre><code class="lang-bash">openssl x509 -req -<span class="hljs-keyword">in</span> server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*kulsSyc0-ylsevP5eIlktA.png" alt="Image" width="800" height="467" loading="lazy"></p>
<h4 id="heading-use-your-new-ssl-certificate">Use your new SSL certificate</h4>
<p>You’re now ready to secure your <code>localhost</code> with HTTPS. Move the <code>server.key</code> and <code>server.crt</code> files to an accessible location on your server and include them when starting your server.</p>
<p>In an Express app written in Node.js, here’s how you would do it. Make sure you do this only for your local environment. <strong>Do not use this in production</strong>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*89r7TnYG49V3zMoUnfOP7Q.png" alt="Image" width="738" height="154" loading="lazy"></p>
<p>I hope you found this tutorial useful. If you’re not comfortable with running the commands given here by yourself, I’ve created a set of handy scripts you can run quickly to generate the certificates for you. More details can be found on the <a target="_blank" href="https://github.com/dakshshah96/local-cert-generator/">GitHub repo</a>.</p>
<p><em>I love helping fellow web developers. Follow me on <a target="_blank" href="https://twitter.com/dakshshah96">Twitter</a> and let me know if you have any suggestions or feedback. If you’d like to show your appreciation towards any of the work I’ve done, be it a blog post, an open source project or just a funny tweet, you can <a target="_blank" href="https://www.buymeacoffee.com/dakshshah96">buy me a cup of coffee</a>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ OpenSSL command cheatsheet ]]>
                </title>
                <description>
                    <![CDATA[ By Alexey Samoshkin When it comes to security-related tasks, like generating keys, CSRs, certificates, calculating digests, debugging TLS connections and other tasks related to PKI and HTTPS, you’d most likely end up using the OpenSSL tool. OpenSSL i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/openssl-command-cheatsheet-b441be1e8c4a/</link>
                <guid isPermaLink="false">66c35c4acf1314a450f0d733</guid>
                
                    <category>
                        <![CDATA[ development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jan 2018 20:15:02 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*3L4lzv7L5K6VcauwadO_7w.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alexey Samoshkin</p>
<p>When it comes to security-related tasks, like generating keys, CSRs, certificates, calculating digests, debugging TLS connections and other tasks related to PKI and HTTPS, you’d most likely end up using the OpenSSL tool.</p>
<p>OpenSSL includes tonnes of features covering a broad range of use cases, and it’s difficult to remember its syntax for all of them and quite easy to get lost. <code>man</code> pages are not so helpful here, so often we just Google “openssl how to [use case here]” or look for some kind of “openssl cheatsheet” to recall the usage of a command and see examples.</p>
<p>This post is my personal collection of <code>openssl</code> command snippets and examples, grouped by use case.</p>
<h3 id="heading-use-cases">Use cases</h3>
<p>Here is a list of use cases, that I’ll be covering:</p>
<ol>
<li><a class="post-section-overview" href="#0507">Working with RSA and ECDSA keys</a></li>
<li><a class="post-section-overview" href="#bdf8">Create certificate signing requests (CSR)</a></li>
<li><a class="post-section-overview" href="#b723">Create X.509 certificates</a></li>
<li><a class="post-section-overview" href="#2322">Verify CSRs or certificates</a></li>
<li><a class="post-section-overview" href="#4fe9">Calculate message digests and base64 encoding</a></li>
<li><a class="post-section-overview" href="#4d47">TLS client to connect to a remote server</a></li>
<li><a class="post-section-overview" href="#0f65">Measure TLS connection and handshake time</a></li>
<li><a class="post-section-overview" href="#ce64">Convert between encoding (PEM, DER) and container formats (PKCS12, PKCS7)</a></li>
<li><a class="post-section-overview" href="#dcab">List ciphers suites</a></li>
<li><a class="post-section-overview" href="#e48c">Manually check certificate revocation status from OCSP responder</a></li>
</ol>
<p>Surely, this is not a complete list, but it covers the most common use cases and includes those I’ve been working with. For example, I skip encryption and decryption, or using openssl for CA management. <code>openssl</code> is like a universe. You never know where it ends. ?</p>
<h3 id="heading-working-with-rsa-and-ecdsa-keys">Working with RSA and ECDSA keys</h3>
<p>In the commands below, replace <code>[bits]</code> with the key size (For example, 2048, 4096, 8192).</p>
<p>Generate an RSA key:<br><code>openssl genrsa -out example.key [bits]</code></p>
<p>Print public key or modulus only:<br><code>openssl rsa -in example.key -pubout</code><br><code>openssl rsa -in example.key -noout -modulus</code></p>
<p>Print textual representation of RSA key:<br><code>openssl rsa -in example.key -text -noout</code></p>
<p>Generate new RSA key and encrypt with a pass phrase based on AES CBC 256 encryption:<br><code>openssl genrsa -aes256 -out example.key [bits]</code></p>
<p>Check your private key. If the key has a pass phrase, you’ll be prompted for it:<br><code>openssl rsa -check -in example.key</code></p>
<p>Remove passphrase from the key:<br><code>openssl rsa -in example.key -out example.key</code></p>
<p>Encrypt existing private key with a pass phrase:<br><code>openssl rsa -des3 -in example.key -out example_with_pass.key</code></p>
<p>Generate ECDSA key. <code>curve</code> is to be replaced with: <code>prime256v1</code>, <code>secp384r1</code>, <code>secp521r1</code>, or any other supported elliptic curve:<br><code>openssl ecparam -genkey -name [curve] | openssl ec -out example.ec.key</code></p>
<p>Print ECDSA key textual representation:<br><code>openssl ec -in example.ec.key -text -noout</code></p>
<p>List available EC curves, that OpenSSL library supports:<br><code>openssl ecparam -list_curves</code></p>
<p>Generate DH params with a given length:<br><code>openssl dhparam -out dhparams.pem [bits]</code></p>
<h3 id="heading-create-certificate-signing-requests-csr">Create certificate signing requests (CSR)</h3>
<p>In the commands below, replace <code>[digest]</code> with the name of the supported hash function: <code>md5</code>, <code>sha1</code>, <code>sha224</code>, <code>sha256</code>, <code>sha384</code> or <code>sha512</code>, etc. It’s better to avoid weak functions like <code>md5</code> and <code>sha1</code>, and stick to <code>sha256</code> and above.</p>
<p>Create a CSR from existing private key.<br><code>openssl req -new -key example.key -out example.csr -[digest]</code></p>
<p>Create a CSR and a private key without a pass phrase in a single command:<br><code>openssl req -nodes -newkey rsa:[bits] -keyout example.key -out example.csr</code></p>
<p>Provide CSR subject info on a command line, rather than through interactive prompt.<br><code>openssl req -nodes -newkey rsa:[bits] -keyout example.key -out example.csr -subj "/C=UA/ST=Kharkov/L=Kharkov/O=Super Secure Company/OU=IT Department/CN=example.com"</code></p>
<p>Create a CSR from existing certificate and private key:<br><code>openssl x509 -x509toreq -in cert.pem -out example.csr -signkey example.key</code></p>
<p>Generate a CSR for multi-domain SAN certificate by supplying an openssl config file:<br><code>openssl req -new -key example.key -out example.csr -config req.conf</code></p>
<p>where <code>req.conf</code>:</p>
<pre><code>[req]prompt=nodefault_md = sha256distinguished_name = dnreq_extensions = req_ext
</code></pre><pre><code>[dn]CN=example.com
</code></pre><pre><code>[req_ext]subjectAltName=@alt_names
</code></pre><pre><code>[alt_names]DNS<span class="hljs-number">.1</span>=example.comDNS<span class="hljs-number">.2</span>=www.example.comDNS<span class="hljs-number">.3</span>=ftp.example.com
</code></pre><h3 id="heading-create-x509-certificates">Create X.509 certificates</h3>
<p>Create self-signed certificate and new private key from scratch:<br><code>openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.crt -x509 -days 365</code></p>
<p>Create a self signed certificate using existing CSR and private key:<br><code>openssl x509 -req -in example.csr -signkey example.key -out example.crt -days 365</code></p>
<p>Sign child certificate using your own “CA” certificate and it’s private key. If you were a CA company, this shows a very naive example of how you could issue new certificates.<br><code>openssl x509 -req -in child.csr -days 365 -CA ca.crt -CAkey ca.key -set_serial 01 -out child.crt</code></p>
<p>Print textual representation of the certificate<br><code>openssl x509 -in example.crt -text -noout</code></p>
<p>Print certificate’s fingerprint as md5, sha1, sha256 digest:<br><code>openssl x509 -in cert.pem -fingerprint -sha256 -noout</code></p>
<h3 id="heading-verify-csrs-or-certificates">Verify CSRs or certificates</h3>
<p>Verify a CSR signature:<br><code>openssl req -in example.csr -verify</code></p>
<p>Verify that private key matches a certificate and CSR:<br><code>openssl rsa -noout -modulus -in example.key | openssl sha256</code><br><code>openssl x509 -noout -modulus -in example.crt | openssl sha256</code><br><code>openssl req -noout -modulus -in example.csr | openssl sha256</code></p>
<p>Verify certificate, provided that you have root and any intemediate certificates configured as trusted on your machine:<br><code>openssl verify example.crt</code></p>
<p>Verify certificate, when you have intermediate certificate chain. Root certificate is not a part of bundle, and should be configured as a trusted on your machine.<br><code>openssl verify -untrusted intermediate-ca-chain.pem example.crt</code></p>
<p>Verify certificate, when you have intermediate certificate chain and root certificate, that is not configured as a trusted one.<br><code>openssl verify -CAFile root.crt -untrusted intermediate-ca-chain.pem child.crt</code></p>
<p>Verify that certificate served by a remote server covers given host name. Useful to check your mutlidomain certificate properly covers all the host names.<br><code>openssl s_client -verify_hostname [www.example.com](http://www.example.com) -connect example.com:443</code></p>
<h3 id="heading-calculate-message-digests-and-base64-encoding">Calculate message digests and base64 encoding</h3>
<p>Calculate <code>md5</code>, <code>sha1</code>, <code>sha256</code>, <code>sha384</code>, <code>sha512</code>digests:<br><code>openssl dgst -[hash_function] &lt;input.f</code>i<code>le</code><br><code>cat input.file | openssl [hash_functi</code>on]</p>
<p>Base64 encoding and decoding:<br><code>cat /dev/urandom | head -c 50 | openssl base64 | openssl base64 -d</code></p>
<h3 id="heading-tls-client-to-connect-to-a-remote-server">TLS client to connect to a remote server</h3>
<p>Connect to a server supporting TLS:<br><code>openssl s_client -connect [example.com:443](http://www.google.com:443)</code><br><code>openssl s_client -host example.com -port 443</code></p>
<p>Connect to a server and show full certificate chain:<br><code>openssl s_client -showcerts -host example.com -port 443 &lt;/dev/n</code>ull</p>
<p>Extract the certificate:<br><code>openssl s_client -connect example.com:443 2&gt;&amp;1 &lt; /dev/null | sed -n '/-----BEGIN/,/-----END/p' &gt; certif</code>icate.pem</p>
<p>Override SNI (Server Name Indication) extension with another server name. Useful for testing when multiple secure sites are hosted on same IP address:<br><code>openssl s_client -servername [www.](http://www.foobbz.site)example.com -host example.com -port 443</code></p>
<p>Test TLS connection by forcibly using specific cipher suite, e.g. <code>ECDHE-RSA-AES128-GCM-SHA256</code>. Useful to check if a server can properly talk via different configured cipher suites, not one it prefers.<br><code>openssl s_client -host example.com -port 443 -cipher ECDHE-RSA-AES128-GCM-SHA256 2&gt;&amp;1 &lt;/de</code>v/null</p>
<h3 id="heading-measure-tls-connection-and-handshake-time">Measure TLS connection and handshake time</h3>
<p>Measure SSL connection time without/with session reuse:<br><code>openssl s_time -connect example.com:443 -new</code><br><code>openssl s_time -connect example.com:443 -reuse</code></p>
<p>Roughly examine TCP and SSL handshake times using <code>curl</code>:<br><code>curl -kso /dev/null -w "tcp:%{time_connect}, ssldone:%{time_appconnect}\n" https://example.com</code></p>
<p>Measure speed of various security algorithms:<br><code>openssl speed rsa2048</code><br><code>openssl speed ecdsap256</code></p>
<h3 id="heading-convert-between-encoding-and-container-formats">Convert between encoding and container formats</h3>
<p>Convert certificate between DER and PEM formats:<br><code>openssl x509 -in example.pem -outform der -out example.der</code><br><code>openssl x509 -in example.der -inform der -out example.pem</code></p>
<p>Combine several certificates in PKCS7 (P7B) file:<br><code>openssl crl2pkcs7 -nocrl -certfile child.crt -certfile ca.crt -out example.p7b</code></p>
<p>Convert from PKCS7 back to PEM. If PKCS7 file has multiple certificates, the PEM file will contain all of the items in it.<br><code>openssl pkcs7 -in example.p7b -print_certs -out example.crt</code></p>
<p>Combine a PEM certificate file and a private key to PKCS#12 (.pfx .p12). Also, you can add a chain of certificates to PKCS12 file.<br><code>openssl pkcs12 -export -out certificate.pfx -inkey privkey.pem -in certificate.pem -certfile ca-chain.pem</code></p>
<p>Convert a PKCS#12 file (.pfx .p12) containing a private key and certificates back to PEM:<br><code>openssl pkcs12 -in keystore.pfx -out keystore.pem -nodes</code></p>
<h3 id="heading-list-cipher-suites">List cipher suites</h3>
<p>List available TLS cipher suites, openssl client is capable of:<br><code>openssl ciphers -v</code></p>
<p>Enumerate all individual cipher suites, which are described by a short-hand OpenSSL cipher list string. This is useful when you’re configuring server (like Nginx), and you need to test your <code>ssl_ciphers</code> string.<br><code>openssl ciphers -v 'EECDH+ECDSA+AESGCM:EECDH+aRSA+SHA256:EECDH:DHE+AESGCM:DHE:!RSA!aNULL:!eNULL:!LOW:!RC4'</code></p>
<h3 id="heading-manually-check-certificate-revocation-status-from-ocsp-responder">Manually check certificate revocation status from OCSP responder</h3>
<p>This is a multi-step process:</p>
<ol>
<li>Retrieve the certificate from a remote server</li>
<li>Obtain the intermediate CA certificate chain</li>
<li>Read OCSP endpoint URI from the certificate</li>
<li>Request a remote OCSP responder for certificate revocation status</li>
</ol>
<p>First, retrieve the certificate from a remote server:<br><code>openssl s_client -connect example.com:443 2&gt;&amp;1 &lt; /dev/null | sed -n '/-----BEGIN/,/-----END/p' &gt;</code> cert.pem</p>
<p>You’d also need to obtain intermediate CA certificate chain. Use <code>-showcerts</code> flag to show full certificate chain, and manually save all intermediate certificates to <code>chain.pem</code> file:<br><code>openssl s_client -showcerts -host example.com -port 443 &lt;/dev/n</code>ull</p>
<p>Read OCSP endpoint URI from the certificate:<br><code>openssl x509 -in cert.pem -noout -ocsp_uri</code></p>
<p>Request a remote OCSP responder for certificate revocation status using the URI from the above step (e.g. http://ocsp.stg-int-x1.letsencrypt.org).<br><code>openssl ocsp -header "Host" "ocsp.stg-int-x1.letsencrypt.org" -issuer chain.pem -VAfile chain.pem -cert cert.pem -text -url [http://ocsp.stg-int-x1.letsencrypt.org](http://ocsp.stg-int-x1.letsencrypt.org)</code></p>
<h3 id="heading-resources">Resources</h3>
<p>I’ve put together a few resources about OpenSSL that you may find useful.</p>
<p>OpenSSL Essentials: Working with SSL Certificates, Private Keys and CSRs | DigitalOcean — <a target="_blank" href="https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs">https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs</a></p>
<p>The Most Common OpenSSL Commands — <a target="_blank" href="https://www.sslshopper.com/article-most-common-openssl-commands.html">https://www.sslshopper.com/article-most-common-openssl-commands.html</a></p>
<p>OpenSSL: Working with SSL Certificates, Private Keys and CSRs — <a target="_blank" href="https://www.dynacont.net/documentation/linux/openssl/">https://www.dynacont.net/documentation/linux/openssl/</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
