{"id":5044,"date":"2018-12-10T20:05:35","date_gmt":"2018-12-10T19:05:35","guid":{"rendered":"https:\/\/monodes.com\/predaelli\/?p=5044"},"modified":"2018-12-10T16:13:17","modified_gmt":"2018-12-10T15:13:17","slug":"dehydrated-a-bash-client-for-lets-encrypt-antoine-aflalo","status":"publish","type":"post","link":"https:\/\/monodes.com\/predaelli\/2018\/12\/10\/dehydrated-a-bash-client-for-lets-encrypt-antoine-aflalo\/","title":{"rendered":"Dehydrated: a bash client for Let&#8217;s Encrypt &#8211; Antoine Aflalo"},"content":{"rendered":"<blockquote><p><a href=\"https:\/\/www.aaflalo.me\/2016\/09\/dehydrated-bash-client-lets-encrypt\/\"><img data-recalc-dims=\"1\" decoding=\"async\" class=\"alignnone size-full\" src=\"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2018\/12\/Acme_Dehydrated.jpg?w=910&#038;ssl=1\" alt=\"\"\/><\/a>Tutorial on how to use Dehydrated, a bash client for Let&#8217;s Encrypt ACME Protocol. Dehydrated helps you take care of your SSL certificates.<\/p><\/blockquote>\n<p>Source: <em><a href=\"https:\/\/www.aaflalo.me\/2016\/09\/dehydrated-bash-client-lets-encrypt\/\">Dehydrated: a bash client for Let&#8217;s Encrypt &#8211; Antoine Aflalo<\/a><\/em><\/p>\n<p><!--more--><!--nextpage--><\/p>\n<blockquote>\n<div class=\"post-header\">\n<h1 class=\"post-title\"><a title=\"Dehydrated: a bash client for Let\u2019s Encrypt\" href=\"https:\/\/www.aaflalo.me\/2016\/09\/dehydrated-bash-client-lets-encrypt\/\" rel=\"bookmark\">Dehydrated: a bash client for Let\u2019s Encrypt<\/a><\/h1>\n<\/div>\n<div class=\"featured-media\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"attachment-post-image size-post-image wp-post-image\" src=\"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2018\/12\/Acme_Dehydrated-1.jpg?resize=802%2C600&#038;ssl=1\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" srcset=\"https:\/\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2018\/12\/Acme_Dehydrated-1.jpg 802w, https:\/\/www.aaflalo.me\/wp-content\/uploads\/2016\/09\/Acme_Dehydrated-300x224.jpg 300w, https:\/\/www.aaflalo.me\/wp-content\/uploads\/2016\/09\/Acme_Dehydrated-620x464.jpg 620w, https:\/\/www.aaflalo.me\/wp-content\/uploads\/2016\/09\/Acme_Dehydrated-768x575.jpg 768w, https:\/\/www.aaflalo.me\/wp-content\/uploads\/2016\/09\/Acme_Dehydrated-370x277.jpg 370w, https:\/\/www.aaflalo.me\/wp-content\/uploads\/2016\/09\/Acme_Dehydrated-800x599.jpg 800w\" alt=\"\" width=\"802\" height=\"600\"\/><\/div>\n<div class=\"post-content\">\n<p>Dehydrated was firstly known as letsencrypt.sh but because letsencrypt is a trademark, they decided to rename the project, but keep the excellent features.<\/p>\n<h1><span id=\"Purpose\" class=\"ez-toc-section\">Purpose<\/span><\/h1>\n<div><sub>If you\u2019re already familiar with let\u2019s encrypt and the ACME protocol, you can go directly to the next section on how to use Dehydrated.<\/sub><\/div>\n<p>Let\u2019s encrypt give you the possibility&nbsp;to automatize the creation and renewal of SSL certificate. Those certificates and keys can be used for anything that uses SSL protocol like to activate https on your website, TLS on your SMTP\/IMAP server, etc \u2026 everywhere you can use an SSL cert; you can use let\u2019s encrypt.<\/p>\n<p>Let\u2019s Encrypt is an authorised CA which mean all the certificate generated by it are considered verified and will be recognised as it by the different clients (browser, email client, etc \u2026). This is one of the biggest advantages against self-signed certificates, and your users won\u2019t have to bypass a security warning or add a security exception.<\/p>\n<p>Not only the generated certificate are valid, but let\u2019s encrypt is an entirely automatize protocol, there is no need of human interaction to create and renew a certificate, all you need is a client compatible with the ACME protocol, and that were Dehydrated enter.<\/p>\n<h1><span id=\"Dehydrated\" class=\"ez-toc-section\">Dehydrated<\/span><\/h1>\n<h2><span id=\"Install\" class=\"ez-toc-section\">Install<\/span><\/h2>\n<p>Either you take one of the release packages, or you clone the repository. I advise creating a symlink after to&nbsp;<code class=\"\" data-line=\"\">\/usr\/local\/sbin\/dehydrated<\/code> it\u2019s easier like this for setting the cronjob after. You also need to have the OpenSSL&nbsp;package installed for dehydrated to work. You also need a web server, Apache or Nginx&nbsp;will do fine.<\/p>\n<div class=\"reposidget\">\n<header class=\"fontello\">\n<h2><span id=\"lukas2511_dehydrated\" class=\"ez-toc-section\"> <a href=\"https:\/\/github.com\/lukas2511\">lukas2511<\/a> \/ <a href=\"https:\/\/github.com\/lukas2511\/dehydrated\"><strong>dehydrated<\/strong><\/a> <\/span><\/h2>\n<\/header>\n<section>\n<p class=\"\">letsencrypt\/acme client implemented as a shell-script \u2013 just add water<\/p>\n<p class=\" homepage\"><a href=\"https:\/\/dehydrated.io\"><strong>https:\/\/dehydrated.io<\/strong><\/a><\/p>\n<\/section>\n<footer><span class=\"fontello star\">4,139<\/span><span class=\"fontello fork\">542<\/span><\/footer>\n<\/div>\n<\/div>\n<h2><span id=\"Configuration\" class=\"ez-toc-section\">Configuration<\/span><\/h2>\n<p>First, create a configuration folder only accessible by root:&nbsp;<code class=\"\" data-line=\"\">\/etc\/dehydrated\/<\/code> You also need to create <code class=\"\" data-line=\"\">\/var\/www\/dehydrated<\/code> that will contain the challenge files for website verification.<\/p>\n<h2><span id=\"Conf_File\" class=\"ez-toc-section\">Conf File<\/span><\/h2>\n<p>Now create a configuration file named <code class=\"\" data-line=\"\">config<\/code> using their template:<\/p>\n<div class=\"su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed\">\n<div class=\"su-spoiler-title\">Configuration File<\/div>\n<div class=\"su-spoiler-content su-clearfix\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">########################################################\n# This is the main config file for dehydrated          #\n#                                                      #\n# This file is looked for in the following locations:  #\n# $SCRIPTDIR\/config (next to this script)              #\n# \/usr\/local\/etc\/dehydrated\/config                     #\n# \/etc\/dehydrated\/config                               #\n# ${PWD}\/config (in current working-directory)         #\n#                                                      #\n# Default values of this config are in comments        #\n########################################################\n\n# Resolve names to addresses of IP version only. (curl)\n# supported values: 4, 6\n# default: &lt;unset&gt;\n#IP_VERSION=\n\n# Path to certificate authority (default: https:\/\/acme-v01.api.letsencrypt.org\/directory)\n#CA=\"https:\/\/acme-v01.api.letsencrypt.org\/directory\"\n\n# Path to license agreement (default: https:\/\/letsencrypt.org\/documents\/LE-SA-v1.1.1-August-1-2016.pdf)\n#LICENSE=\"https:\/\/letsencrypt.org\/documents\/LE-SA-v1.1.1-August-1-2016.pdf\"\n\n# Which challenge should be used? Currently http-01 and dns-01 are supported\n#CHALLENGETYPE=\"http-01\"\n\n# Path to a directory containing additional config files, allowing to override\n# the defaults found in the main configuration file. Additional config files\n# in this directory needs to be named with a '.sh' ending.\n# default: &lt;unset&gt;\n#CONFIG_D=\n\n# Base directory for account key, generated certificates and list of domains (default: $SCRIPTDIR -- uses config directory if undefined)\n#BASEDIR=$SCRIPTDIR\n\n# File containing the list of domains to request certificates for (default: $BASEDIR\/domains.txt)\n#DOMAINS_TXT=\"${BASEDIR}\/domains.txt\"\n\n# Output directory for generated certificates\n#CERTDIR=\"${BASEDIR}\/certs\"\n\n# Directory for account keys and registration information\n#ACCOUNTDIR=\"${BASEDIR}\/accounts\"\n\n# Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: \/var\/www\/dehydrated)\n#WELLKNOWN=\"\/var\/www\/dehydrated\"\n\n# Default keysize for private keys (default: 4096)\n#KEYSIZE=\"4096\"\n\n# Path to openssl config file (default: &lt;unset&gt; - tries to figure out system default)\n#OPENSSL_CNF=\n\n# Program or function called in certain situations\n#\n# After generating the challenge-response, or after failed challenge (in this case altname is empty)\n# Given arguments: clean_challenge|deploy_challenge altname token-filename token-content\n#\n# After successfully signing certificate\n# Given arguments: deploy_cert domain path\/to\/privkey.pem path\/to\/cert.pem path\/to\/fullchain.pem\n#\n# BASEDIR and WELLKNOWN variables are exported and can be used in an external program\n# default: &lt;unset&gt;\n#HOOK=\n\n# Chain clean_challenge|deploy_challenge arguments together into one hook call per certificate (default: no)\n#HOOK_CHAIN=\"no\"\n\n# Minimum days before expiration to automatically renew certificate (default: 30)\n#RENEW_DAYS=\"30\"\n\n# Regenerate private keys instead of just signing new certificates on renewal (default: yes)\n#PRIVATE_KEY_RENEW=\"yes\"\n\n# Create an extra private key for rollover (default: no)\n#PRIVATE_KEY_ROLLOVER=\"no\"\n\n# Which public key algorithm should be used? Supported: rsa, prime256v1 and secp384r1\n#KEY_ALGO=rsa\n\n# E-mail to use during the registration (default: &lt;unset&gt;)\n#CONTACT_EMAIL=\n\n# Lockfile location, to prevent concurrent access (default: $BASEDIR\/lock)\n#LOCKFILE=\"${BASEDIR}\/lock\"\n\n# Option to add CSR-flag indicating OCSP stapling to be mandatory (default: no)\n#OCSP_MUST_STAPLE=\"no\"<\/pre>\n<\/div>\n<\/div>\n<p>In the configuration file, you need absolutely to set the <strong>CONTACT_EMAIL<\/strong> to an email address you own. You should also set the <strong>HOOK<\/strong>&nbsp; variable to&nbsp;<code class=\"\" data-line=\"\">HOOK=\/etc\/dehydrated\/hook.sh<\/code>. We\u2019ll create the script just after; this hook script is called at each step of the certificate renewal\/creation process.<\/p>\n<h2><span id=\"Hook_file\" class=\"ez-toc-section\">Hook file<\/span><\/h2>\n<p>Now let\u2019s create the hook.sh. I\u2019m providing you with my hook file based on their template. &nbsp;The idea is to reload your webserver when a new certificate gets deployed, in my case it\u2019s Nginx, if you use any other one, replace Nginx by yours. I also added a line for my Dovecot and Postfix server only to restart when their certificate is generated. Fell free to use this file and modify it for your needs.<\/p>\n<div class=\"su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed\">\n<div class=\"su-spoiler-title\">Hook File<\/div>\n<div class=\"su-spoiler-content su-clearfix\">\n<div class=\"EnlighterJSWrapper enlighterEnlighterJSWrapper\">\n<ol class=\"hoverEnabled enlighterEnlighterJS EnlighterJS\">\n<li class=\" odd\"><span class=\"co1\">#!\/usr\/bin\/env bash<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"kw3\">deploy_challenge() {<\/span><\/li>\n<li class=\" even\"><span class=\"\"> local DOMAIN=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> TOKEN_FILENAME=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><span class=\"\"> TOKEN_VALUE=<\/span><span class=\"st0\">&#8220;${3}&#8221;<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"co1\"> # This hook is called once for every domain that needs to be<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # validated, including any alternative names you may have listed.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # Parameters:<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; DOMAIN<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The domain name (CN or subject alternative name) being<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # validated.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; TOKEN_FILENAME<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The name of the file containing the token to be served for HTTP<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # validation. Should be served by your web server as<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # \/.well-known\/acme-challenge\/${TOKEN_FILENAME}.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; TOKEN_VALUE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The token value that needs to be served for validation. For DNS<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # validation, this is what you want to put in the _acme-challenge<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # TXT record. For HTTP validation it is the value that is expected<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # be found in the $TOKEN_FILENAME file.<\/span><\/li>\n<li class=\" even\"><span class=\"\">}<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"kw3\">clean_challenge() {<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> local DOMAIN=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> TOKEN_FILENAME=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><span class=\"\"> TOKEN_VALUE=<\/span><span class=\"st0\">&#8220;${3}&#8221;<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"co1\"> # This hook is called after attempting to validate each domain,<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # whether or not validation was successful. Here you can delete<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # files or DNS records that are no longer needed.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The parameters are the same as for deploy_challenge.<\/span><\/li>\n<li class=\" even\"><span class=\"\">}<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"kw3\">deploy_cert() {<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> local DOMAIN=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> KEYFILE=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><span class=\"\"> CERTFILE=<\/span><span class=\"st0\">&#8220;${3}&#8221;<\/span><span class=\"\"> FULLCHAINFILE=<\/span><span class=\"st0\">&#8220;${4}&#8221;<\/span><span class=\"\"> CHAINFILE=<\/span><span class=\"st0\">&#8220;${5}&#8221;<\/span><span class=\"\"> TIMESTAMP=<\/span><span class=\"st0\">&#8220;${6}&#8221;<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"co1\"> # This hook is called once for each certificate that has been<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # produced. Here you might, for instance, copy your new certificates<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # to service-specific locations and reload the service.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # Parameters:<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; DOMAIN<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The primary domain name, i.e. the certificate common<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # name (CN).<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; KEYFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the private key.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; CERTFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the signed certificate.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; FULLCHAINFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the full certificate chain.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; CHAINFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the intermediate certificate(s).<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; TIMESTAMP<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # Timestamp when the specified certificate was created.<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"co1\"> #systemctl reload nginx<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> <a rel=\"tag\" class=\"hashtag u-tag u-category\" href=\"https:\/\/monodes.com\/predaelli\/tag\/if\/\">#if<\/a> [ &#8220;$DOMAIN&#8221; = &#8220;smtp.xxx.xxx&#8221; ]<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # then<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # systemctl restart postfix dovecot<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #fi<\/span><\/li>\n<li class=\" odd\"><span class=\"\">}<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"kw3\">unchanged_cert() {<\/span><\/li>\n<li class=\" even\"><span class=\"\"> local DOMAIN=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> KEYFILE=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><span class=\"\"> CERTFILE=<\/span><span class=\"st0\">&#8220;${3}&#8221;<\/span><span class=\"\"> FULLCHAINFILE=<\/span><span class=\"st0\">&#8220;${4}&#8221;<\/span><span class=\"\"> CHAINFILE=<\/span><span class=\"st0\">&#8220;${5}&#8221;<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"co1\"> # This hook is called once for each certificate that is still<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # valid and therefore wasn&#8217;t reissued.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # Parameters:<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; DOMAIN<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The primary domain name, i.e. the certificate common<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # name (CN).<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; KEYFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the private key.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; CERTFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the signed certificate.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; FULLCHAINFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the full certificate chain.<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; CHAINFILE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The path of the file containing the intermediate certificate(s).<\/span><\/li>\n<li class=\" odd\"><span class=\"\">}<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"kw3\">invalid_challenge() {<\/span><\/li>\n<li class=\" even\"><span class=\"\"> local DOMAIN=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> RESPONSE=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"co1\"> # This hook is called if the challenge response has failed, so domain<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # owners can be aware and act accordingly.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # Parameters:<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; DOMAIN<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The primary domain name, i.e. the certificate common<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # name (CN).<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # &#8211; RESPONSE<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # The response that the verification server returned<\/span><\/li>\n<li class=\" odd\"><span class=\"\">}<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"kw3\">request_failure() {<\/span><\/li>\n<li class=\" even\"><span class=\"\"> local STATUSCODE=<\/span><span class=\"st0\">&#8220;${1}&#8221;<\/span><span class=\"\"> REASON=<\/span><span class=\"st0\">&#8220;${2}&#8221;<\/span><span class=\"\"> REQTYPE=<\/span><span class=\"st0\">&#8220;${3}&#8221;<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"co1\"> # This hook is called when a HTTP request fails (e.g., when the ACME<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # server is busy, returns an error, etc). It will be called upon any<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # response code that does not start with &#8216;2&#8217;. Useful to alert admins<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # about problems with requests.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> #<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # Parameters:<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; STATUSCODE<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The HTML status code that originated the error.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; REASON<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The specified reason for the error.<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # &#8211; REQTYPE<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # The kind of request that was made (GET, POST&#8230;)<\/span><\/li>\n<li class=\" even\"><span class=\"\">}<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"kw3\">exit_hook() {<\/span><\/li>\n<li class=\" odd\"><span class=\"co1\"> # This hook is called at the end of a dehydrated command and can be used<\/span><\/li>\n<li class=\" even\"><span class=\"co1\"> # to do some final (cleanup or other) tasks.<\/span><\/li>\n<li class=\" odd\"><\/li>\n<li class=\" even\"><span class=\"\"> :<\/span><\/li>\n<li class=\" odd\"><span class=\"\">}<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"kw4\">HANDLER<\/span><span class=\"\">=<\/span><span class=\"st0\">&#8220;$1&#8221;<\/span><span class=\"\">; shift<\/span><\/li>\n<li class=\" even\"><span class=\"kw1\">if<\/span><span class=\"\"> [[ <\/span><span class=\"st0\">&#8220;${HANDLER}&#8221;<\/span><span class=\"\"> =~ ^(deploy_challenge|clean_challenge|deploy_cert|unchanged_cert|invalid_challenge|request_failure|exit_hook)$ ]]; <\/span><span class=\"kw1\">then<\/span><\/li>\n<li class=\" odd\"><span class=\"st0\">&#8220;$HANDLER&#8221;<\/span> <span class=\"st0\">&#8220;$@&#8221;<\/span><\/li>\n<li class=\" even\"><span class=\"kw1\">fi<\/span><\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<h2><span id=\"Domain_file\" class=\"ez-toc-section\">Domain file<\/span><\/h2>\n<p>Now in the same directory, create a <code class=\"\" data-line=\"\">domains.txt<\/code> file containing the list of domains you want a certificate for. You need to have already a web server setup with those domains.<\/p>\n<div id=\"quads-ad2\" class=\"quads-location quads-ad2\"><ins class=\"adsbygoogle\" data-ad-client=\"ca-pub-7284443005140816\" data-ad-slot=\"3985904416\" data-ad-format=\"auto\" data-adsbygoogle-status=\"done\"><\/ins><ins id=\"aswift_0_expand\"><\/ins><ins id=\"aswift_0_anchor\"><iframe id=\"aswift_0\" name=\"aswift_0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\" allowfullscreen=\"allowfullscreen\" data-mce-fragment=\"1\" width=\"661\" height=\"75\" frameborder=\"0\"><\/iframe><\/ins><\/div>\n<p>You can set multiple domains on the same line; they will be then put on the same certificate. I advise you to use this to keep subdomain and domain together.<\/p>\n<div class=\"su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed\">\n<div class=\"su-spoiler-title\">Domains.txt Example<\/div>\n<div class=\"su-spoiler-content su-clearfix\">\n<pre class=\"wp-github line-numbers language-text\"><code class=\"\" data-line=\"\"># Create certificate for &#039;example.org&#039; with an alternative name of\n# &#039;www.example.org&#039;. It will be stored in the directory ${CERT_DIR}\/example.org\nexample.org www.example.org\n\n# Create certificate for &#039;example.com&#039; with alternative names of\n# &#039;www.example.com&#039; &amp; &#039;wiki.example.com&#039;. It will be stored in the directory\n# ${CERT_DIR}\/example.com\nexample.com www.example.com wiki.example.com\n\n# Using the alias &#039;certalias&#039; create certificate for &#039;example.net&#039; with\n# alternate name &#039;www.example.net&#039; and store it in the directory\n# ${CERTDIR}\/certalias\nexample.net www.example.net &gt; certalias\n\n# Using the alias &#039;service_example_com&#039; create a wildcard certificate for\n# &#039;*.service.example.com&#039; and store it in the directory\n# ${CERTDIR}\/service_example_com\n# NOTE: It is NOT a certificate for &#039;service.example.com&#039;\n*.service.example.com &gt; service_example_com\n\n# Using the alias &#039;star_service_example_org&#039; create a wildcard certificate for\n# &#039;*.service.example.org&#039; with an alternative name of `service.example.org&#039;\n# and store it in the directory ${CERTDIR}\/star_service_example_org\n# NOTE: It is a certificate for &#039;service.example.org&#039;\n*.service.example.org service.example.org  &gt; star_service_example_org\n\n# Create a certificate for &#039;service.example.net&#039; with an alternative name of\n# &#039;*.service.example.net&#039; (which is a wildcard domain) and store it in the\n# directory ${CERTDIR}\/service.example.net\nservice.example.net *.service.example.net\n<\/code><\/pre>\n<\/div>\n<\/div>\n<h1><span id=\"Webserver\" class=\"ez-toc-section\">Webserver<\/span><\/h1>\n<h2><span id=\"WELLKNOWN\" class=\"ez-toc-section\">WELLKNOWN<\/span><\/h2>\n<p>With <code class=\"\" data-line=\"\">http-01<\/code>-type verification (default in this script, there is also support for <a href=\"https:\/\/www.aaflalo.me\/2016\/09\/dehydrated-bash-client-lets-encrypt\/#dns-server\">DNS-based verification<\/a>) Let\u2019s Encrypt (or the ACME-protocol in general) is checking if you are in control of a domain by accessing a verification file on a URL similar to<code class=\"\" data-line=\"\">http:\/\/example.org\/.well-known\/acme-challenge\/m4g1C-t0k3n<\/code>.<br \/>\nIt will do that for any (sub-)domain you want to sign a certificate for.<\/p>\n<p>At the moment you\u2019ll need to have that location available over standard HTTP on port 80 (redirect to HTTPS will work, but the starting point is always HTTP!).<\/p>\n<p>Dehydrated has a config variable called&nbsp;<code class=\"\" data-line=\"\">WELLKNOWN<\/code>which corresponds to the directory which should be served under <code class=\"\" data-line=\"\">\/.well-known\/acme-challenge<\/code> on your domain. So in the above example, the token would have been saved as <code class=\"\" data-line=\"\">$WELLKNOWN\/m4g1C-t0k3n<\/code>.<\/p>\n<p>If you only have one docroot on your server, you could easily do something like&nbsp;<code class=\"\" data-line=\"\">WELLKNOWN=\/var\/www\/.well-known\/acme-challenge<\/code> for anything else look at the example below.<\/p>\n<h3><span id=\"Example_Usage\" class=\"ez-toc-section\"><a id=\"user-content-example-usage\" class=\"anchor\" href=\"https:\/\/github.com\/lukas2511\/dehydrated\/blob\/master\/docs\/wellknown.md#example-usage\"><\/a>Example Usage<\/span><\/h3>\n<p>If you have more than one docroot (or you are using your server as a reverse proxy\/load balancer), the simple configuration mentioned above won\u2019t work, but with just a few lines of web server configuration, this can be solved.<\/p>\n<p>An example would be to create a directory <code class=\"\" data-line=\"\">\/var\/www\/dehydrated<\/code> and set <code class=\"\" data-line=\"\">WELLKNOWN=\/var\/www\/dehydrated<\/code> in the scripts config.<\/p>\n<p>You\u2019ll need to configure aliases on your Webserver:<\/p>\n<h4><span id=\"Nginx_example_config\" class=\"ez-toc-section\"><a id=\"user-content-nginx-example-config\" class=\"anchor\" href=\"https:\/\/github.com\/lukas2511\/dehydrated\/blob\/master\/docs\/wellknown.md#nginx-example-config\"><\/a>Nginx example config<\/span><\/h4>\n<p>With Nginx you\u2019ll need to add this to any of your <code class=\"\" data-line=\"\">server<\/code>\/VHost config blocks:<\/p>\n<div class=\"EnlighterJSWrapper enlighterEnlighterJSWrapper\">\n<ol class=\"hoverEnabled enlighterEnlighterJS EnlighterJS\">\n<li class=\" odd\"><span class=\"\">server <\/span><span class=\"br0\">{<\/span><\/li>\n<li class=\" even\"><span class=\"br0\">[<\/span><span class=\"\">&#8230;<\/span><span class=\"br0\">]<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> location \/.well-known\/acme-challenge <\/span><span class=\"br0\">{<\/span><\/li>\n<li class=\" even\"><span class=\"\"> alias \/var\/www\/dehydrated;<\/span><\/li>\n<li class=\" odd\"><span class=\"br0\">}<\/span><\/li>\n<li class=\" even\"><span class=\"br0\">[<\/span><span class=\"\">&#8230;<\/span><span class=\"br0\">]<\/span><\/li>\n<li class=\" odd\"><span class=\"br0\">}<\/span><\/li>\n<\/ol>\n<\/div>\n<h4><span id=\"Apache_example_config\" class=\"ez-toc-section\">Apache example config<\/span><\/h4>\n<p>With Apache just add this to your config and it should work in any VHost:<\/p>\n<div class=\"EnlighterJSWrapper enlighterEnlighterJSWrapper\">\n<ol class=\"hoverEnabled enlighterEnlighterJS EnlighterJS\">\n<li class=\" odd\"><span class=\"\">Alias \/.well-known\/acme-challenge \/var\/www\/dehydrated<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"\">&lt;Directory \/var\/www\/dehydrated&gt;<\/span><\/li>\n<li class=\" even\"><span class=\"\"> Options None<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> AllowOverride None<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"co1\"># Apache 2.x<\/span><\/li>\n<li class=\" even\"><span class=\"\"> &lt;IfModule !mod_authz_core.c&gt;<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> Order allow,deny<\/span><\/li>\n<li class=\" even\"><span class=\"\"> Allow from all<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> &lt;\/IfModule&gt;<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"co1\"># Apache 2.4<\/span><\/li>\n<li class=\" even\"><span class=\"\"> &lt;IfModule mod_authz_core.c&gt;<\/span><\/li>\n<li class=\" odd\"><span class=\"\"> Require all granted<\/span><\/li>\n<li class=\" even\"><span class=\"\"> &lt;\/IfModule&gt;<\/span><\/li>\n<li class=\" odd\"><span class=\"\">&lt;\/Directory&gt;<\/span><\/li>\n<\/ol>\n<\/div>\n<h4><span id=\"_Lighttpd_example_config\" class=\"ez-toc-section\">&nbsp;Lighttpd example config<\/span><\/h4>\n<p>With Lighttpd just add this to your config, and it should work in any VHost:<\/p>\n<div class=\"EnlighterJSWrapper enlighterEnlighterJSWrapper\">\n<ol class=\"hoverEnabled enlighterEnlighterJS EnlighterJS\">\n<li class=\" odd\"><span class=\"\">modules += <\/span><span class=\"st0\">&#8220;alias&#8221;<\/span><\/li>\n<li class=\" even\"><\/li>\n<li class=\" odd\"><span class=\"\">alias.url += <\/span><span class=\"br0\">(<\/span><\/li>\n<li class=\" even\"><span class=\"st0\">&#8220;\/.well-known\/acme-challenge\/&#8221;<\/span><span class=\"\"> =&gt; <\/span><span class=\"st0\">&#8220;\/var\/www\/dehydrated\/&#8221;<\/span><\/li>\n<li class=\" odd\"><span class=\"br0\">)<\/span><\/li>\n<\/ol>\n<\/div>\n<h1 id=\"dns-server\"><span id=\"DNS_Server\" class=\"ez-toc-section\">DNS Server<\/span><\/h1>\n<p>Dehydrated can also configure for you (using the hooks) the DNS records of your domain to use the dns-01 type verification.<\/p>\n<h2><span id=\"Tutorial\" class=\"ez-toc-section\">Tutorial<\/span><\/h2>\n<p>I\u2019ve covered in <a href=\"https:\/\/www.aaflalo.me\/2017\/02\/lets-encrypt-with-dehydrated-dns-01\/\">another blog post the DNS-01 validation<\/a> in great details.<\/p>\n<h2><span id=\"dns-01_challenge\" class=\"ez-toc-section\">dns-01 challenge<\/span><\/h2>\n<p>This script also supports the new <code class=\"\" data-line=\"\">dns-01<\/code>-type verification. This type of verification requires you to be able to create a specific <code class=\"\" data-line=\"\">TXT<\/code> DNS record for each hostname included in the certificate.<\/p>\n<p>You need a hook script that deploys the challenge to your DNS server!<\/p>\n<p>The hook script (indicated in the config file or the \u2013hook\/-k command line argument) gets four arguments: an operation name (clean_challenge, deploy_challenge, or deploy_cert) and some operands for that. For deploy_challenge $2 is the domain name for which the certificate is required, $3 is a \u201cchallenge token\u201d (which is not needed for dns-01), and $4 is a token which needs to be inserted in a TXT record for the domain.<\/p>\n<p>Typically, you will need to split the subdomain name in two, the subdomain name and the domain name separately. For example, for \u201cmy.example.com\u201d, you\u2019ll need \u201cmy\u201d and \u201cexample.com\u201d separately. You then have to prefix \u201c_acme-challenge.\u201d before the subdomain name, as in \u201c_acme-challenge.my\u201d and set a TXT record for that on the domain (e.g. \u201cexample.com\u201d) which has the value supplied in $4<\/p>\n<p><code class=\"\" data-line=\"\">_acme-challenge IN TXT $4<br \/>\n_acme-challenge.my IN TXT $4 <\/code><\/p>\n<p>That could be done manually (as most providers don\u2019t have a DNS API), by having your hook script echo $1, $2 and $4 and then wait (read -s -r -e &lt; \/dev\/tty) \u2013 give it a little time to get into their DNS system. Usually, providers give you a box to put \u201c_acme-challenge.my\u201d and the token value in, and a dropdown to choose the record type, TXT.<\/p>\n<p>Or when you do have a DNS API, pass the details accordingly to achieve the same thing.<\/p>\n<p>You can delete the TXT record when called with operation clean_challenge, when $2 is also the domain name.<\/p>\n<p>Here are some examples: <a href=\"https:\/\/github.com\/lukas2511\/dehydrated\/wiki\/Examples-for-DNS-01-hooks\">Examples for DNS-01 hooks<\/a><\/p>\n<h1><span id=\"First_Run\" class=\"ez-toc-section\">First Run<\/span><\/h1>\n<p>Now that you have configured everything, that you have a set your web server (and restarted\/reloaded it after the configuration changes). You\u2019re set to run the command for the first time; it will create your account, generate your private key and create all the certificate your needs with their keys.<\/p>\n<p><span class=\"enlighterEnlighterJS EnlighterJS\"><span class=\"\">dehydrated -f -c \/etc\/dehydrated\/config<\/span><\/span><\/p>\n<h2><span id=\"Certificates\" class=\"ez-toc-section\">Certificates<\/span><\/h2>\n<p>Now you should find a folder <code class=\"\" data-line=\"\">\/etc\/dehydrated\/certs\/<\/code> with a folder for each of your domain set in your <code class=\"\" data-line=\"\">domains.txt<\/code> file.<\/p>\n<p>In each of those folders, you\u2019ll find two important symbolic links that you need to use in all your application that rely on that certificate-key pair.<\/p>\n<ol>\n<li>fullchain.pem :&nbsp;&nbsp;<code class=\"\" data-line=\"\">\/etc\/dehydrated\/certs\/example.com\/fullchain.pem<\/code><\/li>\n<li>privkey.pem :&nbsp;&nbsp;<code class=\"\" data-line=\"\">\/etc\/dehydrated\/certs\/example.com\/privkey.pem<\/code><\/li>\n<\/ol>\n<p>The first one is your certificate will the different root certificates prepended to it, in other words, the one you need to set for your service. The second one is the private key of the certificate.<\/p>\n<h1><span id=\"Cron\" class=\"ez-toc-section\">Cron<\/span><\/h1>\n<p>Using your favourite cron editor, add a new cron to be run every week. By default dehydrated will renew the certificates 30 days before their expiration, you can change that in the configuration if you want, keep in mind a let\u2019s encrypt cert has an expiration of 3 months. This cron run it every Sunday at 2:05 AM.<\/p>\n<p><span class=\"enlighterEnlighterJS EnlighterJS\"><span class=\"\">5 2 * * 6 \/usr\/local\/sbin\/dehydrated -c -f \/etc\/dehydrated\/config<\/span><\/span><\/p>\n<h1><span id=\"More_info\" class=\"ez-toc-section\">More info<\/span><\/h1>\n<div class=\"reposidget\">\n<header class=\"fontello\">\n<h2><span id=\"lukas2511_dehydrated-2\" class=\"ez-toc-section\"> <a href=\"https:\/\/github.com\/lukas2511\">lukas2511<\/a> \/ <a href=\"https:\/\/github.com\/lukas2511\/dehydrated\"><strong>dehydrated<\/strong><\/a> <\/span><\/h2>\n<\/header>\n<section>\n<p class=\"\">letsencrypt\/acme client implemented as a shell-script \u2013 just add water<\/p>\n<p class=\" homepage\"><a href=\"https:\/\/dehydrated.io\"><strong>https:\/\/dehydrated.io<\/strong><\/a><\/p>\n<\/section>\n<footer><span class=\"fontello star\">4,139<\/span><span class=\"fontello fork\">542<\/span><\/footer>\n<\/div>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">Tutorial on how to use Dehydrated, a bash client for Let&#8217;s Encrypt ACME Protocol. Dehydrated helps you take care of your SSL certificates. Source: Dehydrated: a bash client for Let&#8217;s Encrypt &#8211; Antoine Aflalo<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/monodes.com\/predaelli\/2018\/12\/10\/dehydrated-a-bash-client-for-lets-encrypt-antoine-aflalo\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"Dehydrated: a bash client for Let's Encrypt","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[46],"tags":[],"class_list":["post-5044","post","type-post","status-publish","format-standard","hentry","category-web"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6daft-1jm","jetpack-related-posts":[{"id":1872,"url":"https:\/\/monodes.com\/predaelli\/2016\/11\/02\/cert-for-both-www-and-plain-domain\/","url_meta":{"origin":5044,"position":0},"title":"Cert for both www and plain domain","author":"Paolo Redaelli","date":"2016-11-02","format":false,"excerpt":"Just a note for myself: renew Let's Encrypt certificate to make it valid for both www and plain domain You should be able to do that using the command you originally used to obtain the certificate. Add --force-renewal to force the client to get a new certificate even if the\u2026","rel":"","context":"In &quot;Documentations&quot;","block_context":{"text":"Documentations","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":9904,"url":"https:\/\/monodes.com\/predaelli\/2022\/12\/10\/learn-how-to-use-bash-for-loop-in-shell-scripts\/","url_meta":{"origin":5044,"position":1},"title":"Learn How to Use Bash For Loop in Shell Scripts","author":"Paolo Redaelli","date":"2022-12-10","format":false,"excerpt":"A little promemoria For Loops in Shell Scripts Bash For Loop with Ranges #!\/bin\/bash for n in {1..7}; do echo $n done #!\/bin\/bash for n in {1..7..2}; do echo $n done Bash For Loops with Arrays #!\/bin\/bash fruits=(\"blueberry\" \"peach\" \"mango\" \"pineapple\" \"papaya\") for n in ${fruits[@]}; do echo $n done\u2026","rel":"","context":"In &quot;Documentations&quot;","block_context":{"text":"Documentations","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3474,"url":"https:\/\/monodes.com\/predaelli\/2017\/10\/30\/gnomes-like-wine-and-vinegar\/","url_meta":{"origin":5044,"position":2},"title":"Gnomes like wine and vinegar","author":"Paolo Redaelli","date":"2017-10-30","format":false,"excerpt":"gnome3 - How can I connect to Gnome 3 with a Windows VNC client? Got \"rightly\" answered on Unix & Linux Stack Exchange Here are some other possible solutions: Disable Vino encryption, and then setup an SSH tunnel Use a VNC client compatible with Vino's TLS version: Android: bVNC Free,\u2026","rel":"","context":"In &quot;Documentations&quot;","block_context":{"text":"Documentations","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2017\/10\/gnomes-like-wine-300x300.jpeg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1143,"url":"https:\/\/monodes.com\/predaelli\/2016\/03\/14\/how-to-secure-nginx-with-lets-encrypt-on-ubuntu-14-04-digitalocean\/","url_meta":{"origin":5044,"position":3},"title":"How To Secure Nginx with Let&#8217;s Encrypt on Ubuntu 14.04 | DigitalOcean","author":"Paolo Redaelli","date":"2016-03-14","format":false,"excerpt":"Following https:\/\/letsencrypt.readthedocs.org\/en\/latest\/using.html#installation you can obtain a nice SSL certificate for your own webservers; yet for those who likes NGinx like me this guide How To Secure Nginx with Let's Encrypt on Ubuntu 14.04 | DigitalOcean is also useful In this tutorial, we will show you how to use Let's Encrypt\u2026","rel":"","context":"In &quot;Software Libero&quot;","block_context":{"text":"Software Libero","link":"https:\/\/monodes.com\/predaelli\/category\/software\/software-libero\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":13137,"url":"https:\/\/monodes.com\/predaelli\/2025\/04\/18\/bssg-bash-static-site-generator\/","url_meta":{"origin":5044,"position":4},"title":"BSSG &#8211; Bash Static Site Generator","author":"Paolo Redaelli","date":"2025-04-18","format":false,"excerpt":"BSSG - Bash Static Site Generator A simple, performant static site generator in Bash for personal journals\/blogs with 50+ themes, i18n, SEO, parallel builds & more.","rel":"","context":"In &quot;Software Libero&quot;","block_context":{"text":"Software Libero","link":"https:\/\/monodes.com\/predaelli\/category\/software\/software-libero\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":884,"url":"https:\/\/monodes.com\/predaelli\/2016\/01\/14\/884\/","url_meta":{"origin":5044,"position":5},"title":"Time to install MailPile on\u2026","author":"Paolo Redaelli","date":"2016-01-14","format":"status","excerpt":"Time to install MailPile on my personal cloud server: Mailpile - A free & open modern, fast email client with user-friendly encryption and privacy features","rel":"","context":"In &quot;Mood&quot;","block_context":{"text":"Mood","link":"https:\/\/monodes.com\/predaelli\/category\/mood\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/comments?post=5044"}],"version-history":[{"count":0,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5044\/revisions"}],"wp:attachment":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/media?parent=5044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/categories?post=5044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/tags?post=5044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}