<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Quartz Technology</title>
    <description>The latest articles on DEV Community by Quartz Technology (@quartztechnology).</description>
    <link>https://dev.to/quartztechnology</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1032686%2F5c990fc1-b647-41fb-ac69-d27bf9d217b8.png</url>
      <title>DEV Community: Quartz Technology</title>
      <link>https://dev.to/quartztechnology</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/quartztechnology"/>
    <language>en</language>
    <item>
      <title>RETHV - Building Reth for the RISC-V platform</title>
      <dc:creator>Quartz Technology</dc:creator>
      <pubDate>Fri, 28 Jun 2024 16:41:18 +0000</pubDate>
      <link>https://dev.to/quartztechnology/rethv-building-reth-for-the-risc-v-platform-17ji</link>
      <guid>https://dev.to/quartztechnology/rethv-building-reth-for-the-risc-v-platform-17ji</guid>
      <description>&lt;p&gt;We describe how we managed to run &lt;a href="https://github.com/paradigmxyz/reth"&gt;Reth&lt;/a&gt;, the Rust Ethereum execution client maintained by Paradigm and the open-source community, on a RISC-V environnement.&lt;/p&gt;

&lt;p&gt;As we faced issues and learned many things, we wanted not only to share the finished PoC but also the journey itself. If you'd like to chat about running Reth on RISC-V in more details, feel free to &lt;a href="//mailto:contact@quartz.technology"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last but not least, we are not experts on the topics described in the document - we might have missed easy fixes, misunderstood concepts or over-engineered some solutions, we encourage you to let us know.&lt;/p&gt;

&lt;p&gt;Happy reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
The RISC-V environnement

&lt;ul&gt;
&lt;li&gt;Bare Metal&lt;/li&gt;
&lt;li&gt;QEMU to the rescue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Cross-Compiling Reth&lt;/li&gt;
&lt;li&gt;Cross-Compilation Target&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.tomdbx-bindgen-configuration"&gt;MDBX Bindgen Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Building Reth&lt;/li&gt;
&lt;li&gt;
Wrapping Up

&lt;ul&gt;
&lt;li&gt;Custom Docker image for RISC-V toolchain&lt;/li&gt;
&lt;li&gt;Using the non-trivial approach&lt;/li&gt;
&lt;li&gt;Using a simpler approach&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Running Reth&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Acknowledgments&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Authors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Our goal was to be able to run Reth on a RISC-V GNU Linux. Why? Because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We believe it enhances client diversity. It's not only about what is the most used client implementation, but also what hardware it runs on.&lt;/li&gt;
&lt;li&gt;It's an amazing challenge. We learned many things about cross-compilation, QEMU and the tools used in Reth.&lt;/li&gt;
&lt;li&gt;Extending the previous reason, we just wanted to share our journey with the community. Maybe it'll help some of you get started on RISC-V, exploring QEMU and more.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll explain how we managed to configure a RISC-V environnement, how we cross-compiled Reth for the RISC-V target and present the tools used to achieve it. We'll also recap the limitations we currently know about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RISC-V environnement &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this first section, we describe how we failed to run Reth on a non-compatible bare-metal environnement, which led us to use a VM with the help of QEMU. &lt;/p&gt;

&lt;h3&gt;
  
  
  Bare Metal &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;At the beginning, we really wanted to run Reth on a bare-metal server with a RISC-V processor.&lt;/p&gt;

&lt;p&gt;We used the &lt;a href="https://labs.scaleway.com/en/em-rv1/"&gt;Elastic Metal RV1 instances from Scaleway&lt;/a&gt; but faced a first error we previously encountered when trying to run Reth on ARM64 machines: the virtual memory layout on Linux.&lt;br&gt;
In a nutshell, the Linux kernel can be compiled to use a specific virtual memory layout, but the hardware on the machine might not support all of them.&lt;br&gt;
Scaleway's instances only support SV39 mode at best, while we need SV48 at least. Not using a proper virtual memory layout leads to an error which was &lt;a href="https://github.com/paradigmxyz/reth/issues/2211"&gt;documented in the Reth issue here&lt;/a&gt; .&lt;br&gt;
On RISC-V Linux, the SV39 mode allows up to 256 GB of user-space virtual memory while the SV48 allows up to 128 TB - as specified in the &lt;a href="https://www.kernel.org/doc/html/v6.4-rc7/riscv/vm-layout.html"&gt;kernel documentation&lt;/a&gt;.&lt;br&gt;
Check-out the issue linked above to learn more about the underlying reasons of why this is an issue for Reth, onbjerg did an amazing job explaining it in simple terms.&lt;/p&gt;

&lt;p&gt;When we started the project, Scaleway was the only cloud provider with RISC-V instances and we did not have a dev board at home, which led us to look for another setup: using QEMU to create a RISC-V VM.&lt;/p&gt;
&lt;h3&gt;
  
  
  QEMU to the rescue &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We tried to follow the &lt;a href="https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html"&gt;official documentation for running Linux on QEMU for RISC-V&lt;/a&gt; but faced too many compilation errors on macOS with Apple Silicon.&lt;/p&gt;

&lt;p&gt;As we had a Ubuntu machine with an x86 CPU on Hetzner for development purposes, we decided to immediately switch.&lt;br&gt;
After following the instructions to compile QEMU with RISC-V compatibility and running a compatible Debian image (amazing blog post with the &lt;a href="https://colatkinson.site/linux/riscv/2021/01/27/riscv-qemu/"&gt;instructions here&lt;/a&gt;), it worked!&lt;br&gt;
You can connect to the VM using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 &lt;span class="c"&gt;# Passord: root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@debian:~# &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
6.8.12-riscv64
root@debian:~# &lt;span class="nb"&gt;cat&lt;/span&gt; /proc/cpuinfo
...
mmu             : sv57 &lt;span class="c"&gt;# Sweet, this virtual memory layout allows up to 64 PB user-space virtual memory. Enough to store da blobs.&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the provided image only has a 10 GB-size disk. If you'd like to extend it consider taking a look at this &lt;a href="https://serverfault.com/questions/324281/how-do-you-increase-a-kvm-guests-disk-space"&gt;SO answer&lt;/a&gt; and then resizing the FS using &lt;code&gt;fdisk&lt;/code&gt; (be careful, when expanding the root partition, the first sector might not be the default one) and &lt;code&gt;resize2fs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The development environnement is ready. Now is the time to build and run Reth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Compiling Reth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;To compile Reth for the RISC-V 64 target, we have different options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile natively inside the VM. Slow but less prone to errors and requires less configuration tweaks.&lt;/li&gt;
&lt;li&gt;Compile using the cross-compiler. Requires to setup the tools first but leads to way faster compilation time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first option is actually really easy: just follow the official documentation to &lt;a href="https://reth.rs/installation/source.html"&gt;build Reth from source&lt;/a&gt; from within the VM.&lt;br&gt;
The second option is a bit more complex: we can either use install the cross-compiler from a package manager or build it from source. &lt;/p&gt;

&lt;p&gt;As your distribution may very from our own, we chose to build it from the &lt;a href="https://github.com/riscv-collab/riscv-gnu-toolchain"&gt;official toolchain sources&lt;/a&gt;. In fact, we built a &lt;a href="https://hub.docker.com/layers/quartztech/riscv-gnu-toolchain/latest/images/sha256-5e97020d214ba5abc16709db4f1e3c39c2c0cc5417fb901506a3297284af62b7?context=repo"&gt;Docker image&lt;/a&gt; which contains the RISC-V toolchain built from source for both the &lt;code&gt;amd64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt; platforms.&lt;/p&gt;

