yannstatic/static/2022/08/20/VPS_debian_11_contabo.html

2406 lines
212 KiB
HTML
Raw 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>Yunohost Contabo debian 11 ouestyan.fr - YannStatic</title>
<meta name="description" content="https://contabo.com/en/">
<link rel="canonical" href="https://static.rnmkcy.eu/2022/08/20/VPS_debian_11_contabo.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;">Yunohost Contabo debian 11 ouestyan.fr</h1></header></div><meta itemprop="headline" content="Yunohost Contabo debian 11 ouestyan.fr"><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=vps">vps</a>
</li><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=yunohost">yunohost</a>
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">20&nbsp;août&nbsp;&nbsp;2022</span>
<span title="Modification" style="color:#00FF7F">17&nbsp;déc.&nbsp;&nbsp;2022</span></li></ul></div><meta itemprop="datePublished" content="2022-12-17T00:00:00+01:00">
<meta itemprop="keywords" content="vps,yunohost"><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><img src="/images/contabo-logo.png" alt="Contabo" /><br />
<a href="https://contabo.com/en/">https://contabo.com/en/</a></p>
<p>Fournisseur : <strong>Contabo</strong><br />
Accès client : <a href="https://my.contabo.com/">https://my.contabo.com/</a><br />
Nom du plan : <strong>VPS S SSD</strong><br />
Location Nuremberg (EU)<br />
RAM garantie : <strong>8192 Mb</strong><br />
Bande passante mensuelle illimitée<br />
<strong>Espace disque SSD 200 Go</strong><br />
Système dexploitation : <strong>Debian 11</strong><br />
Technologie de virtualisation <strong>KVM</strong><br />
Emplacement du serveur Allemagne <img src="/images/de.png" alt="" /><br />
Frais dinstallation 0.00 EUR<br />
Coût mensuel 5,74 USD, 4,99 EUR soit 5.99€/Mois TTC<br />
Méthodes de paiement PayPal</p>
<p>IP address <strong>62.171.147.4</strong><br />
Accès client : <a href="https://my.contabo.com/">https://my.contabo.com/</a></p>
<p>Sous-réseau IPv6 <br />
<em>Chaque serveur dédié et chaque VPS est livré avec un sous-réseau IPv6 /64 en plus de son adresse IPv4. Vous pouvez utiliser les adresses de ce sous-réseau librement sur le serveur/VPS associé. IPv6 est déjà préconfiguré sur nos serveurs mais doit être activé explicitement dans certains cas. Vous trouverez comment activer IPv6 et dautres informations sur le sujet dans notre tutoriel.</em></p>
<table>
<thead>
<tr>
<th style="text-align: left">type dabonnement</th>
<th style="text-align: left">adresse IPv4</th>
<th style="text-align: left">sous-réseau IPv6</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">VPS S SSD (no setup)</td>
<td style="text-align: left">62.171.147.4</td>
<td style="text-align: left">2a02:c207:2098:7283:0000:0000:0000:0001 / 64</td>
</tr>
</tbody>
</table>
<p>On se connecte en root sur le VPS</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh root@62.171.147.4
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Linux vmi987283.contaboserver.net 5.10.0-12-amd64 #1 SMP Debian 5.10.103-1 (2022-03-07) x86_64
_____
/ ___/___ _ _ _____ _ ___ ___
| | / _ \| \| |_ _/ \ | _ )/ _ \
| |__| (_) | .` | | |/ _ \| _ \ (_) |
\____\___/|_|\_| |_/_/ \_|___/\___/
Welcome!
This server is hosted by Contabo. If you have any questions or need help,
please don't hesitate to contact us at support@contabo.com.
root@vmi987283:~#
</code></pre></div></div>
<p><strong>Quelques outils</strong>, exécuter <code class="language-plaintext highlighter-rouge">apt install tree tmux</code><br />
<strong>Activation ipv6</strong>, exécuter <code class="language-plaintext highlighter-rouge">enable_ipv6</code> puis redémarrer <code class="language-plaintext highlighter-rouge">reboot</code> et se reconnecter ssh</p>
<p>Vérifier ladressage : <code class="language-plaintext highlighter-rouge">ip a</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:47:96:e2 brd ff:ff:ff:ff:ff:ff
altname enp0s18
altname ens18
inet 62.171.147.4/19 brd 62.171.159.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 2a02:c207:2098:7283::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe47:96e2/64 scope link
valid_lft forever preferred_lft forever
</code></pre></div></div>
<p>Se connecter sur contabo <a href="https://my.contabo.com/">https://my.contabo.com/</a></p>
<p>Activer le reverse DNS IPV4 et IPV6 avec ouestyan.fr : Control panel → <strong>Reverse DNS management</strong><br />
<img src="/images/yunocontabo005.png" alt="" /></p>
<p>VNC : Control panel → <strong>VPS control</strong><br />
<img src="/images/yunocontabo006.png" alt="" /><br />
Changement mot de passe VNC, cliquer sur <strong>Manage</strong><strong>VNC Password</strong><br />
Désactiver VNC, cliquer sur <strong>Manage</strong><strong>Disable VNC</strong> et valider par un clic sur <strong>Disable</strong><br />
<code class="language-plaintext warning highlighter-rouge">SUR CE VPS, VNC EST DESACTIVE</code></p>
<p>Modifier le DNS du domaine ouestyan.fr chez le fournisseur OVH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 3600
@ IN SOA dns17.ovh.net. tech.ovh.net. (2022082202 86400 3600 3600000 60)
IN NS ns17.ovh.net.
IN NS dns17.ovh.net.
IN MX 10 ouestyan.fr.
IN A 62.171.147.4
IN AAAA 2a02:c207:2098:7283::1
* IN A 62.171.147.4
* IN AAAA 2a02:c207:2098:7283::1
</code></pre></div></div>
<h2 id="yunohost-ouestyanfr">Yunohost ouestyan.fr</h2>
<p><img src="/images/yunohost.png" alt=" " /></p>
<h3 id="installer-yunohost">Installer yunohost</h3>
<p>Installation dun nouveau YunoHost sur un Debian 11/Bullseye</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl https://install.yunohost.org | bash
</code></pre></div></div>
<p>Patienter …</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
┌───────────────────────────┤ SSH Configuration ├────────────────────────────┐
│ │
│ To improve the security of your server, it is recommended to let YunoHost │
│ manage the SSH configuration. │
│ Your current SSH configuration differs from the recommended configuration. │
│ If you let YunoHost reconfigure it, the way you connect to your server │
│ through SSH will change in the following way: │
│ - you will not be able to connect as root through SSH. Instead you should │
│ use the admin user ; │
│ │
│ Do you agree to let YunoHost apply those changes to your configuration and │
│ therefore affect the way you connect through SSH ? │
│ │
&lt;Yes&gt; &lt;No&gt;
│ │
└────────────────────────────────────────────────────────────────────────────┘
Choix Yes
[ OK ] YunoHost installation completed !
===============================================================================
You should now proceed with Yunohost post-installation. This is where you will
be asked for :
- the main domain of your server ;
- the administration password.
You can perform this step :
- from the command line, by running 'yunohost tools postinstall' as root
- or from your web browser, by accessing :
- https://62.171.147.4/ (global IP, if you're on a VPS)
If this is your first time with YunoHost, it is strongly recommended to take
time to read the administator documentation and in particular the sections
'Finalizing your setup' and 'Getting to know YunoHost'. It is available at
the following URL : https://yunohost.org/admindoc
===============================================================================
</code></pre></div></div>
<h3 id="post-installation">Post-installation</h3>
<p class="info">Vous devez faire la post-installation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost tools postinstall
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Main domain: ouestyan.fr
New administration password: ****************
Confirm new administration password: ****************
Info: Installing YunoHost...
[...]
Success! YunoHost is now configured
Warning: The post-install completed! To finalize your setup, please consider:
- adding a first user through the 'Users' section of the webadmin (or 'yunohost user create &lt;username&gt;' in command-line);
- diagnose potential issues through the 'Diagnosis' section of the webadmin (or 'yunohost diagnosis run' in command-line);
- reading the 'Finalizing your setup' and 'Getting to know YunoHost' parts in the admin documentation: https://yunohost.org/admindoc.
</code></pre></div></div>
<blockquote>
<p>Le mot de passe root remplacé par celui de ladmin yunohost</p>
</blockquote>
<p>Motd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm /etc/motd &amp;&amp; nano /etc/motd
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> __ __ _ _
<span class="se">\ \ </span>/ /_ _ _ _ ___ | |_ ___ ___| |_
<span class="se">\ </span>V /| <span class="o">||</span> <span class="o">||</span> <span class="s1">' \ / _ \| '</span> <span class="se">\ </span>/ _ <span class="se">\(</span>_-&lt;| _|
|_| <span class="se">\_</span>,_||_||_|<span class="se">\_</span>__/|_||_|<span class="se">\_</span>__//__/ <span class="se">\_</span>_|
__ ___ _ ____ _ _ _ _ ____ _ _
/ / |_ <span class="o">)</span> / <span class="o">||</span>__ |/ | / <span class="o">||</span> | <span class="o">||</span>__ <span class="o">||</span> | |
/ _ <span class="se">\ </span>/ / _ | | / / | | _ | <span class="o">||</span>_ _| / /_|_ _|
<span class="se">\_</span>__//___|<span class="o">(</span>_<span class="o">)</span>|_| /_/_ |_|<span class="o">(</span>_<span class="o">)</span>|_| |_| /_/<span class="o">(</span>_<span class="o">)</span> |_|__
___ _ _ ___ ___| |_ _ _ __ _ _ _ / _| _ _
/ _ <span class="se">\|</span> <span class="o">||</span> |/ <span class="nt">-_</span><span class="o">)(</span>_-&lt;| _|| <span class="o">||</span> |/ _<span class="sb">`</span> <span class="o">||</span> <span class="s1">' \ _ | _|| '</span>_|
<span class="se">\_</span>__/ <span class="se">\_</span>,_|<span class="se">\_</span>__|/__/ <span class="se">\_</span>_| <span class="se">\_</span>, |<span class="se">\_</span>_,_||_||_|<span class="o">(</span>_<span class="o">)</span>|_| |_|
|__/
</code></pre></div></div>
<h3 id="créer-utilisateur-yack">Créer utilisateur yack</h3>
<p>Création utilisateur yack</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost user create yack
</code></pre></div></div>
<p><img src="/images/yunocontabo001.png" alt="" /></p>
<p>Ajouter le droit de connexion ssh à un utilisateur (FACULTATIF)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost user permission add ssh yack
</code></pre></div></div>
<p><img src="/images/yunocontabo002.png" alt="" /></p>
<h3 id="domaines-et-dns-ovh">Domaines et DNS OVH</h3>
<p><img src="/images/dns-logo.png" alt="" width="50" /></p>
<p>Configuration DNS domaine par défaut <strong>ouestyan.fr</strong> , exécuter la commande <code class="language-plaintext highlighter-rouge">yunohost domain dns-conf ouestyan.fr</code> pour afficher la configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Basic ipv4/ipv6 records
@ 3600 IN A 62.171.147.4
@ 3600 IN AAAA 2a02:c207:2098:7283::1
; Mail
@ 3600 IN MX 10 ouestyan.fr.
@ 3600 IN TXT "v=spf1 a mx -all"
mail._domainkey 3600 IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3/lxkCrD5jmxFJTeXvqT1BlOHTPnuynI/5k+GlpOwt3bMDK6EHx1/ZS4Bx5lB9P1f/SjkyAm83ZTh0piu5Q3Wmb+ZzDGGsSeiOYVUUT0q4p3iMDnGyx6G27N7pWpUQjX3E6xoDZLJftoKO/6td0TcJjhBLkkujs9yeAtixxzNmQIDAQAB"
_dmarc 3600 IN TXT "v=DMARC1; p=none"
; XMPP
_xmpp-client._tcp 3600 IN SRV 0 5 5222 ouestyan.fr.
_xmpp-server._tcp 3600 IN SRV 0 5 5269 ouestyan.fr.
muc 3600 IN CNAME @
pubsub 3600 IN CNAME @
vjud 3600 IN CNAME @
xmpp-upload 3600 IN CNAME @
; Extra
* 3600 IN A 62.171.147.4
* 3600 IN AAAA 2a02:c207:2098:7283::1
@ 3600 IN CAA 128 issue "letsencrypt.org"
</code></pre></div></div>
<p><img src="/images/ovh-logo-a.png" alt="" /><br />
Se connecter à lespace client du site OVH : <strong>Web cloud → Domaines → ouestyan.fr → Zone DNS</strong><br />
Cliquer sur <strong>“Modifier en mode textuel”</strong>, garder les 4 premières lignes :<br />
<img src="/images/dns-ovh-zone.png" alt="" width="600" /><br />
puis effacer tout ce quil y a en-dessous, et le remplacer par la configuration donnée par votre serveur ( <code class="language-plaintext highlighter-rouge">yunohost domain dns-conf</code>)<br />
<code class="language-plaintext warning highlighter-rouge">EN CAS DE PROBLEME, les enregistrements DNS doivent être ajoutés avec l'outil OVH</code></p>
<h3 id="activer-certificats-ssl-lets-encrypt">Activer Certificats SSL Lets Encrypt</h3>
<p><img src="/images/LetsEncrypt-a.png" alt="" /><br />
On active les certificats SSL pour le domaine ouestyan.fr</p>
<p>Se connecter avec le lien <a href="http://62.171.147.4/yunohost/admin/#/login?redirect=%2F">http://62.171.147.4/yunohost/admin/#/login?redirect=%2F</a><br />
<strong>Domaines</strong><strong>ouestyan.fr</strong> et cliquer sur la création de certificat** Lets Encrypt**<br />
<img src="/images/yunocontabo015.png" alt="" /></p>
<p>Ouvrir le lien <a href="https://ouestyan.fr">https://ouestyan.fr</a></p>
<h3 id="openssh-clé-et-script">OpenSSH, clé et script</h3>
<p><img src="/images/openssh-logo.png" alt="OpenSSH" height="70" /><br />
<u>sur l'ordinateur de bureau</u>
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) nommé <strong>contabovps</strong> pour une liaison SSH avec le serveur KVM.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/contabovps
</code></pre></div></div>
<p>Envoyer les clés publiques sur le serveur KVM aux utilisateurs admin et yack</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id -i ~/.ssh/contabovps.pub admin@ouestyan.fr
ssh-copy-id -i ~/.ssh/contabovps.pub yack@ouestyan.fr
</code></pre></div></div>
<p><u>sur le serveur Yunohost</u>
On se connecte</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh admin@ouestyan.fr
</code></pre></div></div>
<p>Sur votre serveur, la modification du fichier de configuration SSH pour désactiver lauthentification par mot de passe est gérée par un paramètre système</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yunohost settings set security.ssh.password_authentication -v no
</code></pre></div></div>
<p>Modifier le port SSH</p>
<p><em>Pour empêcher les tentatives de connexion SSH par des robots qui analysent Internet à la recherche de tout serveur sur lequel SSH est activé, vous pouvez modifier le port SSH. Ceci est géré par un paramètre système, qui prend en charge la mise à jour de la configuration SSH et Fail2Ban.</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yunohost settings set security.ssh.port -v 55147
</code></pre></div></div>
<p>Accès depuis le poste distant avec la clé privée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -p 55147 -i ~/.ssh/contabovps admin@ouestyan.fr
ssh -p 55147 -i ~/.ssh/contabovps yack@ouestyan.fr
</code></pre></div></div>
<h3 id="diagnostic">Diagnostic</h3>
<p>Après avoir attendu la validation des DNS (quelques minutes à 24h)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost diagnosis run
</code></pre></div></div>
<p><img src="/images/yunocontabo003.png" alt="" /></p>
<h3 id="mises-à-jour-automatique">Mises à jour automatique</h3>
<p><em>Unattended_upgrades est un outil qui permet de télécharger et installer les mises à jour de sécurité automatiquement et sans surveillance, en prenant soin de ninstaller que les paquets provenant de la source APT configurée, et en vérifiant les invites dpkg concernant les modifications du fichier de configuration. Apticron est un simple script qui envoie des courriels sur les mises à jour de paquets en attente comme les mises à jour de sécurité, en gérant correctement les paquets en attente.</em></p>
<p>Installation</p>
<p><img src="/images/majauto01.png" alt="" /></p>
<p><img src="/images/majauto02.png" alt="" /></p>
<h2 id="maintenance">Maintenance</h2>
<h3 id="problème-certificat-sur-serveur-smtp">Problème certificat sur serveur SMTP</h3>
<p><em>je ne peux pas envoyer de message via Thunderbird (problème de certificat)</em></p>
<p>Le paramétrage IMAP port 993 et SMTP port 587 est effectué sans message derreur sur Linux Thunderbird version 102.
Lors de lenvoi dun message jai un message derreur thunderbird</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>the certificate is not secure because it is impossible to verify
that it was issued by a trusted authority...
</code></pre></div></div>
<p><strong>Jai localisé le problème</strong> en me connectant en SSH sur le VPS , en exécutant une commande pour vérifier la validité du certificat sur le serveur SMTP:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client <span class="nt">-starttls</span> smtp <span class="nt">-showcerts</span> <span class="nt">-connect</span> ouestyan.fr:587 <span class="nt">-servername</span> ouestyan.fr
</code></pre></div></div>
<p>Le serveur SMTP na pas le certificat <strong>Lets encrypt</strong> mais le certificat <strong>auto signé</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONNECTED(00000003)
depth=1 CN = yunohost.org, O = yunohost
verify error:num=19:self signed certificate in certificate chain
verify return:1
depth=1 CN = yunohost.org, O = yunohost
verify return:1
depth=0 CN = ouestyan.fr
verify return:1
---
Certificate chain
0 s:CN = ouestyan.fr
i:CN = yunohost.org, O = yunohost
</code></pre></div></div>
<p><strong>Solution problème smtp</strong></p>
<p>Exécuter la commande suivante</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postmap -F hash:/etc/postfix/sni
</code></pre></div></div>
<p>Tester de nouveau la validité du certificat sur le serveur SMTP:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client <span class="nt">-starttls</span> smtp <span class="nt">-showcerts</span> <span class="nt">-connect</span> ouestyan.fr:587 <span class="nt">-servername</span> ouestyan.fr
</code></pre></div></div>
<p>Le serveur SMTP utilise maintenant le certificat <strong>Lets encrypt</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = ouestyan.fr
verify return:1
---
Certificate chain
0 s:CN = ouestyan.fr
i:C = US, O = Let's Encrypt, CN = R3
</code></pre></div></div>
<h2 id="sauvegardes">Sauvegardes</h2>
<h3 id="borg">Borg</h3>
<p><img src="/images/borg-logo.png" alt="" /></p>
<ul>
<li><a href="/2021/10/04/BorgBackup_Yunohost-Boite_de_stockage.html">BorgBackup Yunohost &gt; Boîte de stockage</a><br />
Dépôt borg : <code class="language-plaintext highlighter-rouge">ssh://u277865@u277865.your-storagebox.de:23/./backup/borg/ouestyan_fr</code></li>
<li>BorgBackup Yunohost &gt; yanfi.space (serveur debian bullseye)<br />
Dépôt borg : <code class="language-plaintext highlighter-rouge">ssh://borg@yanfi.space:55178/srv/data/borg-backups/ouestyan_fr</code></li>
</ul>
<h4 id="installation-borg">Installation borg</h4>
<p>Le dépôt final : ssh://u277865@u277865.your-storagebox.de:23/./backup/borg/ouestyan_fr<br />
La passphrase : CuscuteFroueAtaxieFilleSexismeRikiki</p>
<p>Connexion en admin sur yunohost<br />
Installer une application, rechercher borg <br />
<img src="/images/yunocontabo007.png" alt="" /></p>
<p><img src="/images/yunocontabo008.png" alt="" /><br />
<img src="/images/yunocontabo009.png" alt="" /><br />
(2) Remplacer par <code class="language-plaintext highlighter-rouge">ssh://borg@yanfi.space:55178/srv/data/borg-backups/ouestyan_fr</code> pour serveur debian
(4) Si lon veut une sauvegarde à 2h00 du mation tous les jours, il faut remplacer <code class="language-plaintext highlighter-rouge">Daily</code> par <code class="language-plaintext highlighter-rouge">02:00</code></p>
<p>Patienter …<br />
<img src="/images/yunocontabo010.png" alt="" width="400" /><br />
A la fin de linstallation<br />
<img src="/images/yunocontabo011.png" alt="" /></p>
<h4 id="boîte-de-stockage">boîte de stockage</h4>
<p>Il faut récupérer la clé publique destinée à la boîte de stockage <a href="mailto:u277865@u277865.your-storagebox.de">u277865@u277865.your-storagebox.de</a>
En ligne de commande et en mode su : <code class="language-plaintext highlighter-rouge">cat /root/.ssh/id_borg_ed25519.pub</code></p>
<p>Clé publique à ajouter au fichier <code class="language-plaintext highlighter-rouge">/home/.ssh/authorized_keys</code> de la boîte de stockage <strong>u277865@u277865.your-storagebox.de</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA7M8tQJ9glaKInMLjTzYAeUh44Ftv9gKCMwtg6F8Yy9 root@ouestyan.fr
</code></pre></div></div>
<p>Tester la liaison boîte de stockage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sftp -P 23 -i /root/.ssh/id_borg_ed25519 u277865@u277865.your-storagebox.de
</code></pre></div></div>
<p><img src="/images/yunocontabo014.png" alt="" /></p>
<h4 id="tester-la-configuration-borg">Tester la configuration borg</h4>
<p class="info">À cette étape, votre sauvegarde devrait se dérouler à lheure prévue (tous les jours à 2h00). Notez que la première sauvegarde peut être très longue, car de nombreuses données doivent être copiées via ssh. Les sauvegardes suivantes sont incrémentielles : seules les données nouvellement générées depuis la dernière sauvegarde seront copiées.</p>
<p>Si vous voulez tester la configuration correcte de Borg Apps avant lheure prévue, vous pouvez lancer une sauvegarde manuellement sur le serveur Yunohost ouestyan.fr :</p>
<p>On passe en tmux</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-s</span>
tmux
systemctl start borg
<span class="c"># Ctrl b d pour sortir de la session tmux</span>
</code></pre></div></div>
<p>Patienter quelques minutes…</p>
<h4 id="lister-les-sauvegardes">Lister les sauvegardes</h4>
<p>Commande à exécuter en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
app=borg; BORG_PASSPHRASE="$(yunohost app setting $app passphrase)" BORG_RSH="ssh -i /root/.ssh/id_${app}_ed25519 -oStrictHostKeyChecking=yes " borg list "$(yunohost app setting $app repository)"
</code></pre></div></div>
<p>Exemple</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>_auto_conf-2022-08-22_21:08 Mon, 2022-08-22 21:08:24 [ab8501c566921e9c2cd70baacb2f2fc886da204a95cdb5b3e6c87e19d1377b32]
_auto_data-2022-08-22_21:08 Mon, 2022-08-22 21:08:50 [2a263b08aa75c81e932e6cac9eea263c8f340b39e7ff9851a22cbadd7b931158]
_auto_borg-2022-08-22_21:09 Mon, 2022-08-22 21:09:07 [0e0fdeead7502c08acb7d3d875337ef4db0ec77667628309aab17b52aecbe15a]
</code></pre></div></div>
<h2 id="données">Données</h2>
<h3 id="srvdatayan-ouestyanfr">/srv/datayan ouestyan.fr</h3>
<p class="info">Le dossier datayan va contenir tous les dossiers de données :<br />
<strong>BiblioCalibre CalibreTechnique media musique static www</strong></p>
<p>Créer un utilisateur Linux avec un répertoire Home personnalisé <code class="language-plaintext highlighter-rouge">/srv/datayan</code>, un Shell, un commentaire, un UID et un GID personnalisés</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd -m -d /srv/datayan -s /bin/bash -c "Dossiers yannick" -u 1000 userdata
</code></pre></div></div>
<p>Ajouter cet utilisateur au groupe users</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -a -G users userdata
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo id userdata
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">uid=1000(userdata) gid=1002(userdata) groups=1002(userdata),100(users)</code></p>
<p>Droits sur le dossier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown userdata:users -R /srv/datayan/
</code></pre></div></div>
<p>Passer en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>Passer en utilisateur userdata</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su -- userdata
</code></pre></div></div>
<p>Création dossier <code class="language-plaintext highlighter-rouge">.ssh</code> , utilisateur “userdata”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /srv/datayan/.ssh
</code></pre></div></div>
<p>On va créer un jeu de clés SSH <strong>contabo_ouestyan</strong> avec lutilisateur userdata pour un accès à la boîte de stockage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f /srv/datayan/.ssh/contabo_ouestyan
</code></pre></div></div>
<p>Ajout contenu de la clé publique <strong>/srv/datayan/.ssh/contabo_ouestyan.pub</strong> au fichier <strong>/home/.ssh/authorized_keys</strong> de la boîte de stockage <strong>u277865@u277865.your-storagebox.de</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBp5SbDA0UkQSE2UizFG/ZZNmsD6LsVzYfvR3xgAetAu userdata@ouestyan.fr
</code></pre></div></div>
<p>Test de la connexion</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sftp -P 23 -i /srv/datayan/.ssh/contabo_ouestyan u277865@u277865.your-storagebox.de
</code></pre></div></div>
<p><img src="/images/yunocontabo004.png" alt="" /></p>
<p>Création des dossiers</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /srv/datayan/{www,BiblioCalibre,CalibreTechnique,musique,static}
</code></pre></div></div>
<p>Télécharger les contenus du dossier <strong>/srv/datayan/</strong> de la boîte de stockage<br />
On passe en tmux pour exécuter le script en arrière plan</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux
</code></pre></div></div>
<p>Exécuter le script suivant</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># les dossiers sous /srv/datayan/ : BiblioCalibre CalibreTechnique musique static www</span>
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--exclude</span> <span class="s1">'.ssh/*'</span> <span class="nt">-e</span> <span class="s2">"ssh -p 23 -i /srv/datayan/.ssh/contabo_ouestyan -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> <span class="nt">--recursive</span> u277865@u277865.your-storagebox.de:datayan/www/ /srv/datayan/www/
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--exclude</span> <span class="s1">'.ssh/*'</span> <span class="nt">-e</span> <span class="s2">"ssh -p 23 -i /srv/datayan/.ssh/contabo_ouestyan -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> <span class="nt">--recursive</span> u277865@u277865.your-storagebox.de:datayan/static/ /srv/datayan/static/
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--exclude</span> <span class="s1">'.ssh/*'</span> <span class="nt">-e</span> <span class="s2">"ssh -p 23 -i /srv/datayan/.ssh/contabo_ouestyan -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> <span class="nt">--recursive</span> u277865@u277865.your-storagebox.de:datayan/BiblioCalibre/ /srv/datayan/BiblioCalibre/
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--exclude</span> <span class="s1">'.ssh/*'</span> <span class="nt">-e</span> <span class="s2">"ssh -p 23 -i /srv/datayan/.ssh/contabo_ouestyan -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> <span class="nt">--recursive</span> u277865@u277865.your-storagebox.de:datayan/CalibreTechnique/ /srv/datayan/CalibreTechnique/
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--exclude</span> <span class="s1">'.ssh/*'</span> <span class="nt">-e</span> <span class="s2">"ssh -p 23 -i /srv/datayan/.ssh/contabo_ouestyan -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> <span class="nt">--recursive</span> u277865@u277865.your-storagebox.de:datayan/musique/ /srv/datayan/musique/
</code></pre></div></div>
<p>Sortie utilisateur “userdata”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>exit
</code></pre></div></div>
<h2 id="applications">Applications</h2>
<h3 id="nextcloud">Nextcloud</h3>
<p>Clone de la branche 24.0.0</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone --single-branch --branch 24.0.0 https://github.com/YunoHost-Apps/nextcloud_ynh
</code></pre></div></div>
<p>Remplacer <em>php8.0-fpm</em> par <em>php7.4-fpm</em> dans le fichier <code class="language-plaintext highlighter-rouge">nextcloud_ynh/manifest.json</code></p>
<p>Installer Nextcloud version 24 avec PHP7.4</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost app install nextcloud_ynh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DANGER! This app is not part of YunoHost's app catalog. Installing third-party apps may compromise the inte
grity and security of your system. You should probably NOT install it unless you know what you are doing. N
O SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take tha
t risk anyway, type 'Yes, I understand': Yes, I understand
Choose the domain where this app should be installed [ouestyan.fr]: ouestyan.fr
Choose the URL path (after the domain) where this app should be installed: /nextcloud
Choose an administrator user for this app [yack]: yack
Should this app be exposed to anonymous visitors? [yes | no]: yes
Access the users home folder from Nextcloud? [yes | no]: yes
Info: Installing nextcloud...
Info: [....................] &gt; Validating installation parameters...
Info: [....................] &gt; Storing installation settings...
Info: [+...................] &gt; Installing dependencies...
Warning: Load smb config files from /etc/samba/smb.conf
Warning: Loaded services file OK.
Warning: Weak crypto is allowed
Warning: Server role: ROLE_STANDALONE
Info: [#+..................] &gt; Creating a MySQL database...
Info: [##..................] &gt; Setting up source files...
Info: [##..................] &gt; Configuring system user...
Info: [##++++++++..........] &gt; Configuring PHP-FPM...
Info: [##########+.........] &gt; Configuring NGINX web server...
Info: [###########.........] &gt; Creating a data directory...
Info: [###########++++.....] &gt; Installing Nextcloud...
Info: [###############++...] &gt; Configuring Nextcloud...
Info: [#################+..] &gt; Adding multimedia directories...
Info: [##################..] &gt; Configuring log rotation...
Info: [##################+.] &gt; Configuring Fail2Ban...
Info: The service fail2ban has correctly executed the action reload-or-restart.
Info: [###################.] &gt; Configuring permissions...
Info: [###################.] &gt; Reloading NGINX web server...
Info: [####################] &gt; Installation of nextcloud completed
Success! Installation completed
</code></pre></div></div>
<h3 id="audio-yann-zicouestyanfr">Audio Yann (zic.ouestyan.fr)</h3>
<p><em>Navidrome est un serveur et un streamer de collection de musique en ligne open source. Il vous donne la liberté découter votre playlist à partir de nimporte quel navigateur ou appareil mobile.</em></p>
<p>Votre musique est a stockée par default dans le dossier multimédia partagé /home/yunohost.multimedia/share/Music. Ce dossier, facilement accessible depuis Nextcloud avec Stockages externes activée, vous permettra duploader facilement vos fichiers de musique sur votre server.</p>
<p>Vous pouvez personnaliser le dossier de stockage de vos fichiers de musique en éditant le fichier de configuration <strong>/var/lib/navidrome/navidrome.toml</strong> et rediriger la variable <code class="language-plaintext highlighter-rouge">MusicFolder = "/home/yunohost.multimedia/share/Music"</code>. Vous pouvez également changer dautre réglage en vous aidant de la <a href="https://www.navidrome.org/docs/usage/configuration-options/">documentation</a>.</p>
<p>En mode su</p>
<p>Ajout domaine zic.ouestyan.fr en mode administration web<br />
<img src="/images/ouestyan.fr-001.png" alt="" />{width=”400”}</p>
<p>Modifier la configuration du domaine<br />
<img src="/images/ouestyan.fr-002.png" alt="" /></p>
<p>Certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yunohost domain cert-install zic.ouestyan.fr --no-checks
</code></pre></div></div>
<p>Installer navidrome<br />
<img src="/images/xoyaz-yunohost-007.png" alt="" />
<img src="/images/xoyaz-yunohost-008.png" alt="" />
<img src="/images/ouestyan.fr-003.png" alt="" /></p>
<p>Application navidrome<br />
Vérifier le paramétrage <strong>/var/lib/navidrome/navidrome.toml</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Base URL (only the path part) to configure Navidrome behind a proxy (ex: /music)
BaseURL = "/"
# Folder where your music library is stored. Can be read-only
MusicFolder = "/srv/datayan/musique"
</code></pre></div></div>
<p>Créer un compte adminitrateur</p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2022-08-20T00: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="/2022/08/19/Linux-Antivirus-ClamAV.html">ClamAV antivirus linux</a></div><div class="next"><span>SUIVANT</span><a href="/2022/08/26/IONOS_VPS-S_DNS_dot_doh_debian_11.html">IONOS VPS S debian 11 - résolveur DNS public sur TLS (DoT) et HTTPS (DoH)</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>