yannstatic/static/2017/08/31/Acme-Certficats-Serveurs.html

2216 lines
208 KiB
HTML
Raw Permalink Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Serveur , installer et renouveler les certificats SSL Let's encrypt via Acme - YannStatic</title>
<meta name="description" content="acme.sh est un dépôt GitHub qui contient un script shell Unix pur implémentant le protocole client ACME, un protocole denregistrement et de vérification des...">
<link rel="canonical" href="https://static.rnmkcy.eu/2017/08/31/Acme-Certficats-Serveurs.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Serveur , installer et renouveler les certificats SSL Let's encrypt via Acme</h1></header></div><meta itemprop="headline" content="Serveur , installer et renouveler les certificats SSL Let's encrypt via Acme"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=serveur">serveur</a>
2024-10-31 20:18:37 +01:00
</li><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=yunohost">yunohost</a>
2024-10-31 20:18:37 +01:00
</li><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=ssl">ssl</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">31&nbsp;août&nbsp;&nbsp;2017</span>
<span title="Modification" style="color:#00FF7F">25&nbsp;déc.&nbsp;&nbsp;2023</span></li></ul></div><meta itemprop="datePublished" content="2023-12-25T00:00:00+01:00">
<meta itemprop="keywords" content="serveur,yunohost,ssl"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><p><em>acme.sh est un <a href="https://github.com/acmesh-official">dépôt GitHub</a> qui contient un script shell Unix pur implémentant le protocole client ACME, un protocole denregistrement et de vérification des noms de domaine.</em></p>
<h2 id="génération-des-certificats">Génération des certificats</h2>
<h3 id="liens">Liens</h3>
<ul>
<li><a href="https://blog.tetsumaki.net/articles/2017/06/generation-des-certificats-lets-encrypt-par-challenge-dns-avec-le-client-acmesh.html">Génération des certificats Lets Encrypt par challenge DNS avec le client acme.sh</a></li>
<li><a href="https://linuxconfig.org/generate-ssl-certificates-with-letsencrypt-debian-linux">Generate SSL Certificates With LetsEncrypt on Debian Linux</a></li>
<li><a href="https://www.howtoforge.com/getting-started-with-acmesh-lets-encrypt-client/">Getting started with acme.sh Lets Encrypt SSL client</a></li>
</ul>
<h3 id="client-acme">Client acme</h3>
<p>Prérequis</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install socat -y
</code></pre></div></div>
<p>Installation client <strong>acme.sh</strong> (<a href="https://github.com/Neilpang/acme.sh">https://github.com/Neilpang/acme.sh</a>)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install
</code></pre></div></div>
<p>Résultat des commandes précédentes</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[mardi 13 août 2019, 21:38:57 (UTC+0200)] Installing to /home/usera//.acme.sh
[mardi 13 août 2019, 21:38:57 (UTC+0200)] Installed to /home/usera//.acme.sh/acme.sh
[mardi 13 août 2019, 21:38:57 (UTC+0200)] Installing alias to '/home/usera//.bashrc'
[mardi 13 août 2019, 21:38:57 (UTC+0200)] OK, Close and reopen your terminal to start using acme.sh
[mardi 13 août 2019, 21:38:57 (UTC+0200)] Installing cron job
18 0 * * * "/home/usera//.acme.sh"/acme.sh --cron --home "/home/usera//.acme.sh" &gt; /dev/null
[mardi 13 août 2019, 21:38:57 (UTC+0200)] Good, bash is found, so change the shebang to use bash as preferred.
[mardi 13 août 2019, 21:38:57 (UTC+0200)] OK
</code></pre></div></div>
<p>Fermer le terminal, puis le réouvrir et vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ acme.sh -h
</code></pre></div></div>
<h3 id="création-de-clé-et-des-certificats-avec-api-ovh">Création de clé et des certificats avec API OVH</h3>
<ul>
<li><a href="https://eu.api.ovh.com/createApp/">OVH : Création de clé API application</a></li>
<li><a href="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api">How to use OVH domain api</a></li>
</ul>
<p>Passer létape 1 si vous avez déjà un jeu de clé</p>
<h4 id="1--create-application-key-and-secret">1 -Create application key and secret</h4>
<p>https://eu.api.ovh.com/createApp/</p>
<p>Application Name : DNS-Api<br />
Application Description : certificats<br />
Application Key : REC23OMyBq2FZrLN<br />
Application Secret : 32eqGDOrrF6b1Smj4kFgQdv1zX2DW7US</p>
<h4 id="2---set-api-key-and-api-secret">2 - Set api key and api secret</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># application key
export OVH_AK="REC23OMyBq2FZrLN"
# application secret
export OVH_AS="32eqGDOrrF6b1Smj4kFgQdv1zX2DW7US"
</code></pre></div></div>
<p>Génération des certificats</p>
<p><code class="language-plaintext highlighter-rouge">acme.sh --dns dns_ovh --server letsencrypt --issue --keylength 4096 -d mondomaine.tld -d *.mondomaine.tld</code> # Clé RSA 4096bits , chiffrement RSA est un algorithme de cryptographie asymétrique<br />
<code class="language-plaintext highlighter-rouge">acme.sh --dns dns_ovh --server letsencrypt --issue --keylength ec-384 -d 'mondomaine.tld' -d '*.mondomaine.tld'</code> # Clé ecc-384 , cryptographie sur les courbes elliptiques (en anglais, elliptic curve cryptography ou ECC)</p>
<p>Notre exemple<br />
<code class="language-plaintext highlighter-rouge">acme.sh --dns dns_ovh --server letsencrypt --issue --keylength ec-384 -d 'ouestline.xyz' -d '*.ouestline.xyz'</code></p>
<p>Si vous utilisez pour la première fois OVH api, vous devez authentifier lapi. (Cela ne se produit quau premier lancement du bash <code class="language-plaintext highlighter-rouge">acme.sh</code>)<br />
Vous verrez quelque chose comme ci-dessous:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[mardi 13 août 2019, 21:43:18 (UTC+0200)] Using OVH endpoint: ovh-eu
[mardi 13 août 2019, 21:43:18 (UTC+0200)] OVH consumer key is empty, Let's get one:
[mardi 13 août 2019, 21:43:18 (UTC+0200)] Please open this link to do authentication: https://eu.api.ovh.com/auth/?credentialToken=v6T3D18cgLt6V3HAvqP9o7qVp9oMJMI2txPl2QcbuILO1JQifebP7U0uaDMu3Ibn
[mardi 13 août 2019, 21:43:18 (UTC+0200)] Here is a guide for you: https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api
[mardi 13 août 2019, 21:43:18 (UTC+0200)] Please retry after the authentication is done.
</code></pre></div></div>
<h4 id="3---authentification-de-la-clé-api">3 - Authentification de la clé api</h4>
<p>(Cela ne se produit quau premier lancement du bash <code class="language-plaintext highlighter-rouge">acme.sh</code>)</p>
<p>Ouvrir le lien : <a href="https://eu.api.ovh.com/auth/?credentialToken=v6T3D18cgLt6V3HAvqP9o7qVp9oMJMI2txPl2QcbuILO1JQifebP7U0uaDMu3Ibn">https://eu.api.ovh.com/auth/?credentialToken=v6T3D18cgLt6V3HAvqP9o7qVp9oMJMI2txPl2QcbuILO1JQifebP7U0uaDMu3Ibn</a></p>
<p>Authentifier vous et sélectionner “Unlimited” pour la validité (saisir le code otp si validé)
Cliquer sur “Authorize Access”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OVH authentication Success !
If you see this page, it means your authentication is ok.
Go back to your shell, and try again.
</code></pre></div></div>
<h4 id="4---relancer-le-bash">4 - Relancer le bash</h4>
<p><code class="language-plaintext highlighter-rouge">acme.sh --dns dns_ovh --server letsencrypt --issue --keylength 4096 -d mondomaine.tld -d smtp.mondomaine.tld -d imap.mondomaine.tld</code></p>
<p>Notre exemple<br />
<code class="language-plaintext highlighter-rouge">acme.sh --dns dns_ovh --server letsencrypt --issue --keylength ec-384 -d 'ouestline.xyz' -d '*.ouestline.xyz'</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[mardi 13 août 2019, 21:45:13 (UTC+0200)] Verifying: ouestline.xyz
[mardi 13 août 2019, 21:45:16 (UTC+0200)] Success
[mardi 13 août 2019, 21:45:16 (UTC+0200)] Verifying: *.ouestline.xyz
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Success
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Removing DNS records.
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Removing txt: pcHjdzrzqBIbuI98aJx6Tan4iejK_NbnCLrAGu-03-0 for domain: _acme-challenge.ouestline.xyz
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Using OVH endpoint: ovh-eu
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Checking authentication
[mardi 13 août 2019, 21:45:19 (UTC+0200)] Consumer key is ok.
[mardi 13 août 2019, 21:45:20 (UTC+0200)] Removed: Success
[mardi 13 août 2019, 21:45:20 (UTC+0200)] Removing txt: 9m38ahU-HMS1nDrdq8O5AkJUQRYEQchQQxNW4Sdv2M8 for domain: _acme-challenge.ouestline.xyz
[mardi 13 août 2019, 21:45:20 (UTC+0200)] Using OVH endpoint: ovh-eu
[mardi 13 août 2019, 21:45:20 (UTC+0200)] Checking authentication
[mardi 13 août 2019, 21:45:20 (UTC+0200)] Consumer key is ok.
[mardi 13 août 2019, 21:45:22 (UTC+0200)] Removed: Success
[mardi 13 août 2019, 21:45:22 (UTC+0200)] Verify finished, start to sign.
[mardi 13 août 2019, 21:45:22 (UTC+0200)] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/63384623/889352683
[mardi 13 août 2019, 21:45:24 (UTC+0200)] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/0325da09619fcdb4d883a1970157e2101960
[mardi 13 août 2019, 21:45:24 (UTC+0200)] Cert success.
[...]
[mardi 13 août 2019, 21:45:24 (UTC+0200)] Your cert is in /home/usera//.acme.sh/ouestline.xyz_ecc/ouestline.xyz.cer
[mardi 13 août 2019, 21:45:24 (UTC+0200)] Your cert key is in /home/usera//.acme.sh/ouestline.xyz_ecc/ouestline.xyz.key
[mardi 13 août 2019, 21:45:24 (UTC+0200)] The intermediate CA cert is in /home/usera//.acme.sh/ouestline.xyz_ecc/ca.cer
[mardi 13 août 2019, 21:45:24 (UTC+0200)] And the full chain certs is there: /home/usera//.acme.sh/ouestline.xyz_ecc/fullchain.cer
</code></pre></div></div>
<h3 id="installation-des-certificats">Installation des certificats</h3>
<p>Linstallation de certificats avec <strong>acme.sh</strong> créera une tâche cron qui renouvellera automatiquement les certificats et copiera les fichiers pertinents aux emplacements que vous fournissez dans la commande dinstallation. De plus, vous pouvez également spécifier la commande pour recharger la configuration du serveur.</p>
<p>Supposons que nous stockons les fichiers dans le répertoire <code class="language-plaintext highlighter-rouge">/etc/ssl/private/</code> (qui doit être créé au préalable), la commande serait :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /etc/ssl/private/
sudo chown $USER -R /etc/ssl/private/
acme.sh --ecc --install-cert -d ouestline.xyz --key-file /etc/ssl/private/ouestline.xyz-key.pem --fullchain-file /etc/ssl/private/ouestline.xyz-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'
</code></pre></div></div>
<h3 id="renouvellement-automatique">Renouvellement automatique</h3>
<p>$ <code class="language-plaintext highlighter-rouge">crontab -e</code> # edite tous les jobs de lutilisateur en cours</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>18 0 * * * "$HOME/.acme.sh"/acme.sh --cron --home "$HOME/.acme.sh" --renew-hook "$HOME/.acme.sh/acme.sh --ecc --install-cert -d ouestline.xyz --key-file /etc/ssl/private/ouestline.xyz-key.pem --fullchain-file /etc/ssl/private/ouestline.xyz-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'" &gt; /dev/null
</code></pre></div></div>
<h4 id="notification-par-email--si-un-certificat-est-ignoré-renouvelé-ou-erroné">Notification par email si un certificat est ignoré, renouvelé ou erroné</h4>
<p><strong>Niveau de notification des courriels de Lets Encrypt</strong></p>
<p>Il existe au total quatre niveaux de notification, comme suit :</p>
<ul>
<li>0 - Désactiver complètement la notification.</li>
<li>1 - Envoyer une notification uniquement en cas derreur.</li>
<li>2 - Envoyer une notification lorsquun certificat est renouvelé avec succès, ou lorsquil y a une erreur.</li>
<li>3 - Envoi dune notification lorsquun certificat est ignoré, renouvelé ou quil y a une erreur. Vous recevrez une notification par courriel chaque nuit avec ce niveau.</li>
</ul>
<p>La commande est la suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --set-notify --notify-level {niveau}
acme.sh --set-notify --notify-level 2
## ou ne recevoir un email qu'en cas d'erreur ###
acme.sh --set-notify --notify-level 1
</code></pre></div></div>
<p><strong>Définition du mode de notification par courrier électronique</strong></p>
<p>Là encore, il existe au total deux modes de notification, comme suit :</p>
<ul>
<li>0 - Envoi dun courrier électronique en mode groupé. En dautres termes, envoyer toutes les notifications du domaine en un seul message ou courriel. Cest ce dont vous avez besoin si vous avez plus dun certificat TLS/SSL Lets Encrypt.</li>
<li>1 - Mode Cert. Envoyer un message pour chaque certificat TLS/SSL Lets Encrypt. Il se peut que vous receviez un grand nombre de-mails en une seule nuit.</li>
</ul>
<p>La commande est la suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --set-notify --notify-mode 0
</code></pre></div></div>
<p><strong>Configurer la notification par email de Lets Encrypt lorsquun certificat est ignoré, renouvelé, ou quil y a une erreur avec un hook</strong></p>
<p><a href="https://static.lxcyan.local/2022/08/27/Debian_Postfix_serveur_SMTP_envoi_uniquement.html">Debian - Installer et configurer Postfix comme serveur SMTP denvoi uniquement</a></p>
<p>Il existe plusieurs façons dobtenir une notification. Par exemple, vous pouvez utiliser votre serveur SMTP, Slack Webhooks/Slack App, ou pousser les notifications vers votre appareil iOS ou Android à laide de pushover. Cependant, dans ce tutoriel, jutiliserai la méthode SMTP pour obtenir une notification par email.
Comment configurer la notification pour SMTP</p>
<p>Jai configuré Postfix sur mon serveur web pour envoyer des notifications par courriel. Mais, bien sûr, vous pouvez utiliser nimporte quel autre serveur de messagerie pour envoyer des notifications directement en vous connectant à un serveur de messagerie SMTP. La syntaxe de la commande export est la suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Juste l'adresse électronique (pas de noms d'affichage)
export SMTP_FROM="from@your-domain-com"
# Juste l'adresse e-mail, utilisez des virgules entre plusieurs e-mails
export SMTP_TO="to@your-domain-com,admin@your-domain-com"
# IP ou nom de domaine du serveur smtp distant
export SMTP_HOST="smtp.your-domain-com"
# Une des options suivantes : "none", "ssl" (TLS implicite, TLS Wrapper), "tls" (TLS explicite, STARTTLS) :
export SMTP_SECURE="tls"
</code></pre></div></div>
<p>Le port par défaut dépend de la valeur de SMTP_SECURE. Par exemple, none est 25, ssl est 465 et tls est 587. Mais si votre serveur SMTP utilise un port différent, définissez-le comme suit (disons le port 251) :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export SMTP_PORT="251"
</code></pre></div></div>
<p>Votre serveur SMTP nécessite-t-il un login AUTH avec un utilisateur et un mot de passe ? Définissez-le comme suit :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Si votre serveur SMTP nécessite AUTH (login)
export SMTP_USERNAME='votre-nom-d'utilisateur-ici'
export SMTP_PASSWORD='votre-mot-de-passe-ici'
</code></pre></div></div>
<p>Enfin, il est préférable de définir le chemin daccès à python3/python2 ou curl. Utilisez la commande type ou la commande command pour le localiser. Par exemple :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type python3
python3 est /usr/bin/python3
</code></pre></div></div>
<p>Définissez-le comme suit :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># chemin accès python3/python2 ou curl
export SMTP_BIN="/usr/bin/python3"
</code></pre></div></div>
<p>Le délai dattente par défaut est de 30 secondes pour le serveur SMTP. Mais si votre serveur SMTP est très lent à répondre, vous pouvez avoir besoin de définir :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># serveur SMTP est très lent
export SMTP_TIMEOUT="90"
</code></pre></div></div>
<p>Exemple pour un serveur postfix smtp local</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export SMTP_FROM="icevps@icebull.xyz"
export SMTP_TO="vpn@cinay.eu"
export SMTP_HOST="127.0.0.1"
export SMTP_SECURE="none"
export SMTP_BIN="/usr/bin/python3"
</code></pre></div></div>
<p>Exemple pour un serveur smtp distant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export SMTP_FROM="ian@xoyaz.xyz"
export SMTP_TO="vpn@cinay.eu"
export SMTP_HOST="xoyaz.xyz"
export SMTP_PORT="587"
export SMTP_SECURE="tls"
export SMTP_USERNAME="ian@xoyaz.xyz"
export SMTP_PASSWORD="xxxxxxxxxxxxxxx"
export SMTP_BIN="/usr/bin/python3"
</code></pre></div></div>
<p><code class="language-plaintext warning highlighter-rouge">ATTENTION 'SMTP_FROM' doit être identique à 'SMTP_USERNAME'</code></p>
<p>Enfin, exécutez la commande suivante pour activer la notification smtp pour votre Lets Encrypt lorsquun certificat est ignoré, renouvelé ou erroné. Par exemple :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --set-notify --notify-hook smtp
</code></pre></div></div>
<p>Vous obtiendrez des informations derreur ou de succès à lécran comme suit :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Mon 03 Apr 2023 11:35:55 AM GMT] Set notify hook to: smtp
[Mon 03 Apr 2023 11:35:55 AM GMT] Sending via: smtp
[Mon 03 Apr 2023 11:35:56 AM GMT] smtp Success
</code></pre></div></div>
<p>Et voici lemail de test :</p>
<p><img src="/images/acme-smtp.png" alt="" /></p>
<p class="info">Pour le dépannage supplémentaire, exécutez à nouveau la commande avec debug ou debug 2. (Au niveau de débogage 2 ou plus, la sortie affichera la transcription complète de la session SMTP, qui peut inclure le mot de passe SMTP.)<br />
Tous les paramètres <code class="language-plaintext highlighter-rouge">SMTP_*</code> seront enregistrés dans <code class="language-plaintext highlighter-rouge">~/.acme.sh/account.conf</code> et seront réutilisés au besoin.</p>
<p>Vérification</p>
<p>Maintenant que le hook SMTP est configuré, vous recevrez une notification par email en cas de succès ou déchec ou si le certificat est ignoré en masse. Voici ce que cela donne lorsque je renouvelle mon certificat TLS avec un job cron :</p>
<p><img src="/images/acme-smtp01.png" alt="" /></p>
<h4 id="cron-probleme-renouvellement">CRON PROBLEME RENOUVELLEMENT</h4>
<p>Dans lexemple de cron suivant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>18 0 * * * "$HOME/.acme.sh"/acme.sh --cron --home "$HOME/.acme.sh" --renew-hook "$HOME/.acme.sh/acme.sh --ecc --install-cert -d 'domaine.tld' --key-file /etc/ssl/private/domaine.tld-key.pem --fullchain-file /etc/ssl/private/domaine.tld-fullchain.pem --set-notify --notify-hook smtp --reloadcmd 'sudo systemctl reload nginx'" &amp;&gt;/dev/null
</code></pre></div></div>
<p><code class="language-plaintext error highlighter-rouge">Lors du renouvellement "--reloadcmd 'sudo systemctl reload nginx'" n'est pas exécuté</code></p>
<p>Il faut créer un script qui exécute toutes les commandes , y compris celles du <code class="language-plaintext highlighter-rouge">--reloadcmd</code>, et le mettre dans une tâche cron</p>
<p>Le script <code class="language-plaintext highlighter-rouge">certificat_expire.sh</code> est lancé par une tâche cron tous les jours.Le renouvellement se fera 7 jours avant la date déchéance du certificat</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/sh</span>
<span class="c"># Domaine</span>
<span class="nv">_domain</span><span class="o">=</span><span class="s2">"rnmkcy.eu"</span>
<span class="c"># Test expiration certificats</span>
<span class="nv">PEM</span><span class="o">=</span><span class="s2">"/etc/ssl/private/</span><span class="nv">$_domain</span><span class="s2">-fullchain.pem"</span>
<span class="c"># 7 jours en secondes </span>
<span class="nv">DAYS</span><span class="o">=</span><span class="s2">"604800"</span>
<span class="c"># OpenSSL</span>
<span class="nv">_openssl</span><span class="o">=</span><span class="s2">"/usr/bin/openssl"</span>
<span class="c"># Date expiration dans 7 jours ?</span>
<span class="nv">$_openssl</span> x509 <span class="nt">-enddate</span> <span class="nt">-noout</span> <span class="nt">-in</span> <span class="s2">"</span><span class="nv">$PEM</span><span class="s2">"</span> <span class="nt">-checkend</span> <span class="s2">"</span><span class="nv">$DAYS</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="nt">-q</span> <span class="s1">'Certificate will expire'</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="nt">-eq</span> 0 <span class="nt">-o</span> <span class="o">!</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then</span>
<span class="c"># certificat expire dans 7 jours , on renouvelle</span>
<span class="nb">echo</span> <span class="s2">"Force renouvellement des certificats Lets Encrypt"</span>
<span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.acme.sh"</span>/acme.sh <span class="nt">--force</span> <span class="nt">--cron</span> <span class="nt">--home</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.acme.sh"</span> <span class="nt">--renew-hook</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.acme.sh/acme.sh --ecc --install-cert -d </span><span class="nv">$_domain</span><span class="s2"> --key-file /etc/ssl/private/</span><span class="nv">$_domain</span><span class="s2">-key.pem --fullchain-file /etc/ssl/private/</span><span class="nv">$_domain</span><span class="s2">-fullchain.pem"</span>
<span class="c"># Les autres commandes à exécuter</span>
<span class="nb">echo</span> <span class="s2">"Recharge service nginx"</span>
<span class="nb">sudo </span>systemctl reload nginx
<span class="k">else
</span><span class="nb">echo</span> <span class="s2">"Certificat Valide"</span>
<span class="nv">$_openssl</span> x509 <span class="nt">-enddate</span> <span class="nt">-noout</span> <span class="nt">-in</span> <span class="s2">"</span><span class="nv">$PEM</span><span class="s2">"</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Modifier la tâche cron</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>18 0 * * * "$HOME/certificat_expire.sh" &amp;&gt;/dev/null
</code></pre></div></div>
<h3 id="acmesh---aide">acme.sh - Aide</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Usage: acme.sh command ...[parameters]....
Commands:
--help, -h Show this help message.
--version, -v Show version info.
--install Install acme.sh to your system.
--uninstall Uninstall acme.sh, and uninstall the cron job.
--upgrade Upgrade acme.sh to the latest code from https://github.com/Neilpang/acme.sh.
--issue Issue a cert.
--signcsr Issue a cert from an existing csr.
--deploy Deploy the cert to your server.
--install-cert Install the issued cert to apache/nginx or any other server.
--renew, -r Renew a cert.
--renew-all Renew all the certs.
--revoke Revoke a cert.
--remove Remove the cert from list of certs known to acme.sh.
--list List all the certs.
--showcsr Show the content of a csr.
--install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
--uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
--cron Run cron job to renew all the certs.
--toPkcs Export the certificate and key to a pfx file.
--toPkcs8 Convert to pkcs8 format.
--update-account Update account info.
--register-account Register account key.
--deactivate-account Deactivate the account.
--create-account-key Create an account private key, professional use.
--create-domain-key Create an domain private key, professional use.
--createCSR, -ccsr Create CSR , professional use.
--deactivate Deactivate the domain authz, professional use.
--set-notify Set the cron notification hook, level or mode.
Parameters:
--domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
--challenge-alias domain.tld The challenge domain alias for DNS alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode
--domain-alias domain.tld The domain alias for DNS alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode
--force, -f Used to force to install or force to renew a cert immediately.
--staging, --test Use staging server, just for test.
--debug Output debug info.
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode, see: https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode
--apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
--dnssleep [120] The time in seconds to wait for all the txt records to take effect in dns api mode. Default 120 seconds.
--keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
--accountkeylength, -ak [2048] Specifies the account key length.
--log [/path/to/logfile] Specifies the log file. The default is: "/root/.acme.sh/acme.sh.log" if you don't give a file path here.
--log-level 1|2 Specifies the log level, default is 1.
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
--cert-file After issue/renew, the cert will be copied to this path.
--key-file After issue/renew, the key will be copied to this path.
--ca-file After issue/renew, the intermediate cert will be copied to this path.
--fullchain-file After issue/renew, the fullchain cert will be copied to this path.
--reloadcmd "service nginx reload" After issue/renew, it's used to reload the server.
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
--accountconf Specifies a customized account config file.
--home Specifies the home dir for acme.sh.
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
--config-home Specifies the home dir to save all the configurations.
--useragent Specifies the user agent string. it will be saved for future use too.
--accountemail Specifies the account email, only valid for the '--install' and '--update-account' command.
--accountkey Specifies the account key path, only valid for the '--install' command.
--days Specifies the days to renew the cert when using '--issue' command. The default value is 60 days.
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
--listraw Only used for '--list' command, list the certs in raw format.
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
--insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
--ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate.
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically.
--noprofile Only valid for '--install' command, which means: do not install aliases to user profile.
--no-color Do not output color text.
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates.
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed.
--renew-hook Command to be run once for each successfully renewed certificate.
--deploy-hook The hook file to deploy cert
--ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
--always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default.
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
--listen-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6.
--openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
--yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode
--branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to.
--notify-level 0|1|2|3 Set the notification level: Default value is 2.
0: disabled, no notification will be sent.
1: send notifications only when there is an error.
2: send notifications when a cert is successfully renewed, or there is an error.
3: send notifications when a cert is skipped, renewed, or error.
--notify-mode 0|1 Set notification mode. Default value is 0.
0: Bulk mode. Send all the domain's notifications in one message(mail).
1: Cert mode. Send a message for every single cert.
--notify-hook [hookname] Set the notify hook
</code></pre></div></div>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2017-08-31T00:00:00+02:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2017/08/14/motd-message-bienvenue-connexion-ligne-commande.html">motd , message de bienvenue sur connexion en ligne de commande</a></div><div class="next"><span>SUIVANT</span><a href="/2017/09/22/phpmail-envoi-message-UTF8.html">phpmail, utilisation de caractères UTF-8 dans les champs sujet et corps d'un message</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>