&lt;p&gt;From there, it's as easy as just running &lt;code&gt;cargo build&lt;/code&gt; right? Well, there are two details.&lt;br&gt;
The cross-compilation target must be specified and requires some extra parameters, and the MDBX auto-generated bindings requires extra-configuration.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cross-Compilation Target &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;When cross-compiling in Rust using cargo, the target can be specified using the &lt;code&gt;--target&lt;/code&gt; flag.&lt;br&gt;
Here, we will inform cargo that the target is &lt;code&gt;riscv64gc-unknown-linux-gnu&lt;/code&gt;.&lt;br&gt;
One thing we discovered was that another target we aimed for, &lt;code&gt;riscv64gc-unknown-none-elf&lt;/code&gt;, is not yet fully supported by Rust. Namely, it does not support std right now and therefore Reth cannot be cross-compiled for this target.&lt;/p&gt;

&lt;p&gt;During the cross-compilation, the linker also must be specified manually, and we chose the easiest way (an environnement variable) to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu-gcc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if we try to build Reth, the compilation will fail due to the custom &lt;code&gt;mdbx-sys&lt;/code&gt; crate build process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
33.85 error: failed to run custom build &lt;span class="nb"&gt;command &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;reth-mdbx-sys v1.0.0 &lt;span class="o"&gt;(&lt;/span&gt;/build/crates/storage/libmdbx-rs/mdbx-sys&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
33.85
33.85 Caused by:
33.85   process didn&lt;span class="s1"&gt;'t exit successfully: `/build/target/release/build/reth-mdbx-sys-c89ac4f3243e36e2/build-script-build` (exit status: 101)
33.85   --- stdout
33.85   cargo:rerun-if-changed=/build/crates/storage/libmdbx-rs/mdbx-sys/libmdbx
33.85
33.85   --- stderr
33.85   /build/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h:80:2: warning: "The RISC-V architecture is intentionally insecure by design.   Please delete this admonition at your own risk,   if you make such decision informed and consciously.   Refer to https://clck.ru/32d9xH for more information." [-W#warnings]
33.85   /usr/include/stdint.h:26:10: fatal error: '&lt;/span&gt;bits/libc-header-start.h&lt;span class="s1"&gt;' file not found
...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's fix it by tweaking the bindgen configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  MDBX Bindgen Configuration &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;To build the &lt;code&gt;mdbx-sys&lt;/code&gt; crate bindings, the bindgen tool is used. As it uses clang to generate the C/C++/Rust bindings, it does not know about the RISC-V toolchain and we must specify it manually.&lt;br&gt;
Hopefully, as stated in the bindgen's README, we can pass extra flags to clang using the &lt;code&gt;BINDGEN_EXTRA_CLANG_ARGS&lt;/code&gt; environnement variables (we could also tweak the &lt;code&gt;build.rs&lt;/code&gt; file in the crate, but we did not wanted to temper with the sources).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The sysroot for the quartztech/riscv-gnu-toolchain image is in /usr/local/&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BINDGEN_EXTRA_CLANG_ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--sysroot=/usr/local/sysroot"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can build Reth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Reth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the command to build reth using our RISC-V cross-compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; riscv64gc-unknown-linux-gnu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping Up &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Custom Docker image for RISC-V toolchain &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Here's our Dockerfile used as the based image in the next sub-section.&lt;br&gt;
It contains the RISC-V toolchain built from source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ubuntu:22.04&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    autoconf &lt;span class="se"&gt;\
&lt;/span&gt;    automake &lt;span class="se"&gt;\
&lt;/span&gt;    autotools-dev &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    python3 &lt;span class="se"&gt;\
&lt;/span&gt;    python3-pip &lt;span class="se"&gt;\
&lt;/span&gt;    libmpc-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libmpfr-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libgmp-dev &lt;span class="se"&gt;\
&lt;/span&gt;    gawk &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    bison &lt;span class="se"&gt;\
&lt;/span&gt;    flex &lt;span class="se"&gt;\
&lt;/span&gt;    texinfo &lt;span class="se"&gt;\
&lt;/span&gt;    gperf &lt;span class="se"&gt;\
&lt;/span&gt;    libtool &lt;span class="se"&gt;\
&lt;/span&gt;    patchutils &lt;span class="se"&gt;\
&lt;/span&gt;    bc &lt;span class="se"&gt;\
&lt;/span&gt;    zlib1g-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libexpat-dev &lt;span class="se"&gt;\
&lt;/span&gt;    ninja-build &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    cmake &lt;span class="se"&gt;\
&lt;/span&gt;    libglib2.0-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libslirp-dev

&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/riscv/riscv-gnu-toolchain .

&lt;span class="c"&gt;# Newlib installation.&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./configure &lt;span class="nt"&gt;--enable-multilib&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;make

&lt;span class="c"&gt;# Linux installation.&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./configure &lt;span class="nt"&gt;--enable-multilib&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;make linux

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ubuntu:22.04&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/local /usr/local&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; [ "/bin/bash" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using the non-trivial approach &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;For the braves, here's a Dockerfile which uses the Quartz base image to cross-compile Reth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; quartztech/riscv-gnu-toolchain:latest&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/opt/riscv/bin:$PATH&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    pkg-config &lt;span class="se"&gt;\
&lt;/span&gt;    libssl-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libclang-dev

&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/root/.cargo/bin:$PATH&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;rustup target add riscv64gc-unknown-linux-gnu

&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/paradigmxyz/reth .

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-unknown-linux-gnu-gcc&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; BINDGEN_EXTRA_CLANG_ARGS="--sysroot=/usr/local/sysroot"&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; riscv64gc-unknown-linux-gnu

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; [ "/bin/bash" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using a simpler approach &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Now if you use a simpler method and just install the toolchain from a package manager, here's what the Dockerfile would look like (with Ubuntu as the base image at least):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:22.04&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    pkg-config &lt;span class="se"&gt;\
&lt;/span&gt;    libssl-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libclang-dev &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="c"&gt;# All of this article for this change ^^, I love reinventing the wheel.&lt;/span&gt;
    gcc-riscv64-linux-gnu

&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/root/.cargo/bin:$PATH&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;rustup target add riscv64gc-unknown-linux-gnu

&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/paradigmxyz/reth .

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; riscv64gc-unknown-linux-gnu

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; [ "/bin/bash" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Way simpler than everything else, sometimes it's all about installing one package that does the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Reth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The last step is to copy the binary built inside the Docker image to the RISC-V VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;cp&lt;/span&gt; &amp;lt;containerId&amp;gt;:/build/target/riscv64gc-unknown-linux-gnu/release/reth &lt;span class="nb"&gt;.&lt;/span&gt;
scp &lt;span class="nt"&gt;-P&lt;/span&gt; 2222 reth root@localhost:/tmp
ssh root@localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 2222
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;
root@debian:~# &lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
root@debian:/tmp# &lt;span class="nb"&gt;ls
&lt;/span&gt;reth
root@debian:/tmp# ./reth node &lt;span class="nt"&gt;--full&lt;/span&gt;
2024-06-24T20:00:40.554366Z  INFO Initialized tracing, debug log directory: /root/.cache/reth/logs/mainnet
2024-06-24T20:00:40.588379Z  INFO Starting reth &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.0.0-dev (81b5fbf57)"&lt;/span&gt;
2024-06-24T20:00:40.592833Z  INFO Opening database &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.local/share/reth/mainnet/db"&lt;/span&gt;
2024-06-24T20:00:40.824511Z  INFO Configuration loaded &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.local/share/reth/mainnet/reth.toml"&lt;/span&gt;
2024-06-24T20:00:40.908347Z  INFO Verifying storage consistency.
2024-06-24T20:00:41.025506Z  INFO Database opened
2024-06-24T20:00:41.029405Z  INFO
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it is definitely NOT an environnement suited for production, it works!&lt;/p&gt;

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

&lt;p&gt;We managed to overcome some challenges to build and run Reth on RISC-V, which contributes to maximizing the diversity of the Ethereum infrastructure!&lt;/p&gt;

&lt;p&gt;Now let's not celebrate too much: RISC-V is VERY early, slow and insecure (even MDBX reminds us of this, look back at the logs ^^). It's just a proof of concept and also a good excuse for us to test new things.&lt;br&gt;
We also did not (but it's in the TODO list) synchronized a full-node entirely, and therefore can not attest that it works completely.&lt;/p&gt;

&lt;p&gt;I really encourage you to try this on your own, hopefully you'll learn a few things in the process. I spent some time reading documentation on RISC-V, the Rust bindgen, cross-compilation and many more. As everyone has it's own way of approaching this deep-focus phase, I'll let you invest your time as you wish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgments &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;All the Reth contributors for their amazing work.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/onbjerg"&gt;Onbjerg&lt;/a&gt; for his help on &lt;a href="https://github.com/paradigmxyz/reth/issues/2211#issuecomment-1613745079"&gt;debugging compilation errors on ARM64 due to memory layout configuration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://colatkinson.site/"&gt;Colin Atkinson&lt;/a&gt; for his post on &lt;a href="https://colatkinson.site/linux/riscv/2021/01/27/riscv-qemu/"&gt;running RISC-V in QEMU&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/quartz-technology/riscv-gnu-toolchain-docker"&gt;Quartz Docker image for RISC-V Toolchain&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.rust-lang.org/nightly/rustc/platform-support.html"&gt;Rust Platform Support&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html"&gt;RISC-V Linux using QEMU&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kernel.org/doc/html/v6.4-rc7/riscv/vm-layout.html"&gt;Virtual Memory Layout on RISC-V Linux&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/paradigmxyz/reth"&gt;Reth&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rust-lang/rust-bindgen?tab=readme-ov-file"&gt;Rust bindgen&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authors &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This project was made by the 🦀 at &lt;a href="https://quartz.technology"&gt;Quartz Technology&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>reth</category>
      <category>ethereum</category>
      <category>riscv</category>
    </item>
    <item>
      <title>Setup an Ethereum archive node using Reth on the Orange Pi 5</title>
      <dc:creator>Quartz Technology</dc:creator>
      <pubDate>Thu, 20 Jul 2023 16:41:49 +0000</pubDate>
      <link>https://dev.to/quartztechnology/setup-an-ethereum-archive-node-using-reth-on-the-orange-pi-5-3pa8</link>
      <guid>https://dev.to/quartztechnology/setup-an-ethereum-archive-node-using-reth-on-the-orange-pi-5-3pa8</guid>
      <description>&lt;p&gt;In this post we will prepare a custom version of Armbian for the Orange Pi 5, prepare the board's storage and run the &lt;a href="https://github.com/paradigmxyz/reth" rel="noopener noreferrer"&gt;Reth&lt;/a&gt; Ethereum execution client in archive mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;As the newest Ethereum execution client Reth was released, we wanted to share the instructions required to setup your own archive node at home using the Orange Pi 5 board.&lt;/p&gt;

&lt;p&gt;We spent some time figuring out the solution to an issue which prevented the node from running correctly due to the way the Linux distributions for this specific board were configured.&lt;/p&gt;

&lt;p&gt;For those of you who are curious, the issue itself is documented &lt;a href="https://github.com/paradigmxyz/reth/issues/2211" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the next sections, we describe what is the required hardware to get the node ready, as well as what change will be made to Linux and how to deploy the archive node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the hardware
&lt;/h2&gt;

&lt;p&gt;To be able to recompile Armbian (the &lt;em&gt;why&lt;/em&gt; is explained in the next section) we need to follow the &lt;a href="https://docs.armbian.com/Developer-Guide_Build-Preparation/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; requirements.&lt;br&gt;
On our side, we used a Thinkpad running Pop OS.&lt;/p&gt;

&lt;p&gt;The modified version of the OS needs to be written to an SD card.&lt;br&gt;
On our side, we used a SanDisk Extreme Pro microSDXC 128 GB.&lt;/p&gt;

&lt;p&gt;We also need to connect the board to the local network via the ethernet port and to the power using its USB-C port.&lt;/p&gt;

&lt;p&gt;In order to store the data of the archive node, we need external SSDs.&lt;br&gt;
On our side, and despite the fact that this is probably not the most optimised solution, we used two NVMe with 2 TB of storage each, connected to the board using a USB Hub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the OS
&lt;/h2&gt;

&lt;p&gt;As briefly mentioned in the first section, we faced an issue the first time we tried to setup the archive node.&lt;br&gt;
MDBX could not set the database size due to the page size being set to 4 KB, restricting the address space to be 512 GB maximum.&lt;/p&gt;

&lt;p&gt;So the next question is: &lt;em&gt;How can we change this page size to be bigger ?&lt;/em&gt; 🤔&lt;br&gt;
And the answer is: &lt;em&gt;When compiling the Kernel.&lt;/em&gt; 😶&lt;/p&gt;

&lt;p&gt;Thankfully, Armbian provides an excellent and easy-to-use framework to build the distribution and customise the Kernel features - including the page size.&lt;/p&gt;

&lt;p&gt;Let's get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the host machine, plug the micro SD card. Make sure that it is accessible by running the following command:&lt;/li&gt;
&lt;/ul&gt;

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

lsblk


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

&lt;/div&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

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

NAME            MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda               8:0    1 119.1G  0 disk  
└─sda1            8:1    1 119.1G  0 part  /media/xpanoramix/3137-6438
...


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Then, clone the Armbian build framework:&lt;/li&gt;
&lt;/ul&gt;

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

git clone https://github.com/armbian/build
&lt;span class="nb"&gt;cd &lt;/span&gt;build


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Finally, compile the Linux Kernel for the Orange Pi 5 and flash it to the micro SD card:&lt;/li&gt;
&lt;/ul&gt;

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

./compile.sh &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;BOARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;orangepi5 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;BUILD_MINIMAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;BUILD_DESKTOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;KERNEL_CONFIGURE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;CARD_DEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/dev/sdX"&lt;/span&gt; &lt;span class="c"&gt;# Replace "sdX" with the one for your micro SD card !&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Follow the instructions given in the terminal.&lt;br&gt;
Then, you should see the following screen:&lt;/p&gt;

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

&lt;p&gt;Select the only one and let the process continue. After a while, you should see the following screen appear. Select the "&lt;strong&gt;&lt;em&gt;jammy&lt;/em&gt;&lt;/strong&gt;" option:&lt;/p&gt;

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

&lt;p&gt;Let the process continue again, until the following screen appears. Scroll down to "&lt;strong&gt;&lt;em&gt;Kernel Features&lt;/em&gt;&lt;/strong&gt;", press Enter and change the page size from "&lt;strong&gt;&lt;em&gt;4 KB&lt;/em&gt;&lt;/strong&gt;" to "&lt;strong&gt;&lt;em&gt;64 KB&lt;/em&gt;&lt;/strong&gt;".&lt;/p&gt;

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

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

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

&lt;p&gt;Save the configuration and load it.&lt;/p&gt;

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

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

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

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

&lt;p&gt;Finally, click on the "&lt;strong&gt;&lt;em&gt;Exit&lt;/em&gt;&lt;/strong&gt;" button in the bottom-left and "&lt;strong&gt;&lt;em&gt;yes&lt;/em&gt;&lt;/strong&gt;" on the pop-up window that appears right after.&lt;/p&gt;

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

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

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

&lt;p&gt;From here, we have to wait for a bit of time until the distribution has been compiled.&lt;/p&gt;

&lt;p&gt;At the end, the Armbian image will be flashed to the device specified when running the first command.&lt;/p&gt;

&lt;p&gt;Remove it from the host machine, put it into the Orange Pi 5 board and connect power to it.&lt;/p&gt;

&lt;p&gt;It is now time to configure the archive node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the archive node
&lt;/h2&gt;

&lt;p&gt;In this section, we will do the following things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure the SSDs&lt;/li&gt;
&lt;li&gt;Setup Reth&lt;/li&gt;
&lt;li&gt;Start the archive node&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First and foremost, we need to connect to the board.&lt;br&gt;
You can either use a keyboard + monitor combo or connect using SSH. No matter which solution you decide to use, you'll be forced to choose a new password and create a default user. Just follow those instructions, no need for detailed explanations on this here.&lt;/p&gt;

&lt;p&gt;Assuming that we have connected the SSDs to the board, running the &lt;code&gt;lsblk&lt;/code&gt; command should print something similar to this:&lt;/p&gt;

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

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0   1.8T  0 disk
sdb           8:16   0   1.8T  0 disk
mtdblock0    31:0    0    16M  0 disk
mmcblk1     179:0    0 119.1G  0 disk
├─mmcblk1p1 179:1    0   256M  0 part /boot
└─mmcblk1p2 179:2    0 117.6G  0 part /var/log.hdd
                                      /
zram0       254:0    0   7.8G  0 disk &lt;span class="o"&gt;[&lt;/span&gt;SWAP]
zram1       254:1    0    50M  0 disk /var/log
nvme0n1     259:0    0 119.2G  0 disk


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

&lt;/div&gt;

&lt;p&gt;Where you can clearly see my two large NVMes at the top.&lt;/p&gt;

&lt;p&gt;We will use &lt;a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)" rel="noopener noreferrer"&gt;lvm&lt;/a&gt; to "combine" our disks into one.&lt;/p&gt;

&lt;p&gt;You can install the &lt;code&gt;lvm2&lt;/code&gt; tool using the following command:&lt;/p&gt;

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

apt &lt;span class="nb"&gt;install &lt;/span&gt;lvm2 &lt;span class="nt"&gt;-y&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Once installed, you should be able to create the physical volumes using the &lt;code&gt;pvcreate&lt;/code&gt; command:&lt;/p&gt;

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

pvcreate /dev/sda /dev/sdb


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

&lt;/div&gt;

&lt;p&gt;Then, running the &lt;code&gt;pvdisplay&lt;/code&gt; command should print something similar to this:&lt;/p&gt;

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

  &lt;span class="s2"&gt;"/dev/sda"&lt;/span&gt; is a new physical volume of &lt;span class="s2"&gt;"&amp;lt;1.82 TiB"&lt;/span&gt;
  &lt;span class="nt"&gt;---&lt;/span&gt; NEW Physical volume &lt;span class="nt"&gt;---&lt;/span&gt;
  PV Name               /dev/sda
  VG Name
  PV Size               &amp;lt;1.82 TiB
  Allocatable           NO
  PE Size               0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               Yx27XD-zoGA-USBi-oHZI-zAmh-tKpe-qLDoar

  &lt;span class="s2"&gt;"/dev/sdb"&lt;/span&gt; is a new physical volume of &lt;span class="s2"&gt;"&amp;lt;1.82 TiB"&lt;/span&gt;
  &lt;span class="nt"&gt;---&lt;/span&gt; NEW Physical volume &lt;span class="nt"&gt;---&lt;/span&gt;
  PV Name               /dev/sdb
  VG Name
  PV Size               &amp;lt;1.82 TiB
  Allocatable           NO
  PE Size               0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               ws3Poe-PE0t-fyQX-l7QT-ncWE-Ym2K-dTdCTg


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

&lt;/div&gt;

&lt;p&gt;Then, we need to create a volume group called &lt;code&gt;vg0&lt;/code&gt; using the &lt;code&gt;vgcreate&lt;/code&gt; command:&lt;/p&gt;

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

vgcreate vg0 /dev/sda /dev/sdb


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

&lt;/div&gt;

&lt;p&gt;Again, we can confirm that the volume group was created using the &lt;code&gt;vgdisplay&lt;/code&gt; command:&lt;/p&gt;

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

  &lt;span class="nt"&gt;---&lt;/span&gt; Volume group &lt;span class="nt"&gt;---&lt;/span&gt;
  VG Name               vg0
  System ID
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  2
  VG Access             &lt;span class="nb"&gt;read&lt;/span&gt;/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               &amp;lt;3.64 TiB
  PE Size               4.00 MiB
  Total PE              953864
  Alloc PE / Size       953864 / &amp;lt;3.64 TiB
  Free  PE / Size       0 / 0
  VG UUID               UE9Q3j-2TFe-BvNp-c65E-FCtY-onxA-Rwf40a



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

&lt;/div&gt;

&lt;p&gt;Almost done with the volumes ! We need to create and format the logical volume called &lt;code&gt;reth-data&lt;/code&gt; using the &lt;code&gt;lvcreate&lt;/code&gt; and &lt;code&gt;mkfs.ext4&lt;/code&gt; commands.&lt;/p&gt;

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

lvcreate &lt;span class="nt"&gt;-n&lt;/span&gt; reth-data &lt;span class="nt"&gt;-l&lt;/span&gt; 100%FREE vg0


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

&lt;/div&gt;

&lt;p&gt;(Just running the &lt;code&gt;lvdisplay&lt;/code&gt; command to confirm that everything went well)&lt;/p&gt;

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

  --- Logical volume ---
  LV Path                /dev/vg0/reth-data
  LV Name                reth-data
  VG Name                vg0
  LV UUID                0Eb4Hk-jMfH-xrtl-vIPP-rRYy-FksS-5igxBj
  LV Write Access        read/write
  LV Creation host, time orangepi5, 2023-07-12 12:22:23 +0000
  LV Status              available
  # open                 0
  LV Size                &amp;lt;3.64 TiB
  Current LE             953864
  Segments               2
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0


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

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

mkfs.ext4 /dev/vg0/reth-data


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

&lt;/div&gt;

&lt;p&gt;Now we just have to mount the volume and make sure that it will be mounted every time the board starts.&lt;/p&gt;

&lt;p&gt;To do that, we need to edit the &lt;code&gt;/etc/fstab&lt;/code&gt; file and add the following line at the end of it. Note that you can use &lt;code&gt;nano /etc/fstab&lt;/code&gt; to make the edit if you don't want to be stuck until the end of time in vim:&lt;/p&gt;

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

/dev/vg0/reth-data /mnt/reth-data ext4 defaults 0 1


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

&lt;/div&gt;

&lt;p&gt;This will mount the LVM volume at &lt;code&gt;/mnt/reth-data&lt;/code&gt;, but this location does not exist yet, so we need to create it using the &lt;code&gt;mkdir&lt;/code&gt; command:&lt;/p&gt;

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

&lt;span class="nb"&gt;mkdir&lt;/span&gt; /mnt/reth-data


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

&lt;/div&gt;

&lt;p&gt;Before we jump into deploying Reth, we just need to reboot the system using:&lt;/p&gt;

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

&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot


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

&lt;/div&gt;

&lt;p&gt;Connect back to the board, and move into the &lt;code&gt;/mnt/reth-data&lt;/code&gt; folder. The available space should be huge - you can check this using the &lt;code&gt;df -h .&lt;/code&gt; command.&lt;/p&gt;

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

&lt;span class="nb"&gt;cd&lt;/span&gt; /mnt/reth-data/


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

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

Filesystem                  Size  Used Avail Use% Mounted on
/dev/mapper/vg0-reth--data  3.6T   28K  3.4T   1% /mnt/reth-data


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

&lt;/div&gt;

&lt;p&gt;Now is the time to deploy Reth and the monitoring stack.&lt;br&gt;
We will use Docker to run everything inside multiple containers. To install the tool, please refer to the official documentation available &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once this is done, we can clone the Reth repository:&lt;/p&gt;

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

git clone https://github.com/paradigmxyz/reth.git
&lt;span class="nb"&gt;cd &lt;/span&gt;reth


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

&lt;/div&gt;

&lt;p&gt;It is recommended to switch to the latest release:&lt;/p&gt;

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

git checkout v0.1.0-alpha.3 # Replace this with the latest release tag.


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

&lt;/div&gt;

&lt;p&gt;And change a few things in the &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, the &lt;code&gt;BUILD_PROFILE&lt;/code&gt;.
```Dockerfile
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ARG BUILD_PROFILE=maxperf&lt;/p&gt;

&lt;h1&gt;
  
  
  ...
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ...
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Copy reth over from the build stage
&lt;/h1&gt;

&lt;p&gt;COPY --from=builder /app/target/maxperf/reth /usr/local/bin&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
- Then, we can add some Rust flags to enable CPU-specific optimisations: 
```Dockerfile


# Builds dependencies
RUN RUSTFLAGS="-C target-cpu=native" cargo chef cook --profile $BUILD_PROFILE --recipe-path recipe.json

# Build application
COPY . .
RUN RUSTFLAGS="-C target-cpu=native" cargo build --profile $BUILD_PROFILE --locked --bin reth


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Finally, expose a new port &lt;code&gt;8551&lt;/code&gt;:
```Dockerfile
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;EXPOSE 30303 30303/udp 9001 8545 8546 8551&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
And this is it for the changes.

Now copy and paste the following content into a new `docker-compose.yaml` file in the parent directory (`/mnt/reth-data`):

```yaml


version: "3"

services:
  reth:
    restart: always
    build:
      context: ./reth
      dockerfile: Dockerfile
    networks:
      - reth-net
    ports:
      - "30303:30303"
      - "30303:30303/udp"
      - "9001:9001"
      - "8545:8545"
      - "8546:8546"
      - "8551:8551"
    volumes:
      - ./datadir:/app/datadir/
    command: ["node", "--datadir", "/app/datadir/", "--authrpc.addr", "0.0.0.0", "--http", "--http.addr", "0.0.0.0", "--metrics", "0.0.0.0:9001"]

  lighthouse:
    restart: always
    image: sigp/lighthouse:latest
    networks:
      - reth-net
    volumes:
      - ./datadir:/app/datadir/
    command:
      - "lighthouse"
      - "bn"
      - "--checkpoint-sync-url"
      - "https://mainnet.checkpoint.sigp.io"
      - "--execution-endpoint"
      - "http://reth:8551"
      - "--execution-jwt"
      - "/app/datadir/jwt.hex"

networks:
  reth-net:

volumes:
  datadir:


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

&lt;/div&gt;

&lt;p&gt;This configuration combine both Reth (the execution client) and lighthouse (the consensus client).&lt;br&gt;
You can start the containers using the following command:&lt;/p&gt;

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

docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And you should see the building process starting. Be patient, this can take a while because we are building the most optimised binary possible of Reth.&lt;/p&gt;

&lt;p&gt;Additionally, you can setup a monitoring stack by following the instructions from the official &lt;a href="https://paradigmxyz.github.io/reth/run/observability.html" rel="noopener noreferrer"&gt;Reth documentation available here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And voilà ! Once the node is synced (which should take a few days) we will be able to play with it ! In the meantime, there's nothing better than observing the sync process:&lt;/p&gt;

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

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

&lt;p&gt;In this post, we prepared our own Ethereum archive node, from building the OS with specific features enabled up until we installed and deployed the Reth execution client.&lt;/p&gt;

&lt;p&gt;I would like to personally thank &lt;a href="https://github.com/onbjerg" rel="noopener noreferrer"&gt;onbjerg&lt;/a&gt; for his help on resolving the issue caused by the incorrect page size. He actually was the one who indirectly made Reth work on the Orange Pi 5 !&lt;/p&gt;

&lt;p&gt;Of course, we also want to say thank you to all the Reth contributors ❤️&lt;/p&gt;

&lt;p&gt;We hope this helped ! Feel free to reach us out or comment if you have any question 🚀&lt;/p&gt;

&lt;p&gt;Written by &lt;a href="https://twitter.com/0xpanoramix" rel="noopener noreferrer"&gt;0xpanoramix - Luca G.F.&lt;/a&gt; for &lt;a href="https://twitter.com/qu3rtz" rel="noopener noreferrer"&gt;Quartz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>tutorial</category>
      <category>linux</category>
      <category>arm</category>
    </item>
    <item>
      <title>Use reusable workflows to push images on GitHub Actions</title>
      <dc:creator>Quartz Technology</dc:creator>
      <pubDate>Mon, 19 Jun 2023 14:08:09 +0000</pubDate>
      <link>https://dev.to/quartztechnology/use-reusable-workflows-to-push-images-on-github-actions-2a17</link>
      <guid>https://dev.to/quartztechnology/use-reusable-workflows-to-push-images-on-github-actions-2a17</guid>
      <description>&lt;p&gt;Most applications are composed of many services, and it may lead to hundreds or thousands of GitHub actions lines to manage everything.&lt;/p&gt;

&lt;p&gt;This post explains how &lt;a href="https://docs.github.com/en/actions/using-workflows/reusing-workflows" rel="noopener noreferrer"&gt;reusable workflows&lt;/a&gt; and &lt;a href="https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs" rel="noopener noreferrer"&gt;matrix&lt;/a&gt; can reduce GitHub actions yaml to only few lines without any duplications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Let's begin with a bit of context to understand why and when the usage of reusable workflows can be useful.&lt;/p&gt;

&lt;p&gt;Here's a list of exhaustive reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have some duplications in your actions, for instance when you want to build and push your application's services on a registry (like Docker Hub, GitHub registry...)&lt;/li&gt;
&lt;li&gt;You identify common pattern, setup or steps in your CI, this could be setup step or whole processes where
the only difference can be abstract with variables. For instance, you have same steps but in different directories.&lt;/li&gt;
&lt;li&gt;You are working on a project with a lot of services that need to be tested, packaged and deployed online.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can recognize one of your project, this blog post is written for you!&lt;/p&gt;

&lt;p&gt;For this project, I will use a real case that I met for one of my client: &lt;a href="https://www.pridwen.fi" rel="noopener noreferrer"&gt;Pridwen&lt;/a&gt;. This project is a financial tool composed of multiple services, some are fetching data, there is 2 REST API, a Websocket services, telegrams bots and also additional utilities processes for backup, observabilities, update and analysis.&lt;/p&gt;

&lt;p&gt;In total, there are &lt;strong&gt;10 Python services&lt;/strong&gt; that need to be packaged, so it can be deployed on an VPS.&lt;br&gt;
All these services have common deployment processes, they are packaged into &lt;a href="https://jfrog.com/knowledge-base/a-beginners-guide-to-understanding-and-building-docker-images/" rel="noopener noreferrer"&gt;Docker images&lt;/a&gt; and then ran as services through a &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;docker compose&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As well, before doing a release in production, changes are deployed in a development environment. Which means images are &lt;strong&gt;built many times and with different tags&lt;/strong&gt; depending on the stage.&lt;/p&gt;

&lt;p&gt;The schema below shows the development and production release process. Each push on master updates the development stage and there is a manual workflow to release the stack in production.&lt;/p&gt;

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

&lt;p&gt;Indeed, each service has its own &lt;code&gt;Dockerfile&lt;/code&gt;, since all services share common dependencies, these &lt;code&gt;Dockerfile&lt;/code&gt; are located at the root of the repository as shown below:&lt;/p&gt;

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

&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;".Dockerfile"&lt;/span&gt;
&lt;span class="c"&gt;# auto_quoter.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# backend.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# eod_price_update.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# eod_price_update_manual.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# eow_performance.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# expiry_checker.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# rfq_rest.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# rfq_ws_api.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# telegram_quote.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# telegram_rfq_broadcaster_derivatives.Dockerfile&lt;/span&gt;
&lt;span class="c"&gt;# telegram_rfq_broadcaster_spot.Dockerfile&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;All those processes could lead to thousands of YAML lines, which would be so painful to write and maintain.&lt;br&gt;
But GitHub shipped a recent feature to fix this issue: &lt;a href="https://docs.github.com/en/actions/using-workflows/reusing-workflows" rel="noopener noreferrer"&gt;reusable workflows&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a reusable workflow
&lt;/h2&gt;

&lt;p&gt;The main pain point in the project was to build and push image to a registry.&lt;/p&gt;

&lt;p&gt;The common action is the following:&lt;/p&gt;

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

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build_publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and publish image&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository.&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Buildx"&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Login&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Registry"&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;registry&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;password&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# Stored as secret in GH environment&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build &amp;amp; push image&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;context of the build&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;dockerfile path&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;&amp;lt;registry address&amp;gt;/&amp;lt;repo&amp;gt;/&amp;lt;service_name&amp;gt;:&amp;lt;version tag&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you see, this is a lot of steps, which are basically the same no matter the service nor the language. You just need to pick up the write context and Dockerfile to push it to a registry.&lt;/p&gt;

&lt;p&gt;This is a typical situation where a reusable workflow could be useful.&lt;br&gt;
Before writing it, let's identify which values are dynamic and shall be abstract as variable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The context of the build, you may have your Dockerfile into different folders. Or for clarity purpose, 
you may want to explicitly set the context.&lt;/li&gt;
&lt;li&gt;The Dockerfile path, indeed because you may have multiple Dockerfile in your path, or you simplify named them
differently than &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The service name in the tag, because you want to push each services with a different image name.&lt;/li&gt;
&lt;li&gt;The version tag, since you may want to push &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;latest&lt;/code&gt; or specific versions like &lt;code&gt;v1.0.0&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⚠️ Unfortunately, reusable workflows cannot access GitHub environment or secrets, so we also need to add an extra variable to forward the registry password to the workflow.&lt;/p&gt;

&lt;p&gt;We know our common steps and dynamic variable, let's create this reusable workflow.&lt;/p&gt;

&lt;p&gt;Let's create a new file &lt;code&gt;build-push-image-reusable-workflow.yml&lt;/code&gt;.&lt;/p&gt;

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

&lt;span class="c"&gt;# Go into workflows directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; .github/workflows

&lt;span class="c"&gt;# Create new file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;build-push-image-reusable-workflow.yml


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

&lt;/div&gt;

&lt;p&gt;Then let's write the workflow:&lt;/p&gt;

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

&lt;span class="c1"&gt;# No name since it is not an Action by itself.&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Special GitHub trigger to specify a reusable workflow&lt;/span&gt;
  &lt;span class="na"&gt;workflow_call&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Define secrets into secrets key&lt;/span&gt;
    &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;REGISTRY_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Define REGISTRY_TOKEN variable&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Set as required&lt;/span&gt;

    &lt;span class="c1"&gt;# Define classic input (not hidden in CI)&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;        
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                              &lt;span class="c1"&gt;# Define app variable&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;                    &lt;span class="c1"&gt;# Set type as string&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application name&lt;/span&gt;   &lt;span class="c1"&gt;# Set description&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;                  &lt;span class="c1"&gt;# Set as required&lt;/span&gt;

      &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tag to give to the built image&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Context to use on the build&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;                           &lt;span class="c1"&gt;# Set as optional&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.'&lt;/span&gt;                              &lt;span class="c1"&gt;# Set default value to .&lt;/span&gt;

      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile to use to built the image&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Dockerfile'&lt;/span&gt;

&lt;span class="c1"&gt;# Define reusable job&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build_publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and publish image&lt;/span&gt; &lt;span class="c1"&gt;# Specify job's name&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;        &lt;span class="c1"&gt;# Run on Ubuntu runner&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository.&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Buildx"&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Login&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GitHub&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Registry"&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;registry address&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.REGISTRY_TOKEN }}&lt;/span&gt; &lt;span class="c1"&gt;# Use secret arguments through secrets.&amp;lt;variable name&amp;gt;&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build &amp;amp; Push image&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.context }}&lt;/span&gt; &lt;span class="c1"&gt;# Use input as inputs.&amp;lt;variable names&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.dockerfile }}&lt;/span&gt;
          &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;&amp;lt;registry address&amp;gt;/&amp;lt;repository&amp;gt;/${{ inputs.app }}:${{ inputs.tag }}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The reusable workflow is ready, let's use it with a matrix!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡To get more information about reusable workflows capabilities, have a look at the &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_call" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Use the workflow with matrix
&lt;/h2&gt;

&lt;p&gt;First, what is a GitHub action matrix and why using it?&lt;/p&gt;

&lt;p&gt;The matrix is a special field in the GitHub Action that will define different values that will then be inserted into a same job so GitHub can execute them in parallel. This is useful to gain time but also avoid duplication, specially in combination with reusable workflow.&lt;/p&gt;

&lt;p&gt;To make the usage of matrix possible, I reduced the number of dynamic variable to the minimum. In our case, only the name of the Dockerfile may be set.&lt;/p&gt;

&lt;p&gt;Let's write a file to push images in development stage.&lt;/p&gt;

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

&lt;span class="c"&gt;# Create new file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;dev_cd.yml


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

&lt;/div&gt;

&lt;p&gt;And inserts the following content to build and push our 10 services.&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push services to registry in dev stage.&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Update dev on push on main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-push-services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Create service key with list of each service.&lt;/span&gt;
        &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rfq_rest&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rfq_ws_api&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram_quote&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram_rfq_broadcaster_derivatives&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram_rfq_broadcaster_spot&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;auto_quoter&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expiry_checker&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eod_price_update&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eow_performance&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build ${{ matrix.service }}&lt;/span&gt; &lt;span class="c1"&gt;# Name workflow with the service processed.&lt;/span&gt;
    &lt;span class="c1"&gt;# Select the reusable workflow directly in your GH repository&lt;/span&gt;
    &lt;span class="c1"&gt;# You may update the @main to any branch you want to test the workflow&lt;/span&gt;
    &lt;span class="c1"&gt;# and then update it to main after merge.&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;gh organisation&amp;gt;/&amp;lt;repository&amp;gt;/.github/workflows/build-publish-workflows.yml@main&lt;/span&gt;
    &lt;span class="c1"&gt;# Forward secret using secrets field.&lt;/span&gt;
    &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;REGISTRY_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.REGISTRY_TOKEN }}&lt;/span&gt;
    &lt;span class="c1"&gt;# Set input using with field&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.service }}&lt;/span&gt;                   &lt;span class="c1"&gt;# Service built&lt;/span&gt;
      &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;                                     &lt;span class="c1"&gt;# Set image tag as dev&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.service }}.Dockerfile&lt;/span&gt; &lt;span class="c1"&gt;# Dockerfile to use&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here is an example of the action running on Pridwen. You might get similar update with more or less services.&lt;/p&gt;

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

&lt;p&gt;I hope this article was useful! As a DevOps, it's always painful to see complex and mystic CI/CD, I wish this article showed another way to do things to have easy and efficient processes.&lt;/p&gt;

&lt;p&gt;Feel free to reach me out or comment if you have any question 🚀&lt;/p&gt;

&lt;p&gt;❤️ Thanks again to &lt;a href="https://www.pridwen.fi" rel="noopener noreferrer"&gt;Pridwen&lt;/a&gt; for letting me use its use-case as example.&lt;/p&gt;

&lt;p&gt;Written by &lt;a href="https://twitter.com/TheRealVasek" rel="noopener noreferrer"&gt;Vasek - Tom C.&lt;/a&gt; for &lt;a href="https://twitter.com/qu3rtz" rel="noopener noreferrer"&gt;Quartz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Setup HTTPS with NGINX and Certbot</title>
      <dc:creator>Quartz Technology</dc:creator>
      <pubDate>Mon, 12 Jun 2023 15:23:33 +0000</pubDate>
      <link>https://dev.to/quartztechnology/setup-https-with-nginx-and-certbot-3e6n</link>
      <guid>https://dev.to/quartztechnology/setup-https-with-nginx-and-certbot-3e6n</guid>
      <description>&lt;h2&gt;
  
  
  Table of content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why set up HTTPS?&lt;/li&gt;
&lt;li&gt;Set up VPS environment&lt;/li&gt;
&lt;li&gt;Link domain name to VPS IP&lt;/li&gt;
&lt;li&gt;Set up basic Nginx configuration&lt;/li&gt;
&lt;li&gt;Use Certbot to enable HTTPS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the deployment of a new application, it is common to make the application accessible through a &lt;a href="https://www.cloudflare.com/en-gb/learning/dns/glossary/what-is-a-domain-name/" rel="noopener noreferrer"&gt;domain name&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a simple step, really satisfying, but I used to struggle a bit when I started to do it for my first client.&lt;/p&gt;

&lt;p&gt;Project architecture are usually the same, you got a proxy like NGINX that will take care of the redirection to your application(s).&lt;br&gt;
As security measure you setup a firewall and open port &lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt; to allow traffic on HTTP and HTTPS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd60cd4kbv72r7wv2yz1i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd60cd4kbv72r7wv2yz1i.png" alt="Basic application deployment on a VPS using NGINX as proxy exposing port 80 and 443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then it comes to set up HTTPS, and questions like "should I expose my application before enabling HTTPS?", "how do I just do that?", "wait, where do I store those configuration files?".&lt;/p&gt;

&lt;p&gt;This article targets beginners who want a simple and fast way to set HTTPS on any application deployed on a VPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why set up HTTPS?
&lt;/h2&gt;

&lt;p&gt;A bit of theory before starting, why is it important to set up HTTPS on your application?&lt;/p&gt;

&lt;p&gt;Basically, HTTPS adds a security layer around HTTP protocol thanks to TLS encryption.&lt;br&gt;
When a request is sent with HTTPS, it hides the content of the request, so it cannot be intercepted and used by an attacker.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://www.cloudflare.com/en-gb/learning/ssl/why-use-https/" rel="noopener noreferrer"&gt;great article from CloudFlare&lt;/a&gt; for the most curious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up VPS environment
&lt;/h2&gt;

&lt;p&gt;For this guide, I'll use a basic VPS with Ubuntu as operating system and the domain name &lt;code&gt;example.vasek.technology&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To begin, we need to install &lt;a href="https://www.cloudflare.com/en-gb/learning/ssl/why-use-https/" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt; and &lt;a href="https://certbot.eff.org" rel="noopener noreferrer"&gt;Certbot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nginx is a powerful tool for web serving. We will use it to catch requests sent to the domain name and redirect them to the application.&lt;br&gt;
Certbot is a simple CLI to set HTTPS on a server.&lt;/p&gt;

&lt;p&gt;You do not need to set up your application to enable HTTPS, you can do that later.&lt;/p&gt;

&lt;p&gt;Let's install Nginx.&lt;/p&gt;

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

&lt;span class="c"&gt;# Update apt dependencies&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

&lt;span class="c"&gt;# Install Nginx&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This will automatically set up Nginx as a service in your VPS so it will be automatically restart if you shut down your VPS and start it later.&lt;/p&gt;

&lt;p&gt;You can verify that Nginx is correctly configured with &lt;code&gt;sudo systemctl status nginx&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;You should also see a new folder in &lt;code&gt;etc/nginx&lt;/code&gt; containing a lot of files and folders.&lt;br&gt;
Let's not pay attention to them for now.&lt;/p&gt;

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

conf.d          koi-utf     modules-available  proxy_params     sites-enabled  win-utf
fastcgi.conf    koi-win     modules-enabled    scgi_params      snippets
fastcgi_params  mime.types  nginx.conf         sites-available  uwsgi_params


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

&lt;/div&gt;

&lt;p&gt;If you go to your IP address on your web browser, you should also see the default Nginx welcome page.&lt;/p&gt;

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

&lt;p&gt;Let's now install Certbot, to do so we will need Python.&lt;/p&gt;

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

&lt;span class="c"&gt;# Install python3&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3 python3-venv libaugeas0

&lt;span class="c"&gt;# Set up a virtual environment to not conflict with our local one&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv /opt/certbot/

&lt;span class="c"&gt;# Install pip in this environment&lt;/span&gt;
&lt;span class="nb"&gt;sudo&lt;/span&gt; /opt/certbot/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip

&lt;span class="c"&gt;# Install Certbot with nginx plugin&lt;/span&gt;
&lt;span class="nb"&gt;sudo&lt;/span&gt; /opt/certbot/bin/pip &lt;span class="nb"&gt;install &lt;/span&gt;certbot certbot-nginx

&lt;span class="c"&gt;# Create a symbolic link to access use certbot from anywhere&lt;/span&gt;
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /opt/certbot/bin/certbot /usr/bin/certbot

&lt;span class="c"&gt;# Verify certbot is installed&lt;/span&gt;
certbot &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# certbot 2.3.0&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Link domain name to VPS IP
&lt;/h2&gt;

&lt;p&gt;It is time to link your domain name to the VPS IP, so you can access the page from it.&lt;/p&gt;

&lt;p&gt;I personally use Google Domain but any domain name manager works. Let's create a &lt;a href="https://support.dnsimple.com/articles/a-record/" rel="noopener noreferrer"&gt;A record&lt;/a&gt; that points to your VPS IP.&lt;/p&gt;

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

&lt;p&gt;After few minutes, you should be able to access your website on this domain name.&lt;/p&gt;

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

&lt;p&gt;But as you see, it is still written as not secure. Let's fix that!&lt;/p&gt;
&lt;h2&gt;
  
  
  Set up basic Nginx configuration
&lt;/h2&gt;

&lt;p&gt;Create a new file &lt;code&gt;nginx.conf&lt;/code&gt; anywhere in your VPS and add the most basic configuration that will simply serve the welcome page.&lt;br&gt;
We will set up a symbolic link later to let Nginx use it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Listen on HTTP port (80)&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Serve Nginx welcome page&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Set domain name to serve.&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.vasek.technology&lt;/span&gt; &lt;span class="s"&gt;www.example.vasek.technology&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we need two last thing.&lt;/p&gt;

&lt;p&gt;First, the default index.html page in &lt;code&gt;/var/www/html&lt;/code&gt; may not be named properly. By default, Nginx will look for &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, it is always named &lt;code&gt;index.nginx-debian.html&lt;/code&gt;, let's rename it&lt;br&gt;
to &lt;code&gt;index.html&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="c"&gt;# Check for files in /var/www/html&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; /var/www/html
&lt;span class="c"&gt;# index.nginx-debian.html&lt;/span&gt;

&lt;span class="c"&gt;# Rename it to index.html&lt;/span&gt;
&lt;span class="nb"&gt;mv&lt;/span&gt; /var/www/html/index.nginx-debian.html /var/www/html/index.html


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

&lt;/div&gt;

&lt;p&gt;Secondly, Nginx will process every config files located in &lt;code&gt;/etc/nginx/sites-enabled&lt;/code&gt;.&lt;br&gt;
I usually prefer to create a symbolic link to that location, so I can maintain it from my git repository. So others can review it and if it is simpler if I want to change my VPS.&lt;/p&gt;

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

&lt;span class="c"&gt;# Create a symbolic link. Make sure to use an absolute path to your nginx config&lt;/span&gt;
&lt;span class="c"&gt;# file using $PWD variable&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;/nginx.conf"&lt;/span&gt; /etc/nginx/sites-enabled/nginx.conf 

&lt;span class="c"&gt;# Show the file to verify the symbolic link has been correctly done.&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/sites-enabled/nginx.conf 
server &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Listen on HTTP port (80)&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;
    listen &lt;span class="o"&gt;[&lt;/span&gt;::]:80&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;# Serve Nginx welcome page&lt;/span&gt;
    root /var/www/html&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;# Set domain name to serve.&lt;/span&gt;
    server_name example.vasek.technology www.example.vasek.technology&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can also remove the default configure&lt;/p&gt;

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

&lt;span class="nb"&gt;rm&lt;/span&gt; /etc/nginx/sites-enabled/default


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

&lt;/div&gt;

&lt;p&gt;Let's verify that our config is correct.&lt;/p&gt;

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

nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="c"&gt;# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok&lt;/span&gt;
&lt;span class="c"&gt;# nginx: configuration file /etc/nginx/nginx.conf test is successful&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;It is normal if you do not see your file in the log, the main config is in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; and includes any files in &lt;code&gt;/etc/nginx/sites-enabled&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we can reload nginx to apply new configuration.&lt;/p&gt;

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

nginx &lt;span class="nt"&gt;-s&lt;/span&gt; reload


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

&lt;/div&gt;

&lt;p&gt;Let's verify if the Nginx is still serving the welcome page on our domain name.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Use Certbot to enable HTTPS
&lt;/h2&gt;

&lt;p&gt;It is time set up HTTPS on our domain name. Let's run Certbot.&lt;/p&gt;

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

&lt;span class="c"&gt;# Generate SSL certificate using certbot.&lt;/span&gt;
certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; example.vasek.technology &lt;span class="nt"&gt;--email&lt;/span&gt; tom@quartz.technology


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

&lt;/div&gt;

&lt;p&gt;Note that the &lt;code&gt;--email&lt;/code&gt; is an important option, you should provide a valid address email that will stay in time. This email is used as proof of ownership and is used by site like &lt;a href="https://whois.domaintools.com" rel="noopener noreferrer"&gt;Whois&lt;/a&gt; to record all domain names and their owner.&lt;/p&gt;

&lt;p&gt;If you take a look at your &lt;code&gt;nginx.conf&lt;/code&gt;, you will see a lot of changes.&lt;/p&gt;

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

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;# Serve Nginx welcome page&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Set domain name to serve.&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.vasek.technology&lt;/span&gt; &lt;span class="s"&gt;www.example.vasek.technology&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;ipv6only=on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/example.vasek.technology-0001/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/example.vasek.technology-0001/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
    &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/options-ssl-nginx.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_dhparam&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/ssl-dhparams.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Redirect HTTP to HTTPS&lt;/span&gt;
    &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;example.vasek.technology)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;


    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.vasek.technology&lt;/span&gt; &lt;span class="s"&gt;www.example.vasek.technology&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The file has been updated by Certbot to serve HTTPS on your domain name and also redirect HTTP traffic to HTTPS.&lt;br&gt;
It may be a bit messy so clean extra spaces and reorder tabs if necessary.&lt;/p&gt;

&lt;p&gt;You can go back on your domain name and see that HTTPS is now enable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqynhoa2zl13l95dtujvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqynhoa2zl13l95dtujvu.png" alt="Nginx welcome page accessed through domain name with HTTPS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulation! You can now update your configuration to serve your application after deploying it on your VPS.&lt;/p&gt;

&lt;p&gt;For example&lt;/p&gt;

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

    &lt;span class="c1"&gt;# Serve Nginx welcome page&lt;/span&gt;
    &lt;span class="c1"&gt;# Replaced by location&lt;/span&gt;
    &lt;span class="c1"&gt;# root /var/www/html;&lt;/span&gt;


    &lt;span class="c1"&gt;# Redirect request to application listening on&lt;/span&gt;
    &lt;span class="c1"&gt;# port 3000 in the VPS.&lt;/span&gt;
    &lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I hope this article was useful to you! I remember my first time struggling to add HTTPS on my first application with 10 different tabs opened about Nginx and its obscure configuration.&lt;/p&gt;

&lt;p&gt;Feel free to reach me out or comment if you have any question 🚀&lt;/p&gt;

&lt;p&gt;Written by &lt;a href="https://twitter.com/TheRealVasek" rel="noopener noreferrer"&gt;Vasek - Tom C.&lt;/a&gt; for &lt;a href="https://twitter.com/qu3rtz" rel="noopener noreferrer"&gt;Quartz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>security</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
