3246 lines
256 KiB
HTML
3246 lines
256 KiB
HTML
|
<!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>HostMyServers, server32771 Debian 11 (Bullseye) - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="Accès client">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2022/07/21/HostMyServers-VPS-server32771-Debian-Bullseye.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} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {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;">HostMyServers, server32771 Debian 11 (Bullseye)</h1></header></div><meta itemprop="headline" content="HostMyServers, server32771 Debian 11 (Bullseye)"><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></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">21 juil. 2022</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F"> 9 nov. 2022</span></li></ul></div><meta itemprop="datePublished" content="2022-11-09T00:00:00+01:00">
|
|||
|
<meta itemprop="keywords" content="vps"><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">⇧</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/hms.png" alt="" width="80" /><br />
|
|||
|
<a href="https://www.hostmyservers.fr/user">Accès client</a></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="#debian-bullseye">Debian bullseye</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#reconfigurer-locales">Reconfigurer locales</a></li>
|
|||
|
<li><a href="#ntp-avec-systemd-timesyncd">NTP avec systemd-timesyncd</a></li>
|
|||
|
<li><a href="#dns-resolvconf">DNS resolvconf</a></li>
|
|||
|
<li><a href="#création-utilisateur">Création utilisateur</a></li>
|
|||
|
<li><a href="#openssh-clé-et-script">OpenSSH, clé et script</a></li>
|
|||
|
<li><a href="#outils-scripts-motd-et-ssh_rc_bash">Outils, scripts motd et ssh_rc_bash</a></li>
|
|||
|
<li><a href="#parefeu-ufw">Parefeu UFW</a></li>
|
|||
|
<li><a href="#nginx-compilé">Nginx compilé</a></li>
|
|||
|
<li><a href="#domaine-et-certificats">Domaine et certificats</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#ovh-domaine-ouestyanfr">OVH domaine ouestyan.fr</a></li>
|
|||
|
<li><a href="#certificats-lets-encrypt">Certificats Let’s Encrypt</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#nginx-securityconfinc">Nginx security.conf.inc</a></li>
|
|||
|
<li><a href="#fail2ban">Fail2ban</a></li>
|
|||
|
<li><a href="#notifications">Notifications</a></li>
|
|||
|
<li><a href="#docker">Docker</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#sauvegardes">Sauvegardes</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#données-srvdatayan">Données /srv/datayan</a></li>
|
|||
|
<li><a href="#borgbackup">BorgBackup</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#ouestyanfr">ouestyan.fr</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#accueil">Accueil</a></li>
|
|||
|
<li><a href="#navidrome">Navidrome</a></li>
|
|||
|
<li><a href="#searx">Searx</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#installation-des-paquets-prérequis">Installation des paquets prérequis</a></li>
|
|||
|
<li><a href="#installer-searx-et-les-dépendances">Installer searx et les dépendances</a></li>
|
|||
|
<li><a href="#configuration">Configuration</a></li>
|
|||
|
<li><a href="#vérifier-en-local">Vérifier en local</a></li>
|
|||
|
<li><a href="#uwsgi">uwsgi</a></li>
|
|||
|
<li><a href="#nginx-proxy-searx">nginx proxy searx</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#nextcloud">Nextcloud</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#transmission-torrent">Transmission Torrent</a></li>
|
|||
|
<li><a href="#installer-transmission-daemon">Installer transmission-daemon</a></li>
|
|||
|
<li><a href="#proxy-nginx">Proxy nginx</a></li>
|
|||
|
<li><a href="#dossiers-et-configuration">Dossiers et configuration</a></li>
|
|||
|
<li><a href="#transmissionouestyanfr">transmission.ouestyan.fr</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#test-de-sécurité">Test de sécurité</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="debian-bullseye">Debian bullseye</h2>
|
|||
|
|
|||
|
<p><img src="/images/debian11-logo.png" alt="" height="60" /></p>
|
|||
|
|
|||
|
<p>PARAMETRES D’ACCES:<br />
|
|||
|
L’adresse IPv4 du VPS est : 45.145.166.178<br />
|
|||
|
L’adresse IPv6 du VPS est : 2a04:ecc0:8:a8:4567:4989::1</p>
|
|||
|
|
|||
|
<p>Connexion SSH en “root”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh root@45.145.166.178
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifier le fichier des dépôts <code class="language-plaintext highlighter-rouge">/etc/apt/sources.list</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>deb http://deb.debian.org/debian bullseye main contrib non-free
|
|||
|
deb-src http://deb.debian.org/debian bullseye main contrib non-free
|
|||
|
|
|||
|
#deb http://deb.debian.org/debian bullseye-updates main contrib non-free
|
|||
|
#deb-src http://deb.debian.org/debian bullseye-updates main contrib non-free
|
|||
|
|
|||
|
deb http://security.debian.org/debian-security bullseye-security main
|
|||
|
deb-src http://security.debian.org/debian-security bullseye-security main
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Rafraîchir</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update && apt upgrade
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Créer mot de passe “root”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le paramétrage réseau par défaut <code class="language-plaintext highlighter-rouge">/etc/network/interfaces.d/50-cloud-init</code><br />
|
|||
|
Il faut commenter la ligne <code class="language-plaintext highlighter-rouge">dns-nameservers 194.9.173.89 2a04:ecc0:4::89</code> pour utiliser dnsmasq</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># This file is generated from information provided by the datasource. Changes
|
|||
|
# to it will not persist across an instance reboot. To disable cloud-init's
|
|||
|
# network configuration capabilities, write a file
|
|||
|
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
|
|||
|
# network: {config: disabled}
|
|||
|
auto lo
|
|||
|
iface lo inet loopback
|
|||
|
# dns-nameservers 194.9.173.89 2a04:ecc0:4::89
|
|||
|
|
|||
|
auto eth0
|
|||
|
iface eth0 inet static
|
|||
|
address 45.145.166.178/24
|
|||
|
gateway 45.145.166.1
|
|||
|
|
|||
|
# control-alias eth0
|
|||
|
iface eth0 inet6 static
|
|||
|
address 2a04:ecc0:8:a8:4567:4989::1/64
|
|||
|
gateway 2a04:ecc0:8:a8::1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="reconfigurer-locales">Reconfigurer locales</h3>
|
|||
|
|
|||
|
<p>installer le paquet locales-all</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt-get install locales-all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="ntp-avec-systemd-timesyncd">NTP avec systemd-timesyncd</h3>
|
|||
|
|
|||
|
<p>Le service ntp de systemd s’appelle <strong>systemd-timesyncd.service</strong><br />
|
|||
|
La configuration se fait dans <code class="language-plaintext highlighter-rouge">/etc/systemd/timesyncd.conf</code></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Si vous utilisez un autre service pour gérer NTP, assurez-vous de le(s) désactiver : ntpd chronyd</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Installation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install systemd-timesyncd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Par défaut</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl status systemd-timesyncd.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● systemd-timesyncd.service - Network Time Synchronization
|
|||
|
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
|
|||
|
Active: active (running) since Sun 2022-09-25 02:50:09 UTC; 10h ago
|
|||
|
Docs: man:systemd-timesyncd.service(8)
|
|||
|
Main PID: 10822 (systemd-timesyn)
|
|||
|
Status: "Initial synchronization to time server 188.68.41.203:123 (0.debian.pool.ntp.org)."
|
|||
|
Tasks: 2 (limit: 4698)
|
|||
|
Memory: 1012.0K
|
|||
|
CPU: 54ms
|
|||
|
CGroup: /system.slice/systemd-timesyncd.service
|
|||
|
└─10822 /lib/systemd/systemd-timesyncd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Fuseau Europe/Paris</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo timedatectl set-timezone Europe/Paris
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Horloge système synchronisée</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>timedatectl
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Local time: dim. 2022-09-25 15:47:44 CEST
|
|||
|
Universal time: dim. 2022-09-25 13:47:44 UTC
|
|||
|
RTC time: dim. 2022-09-25 13:47:45
|
|||
|
Time zone: Europe/Paris (CEST, +0200)
|
|||
|
System clock synchronized: yes
|
|||
|
NTP service: active
|
|||
|
RTC in local TZ: no
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="dnsmasq">dnsmasq</h3>
|
|||
|
|
|||
|
<p><img src="/images/Dnsmasq_logo.png" alt="" /><br />
|
|||
|
<a href="/2019/12/25/DNSmasq.html">DNSmasq (installation et configuration)</a></p>
|
|||
|
|
|||
|
<p>Installation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install dnsmasq
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si le paquet <strong>resolvconf</strong> est installé, dnsmasq utilisera sa sortie plutôt que le contenu de <code class="language-plaintext highlighter-rouge">/etc/resolv.conf</code> pour trouver les serveurs de noms en amont. Décommenter la ligne <code class="language-plaintext highlighter-rouge">#IGNORE_RESOLVCONF=yes</code> empêche ce comportement.<br />
|
|||
|
Notez que l’inclusion d’une ligne <code class="language-plaintext highlighter-rouge">resolv-file=<filename></code> dans <code class="language-plaintext highlighter-rouge">/etc/dnsmasq.conf</code> n’est pas suffisante pour remplacer <strong>resolvconf</strong> si celui-ci est installé : la ligne <code class="language-plaintext highlighter-rouge">#IGNORE_RESOLVCONF=yes</code> doit être décommentée.</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">/etc/default/dnsmasq</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Whether or not to run the dnsmasq daemon; set to 0 to disable.
|
|||
|
# Note that this is only valid when using SYSV init. For systemd,
|
|||
|
# use "systemctl disable dnsmasq"
|
|||
|
ENABLED=1
|
|||
|
|
|||
|
# By default search this drop directory for configuration options.
|
|||
|
# Libvirt leaves a file here to make the system dnsmasq play nice.
|
|||
|
# Comment out this line if you don't want this. The dpkg-* are file
|
|||
|
# endings which cause dnsmasq to skip that file. This avoids pulling
|
|||
|
# in backups made by dpkg.
|
|||
|
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
|||
|
|
|||
|
# If the resolvconf package is installed, dnsmasq will use its output
|
|||
|
# rather than the contents of /etc/resolv.conf to find upstream
|
|||
|
# nameservers. Uncommenting this line inhibits this behaviour.
|
|||
|
# Note that including a "resolv-file=<filename>" line in
|
|||
|
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
|||
|
# installed: the line below must be uncommented.
|
|||
|
IGNORE_RESOLVCONF=yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Configuration de dnsmasq avec le fichier /etc/resolv.conf</p>
|
|||
|
|
|||
|
<p>Vous devez faire en sorte que toutes les requêtes soient envoyées à dnsmasq en ajoutant les adresses localhost comme seuls serveurs de noms dans le fichier <code class="language-plaintext highlighter-rouge">/etc/resolv.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
|
|||
|
# 127.0.0.53 is the systemd-resolved stub resolver.
|
|||
|
# run "resolvectl status" to see details about the actual nameservers.
|
|||
|
|
|||
|
nameserver 127.0.0.1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ouvrir le fichier <code class="language-plaintext highlighter-rouge">/etc/dnsmasq.conf</code> et effectuer les réglages de configuration</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>domain-needed
|
|||
|
expand-hosts
|
|||
|
localise-queries
|
|||
|
|
|||
|
interface=lo
|
|||
|
|
|||
|
resolv-file=/etc/resolv.dnsmasq.conf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Explications</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>domain-needed</strong> : Ne transmet pas les requêtes ne contenant pas un nom de domaine complet. Par exemple,une requête pour machine ne sera pas transmise aux serveurs DNS de votre FAI, alors qu’une requête pour machine.domain.com le sera.</li>
|
|||
|
<li>Si vous souhaitez qu’un domaine soit automatiquement ajouté aux noms simples dans un fichier hosts, décommentez l’option <strong>expand-hosts</strong></li>
|
|||
|
<li><strong>localise-queries</strong> : Retourne des réponses aux requêtes DNS dépendantes de l’interface sur laquelle la requête a été reçue, à partir du fichier /etc/hosts. Si un nom dans /etc/hosts a plus d’une adresse associée avec lui, et qu’une des adresses au moins est dans le même sous-réseau que l’interface sur laquelle la requête a été reçue, alors ne retourne que la(les) adresse(s) du sous-réseau considéré. Cela permet d’avoir dans /etc/hosts un serveur avec de multiples adresses, une pour chacune de ses interfaces, et de fournir aux hôtes l’adresse correcte (basée sur le réseau auquel ils sont attachés). Cette possibilité est actuellement limitée à IPv4.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Pour lutter contre la censure sur Internet, <a href="https://www.fdn.fr/actions/dns/">FDN</a> fait le choix de mettre à disposition de toutes et tous des résolveurs DNS récursifs ouverts.<br />
|
|||
|
Le fichier des dns <code class="language-plaintext highlighter-rouge">/etc/resolv.dnsmasq.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nameserver 80.67.169.12
|
|||
|
nameserver 2001:910:800::12
|
|||
|
nameserver 80.67.169.40
|
|||
|
nameserver 2001:910:800::40
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer dnsmasq</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart dnsmasq
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifications, installer dnsutils au préalable (<code class="language-plaintext highlighter-rouge">sudo apt install dnsutils</code>)</p>
|
|||
|
|
|||
|
<h3 id="création-utilisateur">Création utilisateur</h3>
|
|||
|
|
|||
|
<p>Utilisateur <strong>hmsuser</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /home/hmsuser/ -s /bin/bash hmsuser
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Mot de passe <strong>hmsuser</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd hmsuser
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Visudo pour les accès root via utilisateur <strong>hmsuser</strong></p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"hmsuser ALL=(ALL) NOPASSWD: ALL"</span> <span class="o">>></span> /etc/sudoers
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Déconnexion puis connexion ssh en mode utilisateur</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh hmsuser@45.145.166.178
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="openssh-clé-et-script">OpenSSH, clé et script</h3>
|
|||
|
|
|||
|
<p><img src="/images/ssh_logo1.png" alt="OpenSSH" height="70" /><br />
|
|||
|
<strong>connexion avec clé</strong><br />
|
|||
|
<u>sur l'ordinateur de bureau</u>
|
|||
|
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) pour une liaison SSH avec le serveur.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/server32771
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Envoyer les clés publiques sur le serveur KVM</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id -i ~/.ssh/server32771.pub hmsuser@45.145.166.178
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><u>sur le serveur KVM</u>
|
|||
|
On se connecte</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh hmsuser@45.145.166.178
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifier la configuration serveur SSH</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/ssh/sshd_config
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifier</p>
|
|||
|
|
|||
|
<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Port</span> = <span class="m">55178</span>
|
|||
|
<span class="n">PermitRootLogin</span> <span class="n">no</span>
|
|||
|
<span class="n">PasswordAuthentication</span> <span class="n">no</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Relancer openSSH</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart sshd
|
|||
|
</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 hmsuser@45.145.166.178 -p 55178 -i ~/.ssh/server32771
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="outils-scripts-motd-et-ssh_rc_bash">Outils, scripts motd et ssh_rc_bash</h3>
|
|||
|
|
|||
|
<p><img src="/images/bash-shell-logo.png" alt="" height="50" /><br />
|
|||
|
Installer utilitaires</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install rsync curl tmux jq figlet git
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Motd</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/motd && sudo nano /etc/motd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> _ _ _ __ __ ___
|
|||
|
| || | ___ ___| |_ | \/ | _ _ / __| ___ _ _ __ __ ___ _ _ ___
|
|||
|
| __ |/ _ \(_-<| _|| |\/| || || |\__ \/ -_)| '_|\ V // -_)| '_|(_-<
|
|||
|
|_||_|\___//__/ \__||_| |_| \_, ||___/\___||_| \_/ \___||_| /__/
|
|||
|
|__/____ ___ ____ ____ _
|
|||
|
___ ___ _ _ __ __ ___ _ _|__ /|_ )|__ ||__ |/ |
|
|||
|
(_-</ -_)| '_|\ V // -_)| '_||_ \ / / / / / / | |
|
|||
|
/__/\___||_| \_/ \___||_| |___//___| /_/ /_/ |_|
|
|||
|
_ __
|
|||
|
___ _ _ ___ ___| |_ _ _ __ _ _ _ / _| _ _
|
|||
|
/ _ \| || |/ -_)(_-<| _|| || |/ _` || ' \ _ | _|| '_|
|
|||
|
\___/ \_,_|\___|/__/ \__| \_, |\__,_||_||_|(_)|_| |_|
|
|||
|
|__/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Script <strong>ssh_rc_bash</strong></p>
|
|||
|
<blockquote>
|
|||
|
<p><strong>ATTENTION!!! Les scripts sur connexion peuvent poser des problèmes pour des appels externes autres que ssh</strong></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://static.xoyaz.xyz/files/ssh_rc_bash
|
|||
|
chmod +x ssh_rc_bash # rendre le bash exécutable
|
|||
|
./ssh_rc_bash # exécution
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/hms.ouestyan.fr.png" alt="" /></p>
|
|||
|
|
|||
|
<h3 id="parefeu-ufw">Parefeu UFW</h3>
|
|||
|
|
|||
|
<p><img src="/images/ufw-logo.png" alt="ufw" width="50" /></p>
|
|||
|
|
|||
|
<p><em>UFW, ou pare - feu simple , est une interface pour gérer les règles de pare-feu dans Arch Linux, Debian ou Ubuntu. UFW est utilisé via la ligne de commande (bien qu’il dispose d’interfaces graphiques disponibles), et vise à rendre la configuration du pare-feu facile.</em></p>
|
|||
|
|
|||
|
<p>Installation <strong>Debian / Ubuntu</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install ufw
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Par défaut, les jeux de règles d’UFW sont vides, de sorte qu’il n’applique aucune règle de pare-feu, même lorsque le démon est en cours d’exécution.</em></p>
|
|||
|
|
|||
|
<p>Les règles</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw allow 55178/tcp <span class="c"># port SSH</span>
|
|||
|
<span class="nb">sudo </span>ufw allow http <span class="c"># port 80</span>
|
|||
|
<span class="nb">sudo </span>ufw allow https <span class="c"># port 443</span>
|
|||
|
<span class="nb">sudo </span>ufw allow DNS <span class="c"># port 53</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Activer le parefeu</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ufw enable
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
|
|||
|
Firewall is active and enabled on system startup
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Status</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo ufw status verbose
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Status: active
|
|||
|
Logging: on (low)
|
|||
|
Default: deny (incoming), allow (outgoing), disabled (routed)
|
|||
|
New profiles: skip
|
|||
|
|
|||
|
To Action From
|
|||
|
-- ------ ----
|
|||
|
55178/tcp ALLOW IN Anywhere
|
|||
|
80/tcp ALLOW IN Anywhere
|
|||
|
443 ALLOW IN Anywhere
|
|||
|
53 (DNS) ALLOW IN Anywhere
|
|||
|
55178/tcp (v6) ALLOW IN Anywhere (v6)
|
|||
|
80/tcp (v6) ALLOW IN Anywhere (v6)
|
|||
|
443 (v6) ALLOW IN Anywhere (v6)
|
|||
|
53 (DNS (v6)) ALLOW IN Anywhere (v6)
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="nginx-compilé">Nginx compilé</h3>
|
|||
|
|
|||
|
<p><img src="/images/nginx-logo.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Utilisateur avec droits sudo</p>
|
|||
|
|
|||
|
<p>Télécharger le bash</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://static.xoyaz.xyz/files/compilation-nginx-tls1.3.sh
|
|||
|
chmod +x compilation-nginx-tls1.3.sh # rendre le bash exécutable
|
|||
|
./compilation-nginx-tls1.3.sh # exécution
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>A la fin de la compilation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Versions Nginx OpenSSL
|
|||
|
nginx version: nginx/1.20.2
|
|||
|
OpenSSL 1.1.1n 15 Mar 2022
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="domaine-et-certificats">Domaine et certificats</h3>
|
|||
|
|
|||
|
<p>Se connecter sur HMS pour configurer le reverse dns <br />
|
|||
|
45.145.166.178 –> ouestyan.fr<br />
|
|||
|
Demander par ticket la modification du reverse dns ipv6<br />
|
|||
|
2a04:ecc0:8:a8:4567:4989:0:1 –> ouestyan.fr</p>
|
|||
|
|
|||
|
<p>Changer le hostname</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo hostnamectl set-hostname ouestyan.fr
|
|||
|
hostnamectl
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Static hostname: ouestyan.fr
|
|||
|
Icon name: computer-vm
|
|||
|
Chassis: vm
|
|||
|
Machine ID: 0e0cc9839fc64a049ba55e3248fab176
|
|||
|
Boot ID: f3913f931a8b4090a7d40ac500e2db0f
|
|||
|
Virtualization: kvm
|
|||
|
Operating System: Debian GNU/Linux 11 (bullseye)
|
|||
|
Kernel: Linux 5.10.0-18-cloud-amd64
|
|||
|
Architecture: x86-64
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="ovh-domaine-ouestyanfr">OVH domaine ouestyan.fr</h4>
|
|||
|
|
|||
|
<p><img src="/images/dns-logo.png" alt="dns" width="50" /><br />
|
|||
|
OVH configuration domaine <strong>ouestyan.fr</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 3600
|
|||
|
@ IN SOA dns17.ovh.net. tech.ovh.net. (2022092612 86400 3600 3600000 60)
|
|||
|
IN NS ns17.ovh.net.
|
|||
|
IN NS dns17.ovh.net.
|
|||
|
IN MX 10 ouestyan.fr.
|
|||
|
IN A 45.145.166.178
|
|||
|
IN AAAA 2a04:ecc0:8:a8:4567:4989::1
|
|||
|
IN CAA 128 issue "letsencrypt.org"
|
|||
|
* IN A 45.145.166.178
|
|||
|
* IN AAAA 2a04:ecc0:8:a8:4567:4989::1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="certificats-lets-encrypt">Certificats Let’s Encrypt</h4>
|
|||
|
|
|||
|
<p><img src="/images/letsencrypt-logo1.png" alt="letsencrypt" height="80" /><br />
|
|||
|
Installation gestionnaire des certificats Let’s Encrypt</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
|
|||
|
# socat est prérequis (installé par défaut)
|
|||
|
git clone https://github.com/acmesh-official/acme.sh.git
|
|||
|
cd acme.sh
|
|||
|
./acme.sh --install
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Se reconnecter</p>
|
|||
|
|
|||
|
<p>Exporter les clés OVH API</p>
|
|||
|
|
|||
|
<p>Génération des certificats</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --dns dns_ovh --server letsencrypt --issue --keylength ec-384 -d 'ouestyan.fr' -d '*.ouestyan.fr'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ouvrir le lien d’authentification et relancer la commande précédente après le message “OVH authentication Success !” et patienter…</p>
|
|||
|
|
|||
|
<p>Résultat de l’installation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[lun. 26 sept. 2022 08:36:37 CEST] Your cert is in: /home/hmsuser//.acme.sh/ouestyan.fr_ecc/ouestyan.fr.cer
|
|||
|
[lun. 26 sept. 2022 08:36:37 CEST] Your cert key is in: /home/hmsuser//.acme.sh/ouestyan.fr_ecc/ouestyan.fr.key
|
|||
|
[lun. 26 sept. 2022 08:36:38 CEST] The intermediate CA cert is in: /home/hmsuser//.acme.sh/ouestyan.fr_ecc/ca.cer
|
|||
|
[lun. 26 sept. 2022 08:36:38 CEST] And the full chain certs is there: /home/hmsuser//.acme.sh/ouestyan.fr_ecc/fullchain.cer
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installation des certificats</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 'ouestyan.fr' -d '*.ouestyan.fr' --key-file /etc/ssl/private/ouestyan.fr-key.pem --fullchain-file /etc/ssl/private/ouestyan.fr-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p class="warning">Supprimer ` –reloadcmd ‘sudo systemctl reload nginx.service’` à la ligne précédente si Nginx n’est pas installé</p>
|
|||
|
|
|||
|
<p>Editer le crontab</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>13 0 * * * "/home/hmsuser/.acme.sh"/acme.sh --cron --home "/home/hmsuser/.acme.sh" --renew-hook "/home/hmsuser/.acme.sh/acme.sh --ecc --install-cert -d 'ouestyan.fr' -d '*.ouestyan.fr' --key-file /etc/ssl/private/ouestyan.fr-key.pem --fullchain-file /etc/ssl/private/ouestyan.fr-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'" > /dev/null
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="nginx-securityconfinc">Nginx security.conf.inc</h3>
|
|||
|
|
|||
|
<p><a href="/2022/10/22/Nginx_headers_SSL_HSTS_OCSP.html">Nginx headers,SSL,HSTS,OCSP</a></p>
|
|||
|
|
|||
|
<p>Créer un fichier pour un regroupement <code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/security.conf.inc</code> mode intermédiaire</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # /etc/nginx/conf.d/security.conf.inc
|
|||
|
ssl_session_timeout 1d;
|
|||
|
ssl_session_cache shared:SSL:50m; # about 200000 sessions
|
|||
|
ssl_session_tickets off;
|
|||
|
|
|||
|
|
|||
|
# intermediate configuration
|
|||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
|||
|
ssl_prefer_server_ciphers off;
|
|||
|
|
|||
|
# Pre-defined FFDHE group (RFC 7919)
|
|||
|
# From https://ssl-config.mozilla.org/ffdhe2048.txt
|
|||
|
# https://security.stackexchange.com/a/149818
|
|||
|
ssl_dhparam /etc/ssl/private/ffdhe2048.pem;
|
|||
|
|
|||
|
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
|
|||
|
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
|||
|
# https://observatory.mozilla.org/
|
|||
|
|
|||
|
more_set_headers "Content-Security-Policy : upgrade-insecure-requests";
|
|||
|
more_set_headers "Referrer-Policy: same-origin;"
|
|||
|
|
|||
|
more_set_headers "X-Content-Type-Options : nosniff";
|
|||
|
more_set_headers "X-XSS-Protection : 1; mode=block";
|
|||
|
more_set_headers "X-Download-Options : noopen";
|
|||
|
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
|
|||
|
more_set_headers "X-Frame-Options : SAMEORIGIN";
|
|||
|
|
|||
|
# Disable the disaster privacy thing that is FLoC
|
|||
|
more_set_headers "Permissions-Policy : interest-cohort=()";
|
|||
|
|
|||
|
# Disable gzip to protect against BREACH
|
|||
|
# Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!)
|
|||
|
gzip off;
|
|||
|
|
|||
|
# Certificats Let's Encrypt
|
|||
|
ssl_certificate /etc/ssl/private/ouestyan.fr-fullchain.pem;
|
|||
|
ssl_certificate_key /etc/ssl/private/ouestyan.fr-key.pem;
|
|||
|
|
|||
|
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
|||
|
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
|
|||
|
|
|||
|
# OCSP settings
|
|||
|
ssl_stapling on;
|
|||
|
ssl_stapling_verify on;
|
|||
|
ssl_trusted_certificate /etc/ssl/private/ouestyan.fr-fullchain.pem;
|
|||
|
resolver 1.1.1.1;
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans tous les Vhosts, il faut ajouter l’inclusion du fichier : <code class="language-plaintext highlighter-rouge">include /etc/nginx/conf.d/security.conf.inc;</code></p>
|
|||
|
|
|||
|
<h3 id="fail2ban">Fail2ban</h3>
|
|||
|
|
|||
|
<p><a href="/2022/09/27/Debian_11_Fail2ban_UFW.html">Installer et configurer Fail2ban + UFW sur Debian 11</a></p>
|
|||
|
|
|||
|
<h3 id="notifications">Notifications</h3>
|
|||
|
|
|||
|
<p><code class="language-plaintext warning highlighter-rouge">Il faut demander l'ouverture du port 25 au fournisseur du VPS</code></p>
|
|||
|
|
|||
|
<p>Le serveur doit pouvoir expédier des messages de notification par messagerie</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Il faut ajouter le port TCP 25 au parefeu : <code class="language-plaintext highlighter-rouge">sudo ufw allow 25</code></li>
|
|||
|
<li>Configurer DNS de votre fournisseur de domaine, ici OVH<br />
|
|||
|
Ajouter enregistrement MX : <strong>IN MX 10 ouestyan.fr.</strong> (le point est obligatoire après fr)</li>
|
|||
|
<li>Procédures d’installation et paramétrage →
|
|||
|
<a href="/2022/08/27/Debian_Postfix_serveur_SMTP_envoi_uniquement.html">Debian - Installer et configurer Postfix comme serveur SMTP d’envoi uniquement</a></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<p>Test envoi message</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "Test envoi via postfix smtp" | mail -s "serveur debian" root
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="docker">Docker</h3>
|
|||
|
|
|||
|
<p><a href="/2020/03/10/Docker-Debian-Buster.html">Docker + Docker Compose sur Debian, installation et utilisation</a></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>Docker Engine</strong> ou <strong>Docker Daemon</strong> correspondant au processus qui fait tourner Docker sur le système, en charge de la génération et l’exécution des containers</li>
|
|||
|
<li><strong>Docker Registry</strong> est un emplacement de stockage pour héberger les images de containers Docker (il peut être public ou privé)</li>
|
|||
|
<li><strong>Docker Image</strong> correspondant à un fichier qui contient la définition d’un container Docker (dépendances, configuration, etc.)</li>
|
|||
|
<li><strong>Docker Client</strong> correspondant à l’utilitaire en ligne de commande qui va permettre de gérer les containers (commande “docker”)</li>
|
|||
|
<li><strong>Docker Container</strong> correspondant aux containers en eux-mêmes, tout en sachant qu’une image peut permettre de créer plusieurs containers avec chacun un identifiant unique</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="sauvegardes">Sauvegardes</h2>
|
|||
|
|
|||
|
<h3 id="données-srvdatayan">Données /srv/datayan</h3>
|
|||
|
|
|||
|
<p class="info">Le dossier datayan va contenir tous les dossiers de données :<br />
|
|||
|
<strong>BiblioCalibre CalibreTechnique media musique static www</strong><br />
|
|||
|
L’utilisateur doit avoir un ID=1000</p>
|
|||
|
|
|||
|
<p><strong>Opérations sur le serveur HostMyServers server32771 (yanfi.space)</strong><br />
|
|||
|
Dans l’installation de base debian 11, l’utilisateur à un ID=1000</p>
|
|||
|
|
|||
|
<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 $USER
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier : <code class="language-plaintext highlighter-rouge">id $USER</code> → uid=1000(hmsuser) gid=1000(hmsuser) groups=1000(hmsuser),100(users)</p>
|
|||
|
|
|||
|
<p>Créer le dossier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /srv/datayan
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Donner les droits</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown $USER:users -R /srv/datayan
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="borgbackup">BorgBackup</h3>
|
|||
|
|
|||
|
<p><img src="/images/borg-logo.png" alt="" height="50" /><br />
|
|||
|
Installer borg : <code class="language-plaintext highlighter-rouge">sudo apt install borg</code><br />
|
|||
|
Créer un utilisateur borg et son répertoire “home” → <code class="language-plaintext highlighter-rouge">/srv/data/borg-backups</code> : <code class="language-plaintext highlighter-rouge">sudo useradd -d /srv/data -m -r -U borg</code></p>
|
|||
|
|
|||
|
<p>Les clés publiques des serveurs autorisés se trouvent dans le fichier <strong>authorized_keys</strong> de l’utilisateur <strong>borg</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@ouestyan:/home/hmsuser# su - borg
|
|||
|
$ pwd
|
|||
|
/srv/data/borg-backups
|
|||
|
$ cat .ssh/authorized_keys
|
|||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMs2JATwIa9fPOk0gfOgm4YNIT9ZKfWwpXDamzZ5dVsh root@ouestline.xyz
|
|||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPuVXP+pUjvedC/htJmKXamAotLESDCRqU0MOoD7vqCA root@422x.l.time4vps.cloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h2 id="ouestyanfr">ouestyan.fr</h2>
|
|||
|
|
|||
|
<h3 id="accueil">Accueil</h3>
|
|||
|
|
|||
|
<p>Déposer une image <code class="language-plaintext highlighter-rouge">wallpaper.jpg</code> dans le dossier <code class="language-plaintext highlighter-rouge">/var/www/default-www</code></p>
|
|||
|
|
|||
|
<p>Créer un fichier <code class="language-plaintext highlighter-rouge">/var/www/default-www/index.html</code></p>
|
|||
|
|
|||
|
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
|
|||
|
<span class="nt"><html></span>
|
|||
|
<span class="nt"><head></span>
|
|||
|
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
|
|||
|
<span class="nt"><title></span>ouestyan.fr<span class="nt"></title></span>
|
|||
|
<span class="nt"><style </span><span class="na">type=</span><span class="s">"text/css"</span> <span class="na">media=</span><span class="s">"screen"</span> <span class="nt">></span>
|
|||
|
<span class="nt">html</span> <span class="p">{</span>
|
|||
|
<span class="nl">margin</span><span class="p">:</span><span class="m">0</span><span class="p">;</span>
|
|||
|
<span class="nl">padding</span><span class="p">:</span><span class="m">0</span><span class="p">;</span>
|
|||
|
<span class="nl">background</span><span class="p">:</span> <span class="sx">url(wallpaper.jpg)</span> <span class="nb">no-repeat</span> <span class="nb">center</span> <span class="nb">fixed</span><span class="p">;</span>
|
|||
|
<span class="nl">-webkit-background-size</span><span class="p">:</span> <span class="n">cover</span><span class="p">;</span> <span class="c">/* pour anciens Chrome et Safari */</span>
|
|||
|
<span class="nl">background-size</span><span class="p">:</span> <span class="n">cover</span><span class="p">;</span> <span class="c">/* version standardisée */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="nt">body</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span> <span class="p">}</span>
|
|||
|
<span class="nt">a</span><span class="nd">:link</span> <span class="p">{</span>
|
|||
|
<span class="nl">color</span><span class="p">:</span> <span class="n">grey</span><span class="p">;</span>
|
|||
|
<span class="nl">background-color</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span>
|
|||
|
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="nt">a</span> <span class="p">{</span>
|
|||
|
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">underline</span><span class="p">;</span>
|
|||
|
<span class="nl">background-color</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span>
|
|||
|
<span class="nl">color</span><span class="p">:</span> <span class="m">#a00</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="nt">a</span><span class="nd">:visited</span> <span class="p">{</span>
|
|||
|
<span class="nl">color</span><span class="p">:</span> <span class="m">#844</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="nt">a</span><span class="nd">:hover</span><span class="o">,</span> <span class="nt">a</span><span class="nd">:focus</span><span class="o">,</span> <span class="nt">a</span><span class="nd">:active</span> <span class="p">{</span>
|
|||
|
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
|
|||
|
<span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
|
|||
|
<span class="nl">background</span><span class="p">:</span> <span class="m">#800</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
|
|||
|
<span class="nt"></style></span>
|
|||
|
|
|||
|
<span class="nt"></head></span>
|
|||
|
<span class="nt"><body></span>
|
|||
|
|
|||
|
<span class="nt"><h1></span>Serveur ouestyan.fr<span class="nt"></h1></span>
|
|||
|
|
|||
|
|
|||
|
<span class="nt"></body></span>
|
|||
|
<span class="nt"></html></span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>ouestyan.fr.conf</strong></p>
|
|||
|
|
|||
|
<p>Créer le fichier <code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/ouestyan.fr.conf</code></p>
|
|||
|
|
|||
|
<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
|
|||
|
<span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
|
|||
|
<span class="kn">listen</span> <span class="s">[::]:80</span><span class="p">;</span>
|
|||
|
<span class="kn">server_name</span> <span class="s">ouestyan.fr</span><span class="p">;</span>
|
|||
|
<span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span><span class="nv">$host$request_uri</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="c1"># /etc/nginx/conf.d/ouestyan.fr.conf</span>
|
|||
|
|
|||
|
|
|||
|
<span class="k">server</span> <span class="p">{</span>
|
|||
|
<span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
|
|||
|
<span class="kn">listen</span> <span class="s">[::]:443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
|
|||
|
<span class="kn">server_name</span> <span class="s">ouestyan.fr</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kn">root</span> <span class="n">/var/www/default-www</span><span class="p">;</span>
|
|||
|
<span class="kn">index</span> <span class="s">index.html</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kn">include</span> <span class="n">/etc/nginx/conf.d/security.conf.inc</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="c1">#include /etc/nginx/conf.d/ouestyan.fr.d/*.conf;</span>
|
|||
|
|
|||
|
<span class="kn">access_log</span> <span class="n">/var/log/nginx/ouestyan.fr-access.log</span><span class="p">;</span>
|
|||
|
<span class="kn">error_log</span> <span class="n">/var/log/nginx/ouestyan.fr-error.log</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lien <a href="https://ouestyan.fr">https://ouestyan.fr</a> <br />
|
|||
|
<img src="/images/ouestyan.fr.png" alt="" width="500" /></p>
|
|||
|
|
|||
|
<h3 id="navidrome">Navidrome</h3>
|
|||
|
|
|||
|
<p><a href="/2022/04/02/Audio_Navidrome-installation_sur_debian.html">Audio Navidrome, installation sur debian</a></p>
|
|||
|
|
|||
|
<p><strong><u>Installation navidrome</u></strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Conditions préalables à la mise à jour et à l’installation
|
|||
|
sudo apt update && sudo apt upgrade
|
|||
|
sudo apt install libtag1-dev ffmpeg
|
|||
|
# Utilisateur “navidrome”
|
|||
|
sudo useradd -r -s /bin/false navidrome
|
|||
|
# Créez un répertoire pour stocker l’exécutable Navidrome
|
|||
|
# et un répertoire de travail avec les permissions appropriées
|
|||
|
sudo install -d -o navidrome -g navidrome /opt/navidrome
|
|||
|
sudo install -d -o navidrome -g navidrome /var/lib/navidrome
|
|||
|
# On utilise la version compilée disponible sous ~/navidrome
|
|||
|
sudo mv navidrome /opt/navidrome/
|
|||
|
sudo chown -R navidrome:navidrome /opt/navidrome
|
|||
|
sudo chmod +x /opt/navidrome/navidrome
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Fichier de configuration <strong>navidrome.toml</strong> : <code class="language-plaintext highlighter-rouge">sudo nano /var/lib/navidrome/navidrome.toml</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MusicFolder = "/srv/datayan/musique"
|
|||
|
ND_PLAYLISTSPATH = "Playlists"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>unité Systemd <strong>navidrome.service</strong> : <code class="language-plaintext highlighter-rouge">sudo nano /etc/systemd/system/navidrome.service</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
|
|||
|
Description=Navidrome Music Server and Streamer compatible with Subsonic/Airsonic
|
|||
|
After=remote-fs.target network.target
|
|||
|
AssertPathExists=/var/lib/navidrome
|
|||
|
|
|||
|
[Install]
|
|||
|
WantedBy=multi-user.target
|
|||
|
|
|||
|
[Service]
|
|||
|
User=navidrome
|
|||
|
Group=navidrome
|
|||
|
Type=simple
|
|||
|
ExecStart=/opt/navidrome/navidrome --configfile "/var/lib/navidrome/navidrome.toml"
|
|||
|
WorkingDirectory=/var/lib/navidrome
|
|||
|
TimeoutStopSec=20
|
|||
|
KillMode=process
|
|||
|
Restart=on-failure
|
|||
|
|
|||
|
# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
|||
|
DevicePolicy=closed
|
|||
|
NoNewPrivileges=yes
|
|||
|
PrivateTmp=yes
|
|||
|
PrivateUsers=yes
|
|||
|
ProtectControlGroups=yes
|
|||
|
ProtectKernelModules=yes
|
|||
|
ProtectKernelTunables=yes
|
|||
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
|||
|
RestrictNamespaces=yes
|
|||
|
RestrictRealtime=yes
|
|||
|
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
|
|||
|
ReadWritePaths=/var/lib/navidrome
|
|||
|
|
|||
|
# You can uncomment the following line if you're not using the jukebox This
|
|||
|
# will prevent navidrome from accessing any real (physical) devices
|
|||
|
#PrivateDevices=yes
|
|||
|
|
|||
|
# You can change the following line to `strict` instead of `full` if you don't
|
|||
|
# want navidrome to be able to write anything on your filesystem outside of
|
|||
|
# /var/lib/navidrome.
|
|||
|
ProtectSystem=full
|
|||
|
|
|||
|
# You can uncomment the following line if you don't have any media in /home/*.
|
|||
|
# This will prevent navidrome from ever reading/writing anything there.
|
|||
|
#ProtectHome=true
|
|||
|
|
|||
|
# You can customize some Navidrome config options by setting environment variables here. Ex:
|
|||
|
#Environment=ND_BASEURL="/navidrome"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>lancer le service</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl daemon-reload
|
|||
|
<span class="nb">sudo </span>systemctl start navidrome.service
|
|||
|
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>navidrome.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Tester navidrome, exécuter la commande sur un poste local ayant accès via ssh au serveur distant</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 9500:localhost:4533 hmsuser@45.145.166.178 -p 55178 -i /home/yann/.ssh/server32771
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ouvrir le lien <code class="language-plaintext highlighter-rouge">localhost:9500</code> dans un navigateur</p>
|
|||
|
|
|||
|
<p><strong><u>Proxy nginx zic.ouestyan.fr</u></strong></p>
|
|||
|
|
|||
|
<p>Le fichier de configuration nginx <code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/zic.ouestyan.fr.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
|
|||
|
listen 80;
|
|||
|
listen [::]:80;
|
|||
|
server_name zic.ouestyan.fr;
|
|||
|
return 301 https://$host$request_uri;
|
|||
|
}
|
|||
|
server {
|
|||
|
listen 443 ssl http2;
|
|||
|
listen [::]:443 ssl http2;
|
|||
|
server_name zic.ouestyan.fr;
|
|||
|
|
|||
|
include /etc/nginx/conf.d/security.conf.inc;
|
|||
|
|
|||
|
location / {
|
|||
|
proxy_pass http://127.0.0.1:4533;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Valider et recharger ginx</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
|
|||
|
sudo systemctl reload nginx
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lien <a href="https://zic.ouestyan.fr">https://zic.ouestyan.fr</a><br />
|
|||
|
<img src="/images/zic.ouestyan.fr.png" alt="" width="500" /></p>
|
|||
|
|
|||
|
<h3 id="searx">Searx</h3>
|
|||
|
|
|||
|
<p><a href="https://searx.github.io/searx/admin/installation-searx.html#installation-basic">Step by step installation</a></p>
|
|||
|
|
|||
|
<h4 id="installation-des-paquets-prérequis">Installation des paquets prérequis</h4>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-H</span> apt-get <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\</span>
|
|||
|
python3-dev python3-babel python3-venv <span class="se">\</span>
|
|||
|
uwsgi uwsgi-plugin-python3 <span class="se">\</span>
|
|||
|
git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev <span class="se">\</span>
|
|||
|
shellcheck
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Créer un utilisateur système</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-H</span> useradd <span class="nt">--shell</span> /bin/bash <span class="nt">--system</span> <span class="se">\</span>
|
|||
|
<span class="nt">--home-dir</span> <span class="s2">"/usr/local/searx"</span> <span class="se">\</span>
|
|||
|
<span class="nt">--comment</span> <span class="s1">'Privacy-respecting metasearch engine'</span> searx
|
|||
|
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">mkdir</span> <span class="s2">"/usr/local/searx"</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">chown</span> <span class="nt">-R</span> <span class="s2">"searx:searx"</span> <span class="s2">"/usr/local/searx"</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="installer-searx-et-les-dépendances">Installer searx et les dépendances</h4>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># basculer sur utilisateur searx</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nt">-u</span> searx <span class="nt">-i</span>
|
|||
|
<span class="c"># le prompt : searx@ouestyan:~$</span>
|
|||
|
<span class="c"># cloner le dépôt</span>
|
|||
|
git clone <span class="s2">"https://github.com/searx/searx.git"</span> <span class="s2">"/usr/local/searx/searx-src"</span>
|
|||
|
<span class="c"># créer virtualenv</span>
|
|||
|
python3 <span class="nt">-m</span> venv <span class="s2">"/usr/local/searx/searx-pyenv"</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">". /usr/local/searx/searx-pyenv/bin/activate"</span> <span class="o">>></span> <span class="s2">"/usr/local/searx/.profile"</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour installer les dépendances de searx, quittez la session bash searx que vous avez ouverte ci-dessus et redémarrez-en une nouvelle.
|
|||
|
Avant l’installation, vérifiez d’abord si votre virtualenv provient du login (<code class="language-plaintext highlighter-rouge">~/.profile</code>) :</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hmsuser@ouestyan:~<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-H</span> <span class="nt">-u</span> searx <span class="nt">-i</span>
|
|||
|
<span class="o">(</span>searx-pyenv<span class="o">)</span> searx@ouestyan:~<span class="nv">$ </span><span class="nb">command</span> <span class="nt">-v</span> python <span class="o">&&</span> python <span class="nt">--version</span>
|
|||
|
/usr/local/searx/searx-pyenv/bin/python
|
|||
|
Python 3.9.2
|
|||
|
|
|||
|
<span class="c"># update pip's boilerplate ..</span>
|
|||
|
pip <span class="nb">install</span> <span class="nt">-U</span> pip
|
|||
|
pip <span class="nb">install</span> <span class="nt">-U</span> setuptools
|
|||
|
pip <span class="nb">install</span> <span class="nt">-U</span> wheel
|
|||
|
pip <span class="nb">install</span> <span class="nt">-U</span> pyyaml
|
|||
|
|
|||
|
<span class="c"># jump to searx's working tree and install searx into virtualenv</span>
|
|||
|
<span class="o">(</span>searx-pyenv<span class="o">)</span> searx@ouestyan:~<span class="nv">$ </span><span class="nb">cd</span> <span class="s2">"/usr/local/searx/searx-src"</span>
|
|||
|
<span class="o">(</span>searx-pyenv<span class="o">)</span> searx@ouestyan:~<span class="nv">$ </span>pip <span class="nb">install</span> <span class="nt">-e</span> <span class="nb">.</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="configuration">Configuration</h4>
|
|||
|
|
|||
|
<p>Ouvrez un deuxième terminal pour les tâches de configuration</p>
|
|||
|
|
|||
|
<p>Pour créer un /etc/searx/settings.yml initial, vous pouvez commencer par une copie du fichier <code class="language-plaintext highlighter-rouge">Origin : utils/templates/etc/searx/use_default_settings.yml</code>. Cette configuration utilise les paramètres par défaut de <code class="language-plaintext highlighter-rouge">Origin : searx/settings.yml</code> et est recommandée depuis la fusion du PR 2291.</p>
|
|||
|
|
|||
|
<p>Pour une installation minimale, configurez comme indiqué ci-dessous - remplacez searx@$(uname -n) par un nom de votre choix, définissez ultrasecretkey - et/ou modifiez /etc/searx/settings.yml selon vos besoins.</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># paramètres searx</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"/etc/searx"</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">cp</span> <span class="s2">"/usr/local/searx/searx-src/searx/settings.yml"</span> <span class="se">\</span>
|
|||
|
<span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
<span class="c"># minimal setup</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">sed</span> <span class="nt">-i</span> <span class="nt">-e</span> <span class="s2">"s/ultrasecretkey/</span><span class="si">$(</span>openssl rand <span class="nt">-hex</span> 16<span class="si">)</span><span class="s2">/g"</span> <span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">sed</span> <span class="nt">-i</span> <span class="nt">-e</span> <span class="s2">"s/{instance_name}/searx@</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-n</span><span class="si">)</span><span class="s2">/g"</span> <span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifier le fichier de paramétrage <code class="language-plaintext highlighter-rouge">/etc/searx/settings.yml</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>general:
|
|||
|
|
|||
|
instance_name : "OuestSearx" # displayed name
|
|||
|
|
|||
|
ui:
|
|||
|
theme_args :
|
|||
|
oscar_style : logicodev-dark # default style of oscar
|
|||
|
results_on_new_tab: True # Open result links in a new tab by default
|
|||
|
|
|||
|
# supprimer la ligne 'disabled : True' des éléments ci dessous ou positionner 'disabled : False'
|
|||
|
|
|||
|
- name : ddg definitions
|
|||
|
engine : duckduckgo_definitions
|
|||
|
shortcut : ddd
|
|||
|
weight : 2
|
|||
|
|
|||
|
- name : duckduckgo
|
|||
|
engine : duckduckgo
|
|||
|
shortcut : ddg
|
|||
|
|
|||
|
- name : duckduckgo images
|
|||
|
engine : duckduckgo_images
|
|||
|
shortcut : ddi
|
|||
|
timeout: 3.0
|
|||
|
|
|||
|
- name : startpage
|
|||
|
engine : startpage
|
|||
|
shortcut : sp
|
|||
|
timeout : 6.0
|
|||
|
disabled : False
|
|||
|
additional_tests:
|
|||
|
rosebud: *test_rosebud
|
|||
|
|
|||
|
# facultatif
|
|||
|
# ajouter ligne 'disabled : True' sur certains éléments de la liste
|
|||
|
|
|||
|
- name : bing
|
|||
|
engine : bing
|
|||
|
shortcut : bi
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : bing images
|
|||
|
engine : bing_images
|
|||
|
shortcut : bii
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : bing news
|
|||
|
engine : bing_news
|
|||
|
shortcut : bin
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : bing videos
|
|||
|
engine : bing_videos
|
|||
|
shortcut : biv
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : wikidata
|
|||
|
engine : wikidata
|
|||
|
shortcut : wd
|
|||
|
timeout : 3.0
|
|||
|
weight : 2
|
|||
|
tests: *tests_infobox
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : google
|
|||
|
engine : google
|
|||
|
shortcut : go
|
|||
|
use_mobile_ui: false
|
|||
|
# additional_tests:
|
|||
|
# android: *test_android
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : google images
|
|||
|
engine : google_images
|
|||
|
shortcut : goi
|
|||
|
# additional_tests:
|
|||
|
# android: *test_android
|
|||
|
# dali:
|
|||
|
# matrix:
|
|||
|
# query: ['Dali Christ']
|
|||
|
# lang: ['en', 'de', 'fr', 'zh-CN']
|
|||
|
# result_container:
|
|||
|
# - ['one_title_contains', 'Salvador']
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : google news
|
|||
|
engine : google_news
|
|||
|
shortcut : gon
|
|||
|
# additional_tests:
|
|||
|
# android: *test_android
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : google videos
|
|||
|
engine : google_videos
|
|||
|
shortcut : gov
|
|||
|
# additional_tests:
|
|||
|
# android: *test_android
|
|||
|
disabled : True
|
|||
|
|
|||
|
- name : google scholar
|
|||
|
engine : google_scholar
|
|||
|
shortcut : gos
|
|||
|
disabled : True
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="vérifier-en-local">Vérifier en local</h4>
|
|||
|
|
|||
|
<p>Pour vérifier votre configuration searx, vous pouvez activer le débogage et démarrer la webapp. Searx recherche un fichier de configuration dans l’environnement exporté <code class="language-plaintext highlighter-rouge">$SEARX_SETTINGS_PATH</code></p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># dans le second terminal (hmsuser@ouestyan:~$)</span>
|
|||
|
<span class="c"># enable debug ..</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">sed</span> <span class="nt">-i</span> <span class="nt">-e</span> <span class="s2">"s/debug : False/debug : True/g"</span> <span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
|
|||
|
<span class="c"># start webapp</span>
|
|||
|
<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-H</span> <span class="nt">-u</span> searx <span class="nt">-i</span>
|
|||
|
<span class="c"># prompt --> (searx-pyenv) searx@ouestyan:~$ </span>
|
|||
|
<span class="nb">cd</span> /usr/local/searx/searx-src
|
|||
|
<span class="nb">export </span><span class="nv">SEARX_SETTINGS_PATH</span><span class="o">=</span><span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
<span class="c"># lancement de la webapp</span>
|
|||
|
python searx/webapp.py
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ouvrez un navigateur WEB et visitez http:// . Si vous êtes dans un conteneur ou dans un script, testez avec curl dans le second terminal</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl --location --verbose --head --insecure localhost:8888
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* Trying 127.0.0.1:8888...
|
|||
|
* Connected to localhost (127.0.0.1) port 8888 (#0)
|
|||
|
> GET / HTTP/1.1
|
|||
|
> Host: localhost:8888
|
|||
|
> User-Agent: curl/7.74.0
|
|||
|
> Accept: */*
|
|||
|
>
|
|||
|
* Mark bundle as not supporting multiuse
|
|||
|
* HTTP 1.0, assume close after body
|
|||
|
< HTTP/1.0 200 OK
|
|||
|
[...]
|
|||
|
</code></pre></div></div>
|
|||
|
<p>Si tout fonctionne bien, appuyez sur [CTRL-C] pour arrêter la webapp et désactiver l’option de débogage dans settings.yml.</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># disable debug</span>
|
|||
|
<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-H</span> <span class="nb">sed</span> <span class="nt">-i</span> <span class="nt">-e</span> <span class="s2">"s/debug : True/debug : False/g"</span> <span class="s2">"/etc/searx/settings.yml"</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous pouvez maintenant quitter searx en mode bash (entrez deux fois la commande exit). À ce stade, searx n’est pas un daemon , uwsgi le permet.</p>
|
|||
|
|
|||
|
<h4 id="uwsgi">uwsgi</h4>
|
|||
|
|
|||
|
<p>Créer le fichier <code class="language-plaintext highlighter-rouge">/etc/uwsgi/apps-available/searx.ini</code></p>
|
|||
|
|
|||
|
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[uwsgi]</span>
|
|||
|
|
|||
|
<span class="c"># uWSGI core
|
|||
|
# ----------
|
|||
|
#
|
|||
|
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#uwsgi-core
|
|||
|
</span>
|
|||
|
<span class="c"># Who will run the code
|
|||
|
</span><span class="py">uid</span> <span class="p">=</span> <span class="s">searx</span>
|
|||
|
<span class="py">gid</span> <span class="p">=</span> <span class="s">searx</span>
|
|||
|
|
|||
|
<span class="c"># set (python) default encoding UTF-8
|
|||
|
</span><span class="py">env</span> <span class="p">=</span> <span class="s">LANG=C.UTF-8</span>
|
|||
|
<span class="py">env</span> <span class="p">=</span> <span class="s">LANGUAGE=C.UTF-8</span>
|
|||
|
<span class="py">env</span> <span class="p">=</span> <span class="s">LC_ALL=C.UTF-8</span>
|
|||
|
|
|||
|
<span class="c"># chdir to specified directory before apps loading
|
|||
|
</span><span class="py">chdir</span> <span class="p">=</span> <span class="s">/usr/local/searx/searx-src/searx</span>
|
|||
|
|
|||
|
<span class="c"># searx configuration (settings.yml)
|
|||
|
</span><span class="py">env</span> <span class="p">=</span> <span class="s">SEARX_SETTINGS_PATH=/etc/searx/settings.yml</span>
|
|||
|
|
|||
|
<span class="c"># disable logging for privacy
|
|||
|
</span><span class="py">disable-logging</span> <span class="p">=</span> <span class="s">true</span>
|
|||
|
|
|||
|
<span class="c"># The right granted on the created socket
|
|||
|
</span><span class="py">chmod-socket</span> <span class="p">=</span> <span class="s">666</span>
|
|||
|
|
|||
|
<span class="c"># Plugin to use and interpreter config
|
|||
|
</span><span class="py">single-interpreter</span> <span class="p">=</span> <span class="s">true</span>
|
|||
|
|
|||
|
<span class="c"># enable master process
|
|||
|
</span><span class="py">master</span> <span class="p">=</span> <span class="s">true</span>
|
|||
|
|
|||
|
<span class="c"># load apps in each worker instead of the master
|
|||
|
</span><span class="py">lazy-apps</span> <span class="p">=</span> <span class="s">true</span>
|
|||
|
|
|||
|
<span class="c"># load uWSGI plugins
|
|||
|
</span><span class="py">plugin</span> <span class="p">=</span> <span class="s">python3,http</span>
|
|||
|
|
|||
|
<span class="c"># By default the Python plugin does not initialize the GIL. This means your
|
|||
|
# app-generated threads will not run. If you need threads, remember to enable
|
|||
|
# them with enable-threads. Running uWSGI in multithreading mode (with the
|
|||
|
# threads options) will automatically enable threading support. This *strange*
|
|||
|
# default behaviour is for performance reasons.
|
|||
|
</span><span class="py">enable-threads</span> <span class="p">=</span> <span class="s">true</span>
|
|||
|
|
|||
|
|
|||
|
<span class="c"># plugin: python
|
|||
|
# --------------
|
|||
|
#
|
|||
|
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-python
|
|||
|
</span>
|
|||
|
<span class="c"># load a WSGI module
|
|||
|
</span><span class="py">module</span> <span class="p">=</span> <span class="s">searx.webapp</span>
|
|||
|
|
|||
|
<span class="c"># set PYTHONHOME/virtualenv
|
|||
|
</span><span class="py">virtualenv</span> <span class="p">=</span> <span class="s">/usr/local/searx/searx-pyenv</span>
|
|||
|
|
|||
|
<span class="c"># add directory (or glob) to pythonpath
|
|||
|
</span><span class="py">pythonpath</span> <span class="p">=</span> <span class="s">/usr/local/searx/searx-src</span>
|
|||
|
|
|||
|
|
|||
|
<span class="c"># speak to upstream
|
|||
|
# -----------------
|
|||
|
#
|
|||
|
# Activate the 'http' configuration for filtron or activate the 'socket'
|
|||
|
# configuration if you setup your HTTP server to use uWSGI protocol via sockets.
|
|||
|
</span>
|
|||
|
<span class="c"># using IP:
|
|||
|
#
|
|||
|
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-http
|
|||
|
# Native HTTP support: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
|
|||
|
</span>
|
|||
|
<span class="py">http</span> <span class="p">=</span> <span class="s">127.0.0.1:8888</span>
|
|||
|
|
|||
|
<span class="c"># using unix-sockets:
|
|||
|
#
|
|||
|
# On some distributions you need to create the app folder for the sockets::
|
|||
|
#
|
|||
|
# mkdir -p /run/uwsgi/app/searx
|
|||
|
# chown -R searx:searx /run/uwsgi/app/searx
|
|||
|
#
|
|||
|
# socket = /run/uwsgi/app/searx/socket
|
|||
|
</span>
|
|||
|
<span class="c"># Cache
|
|||
|
</span><span class="py">cache2</span> <span class="p">=</span> <span class="s">name=searxcache,items=2000,blocks=2000,blocksize=4096,bitmap=1</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Activer le fichier ini</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -H ln -s /etc/uwsgi/apps-available/searx.ini /etc/uwsgi/apps-enabled/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Démarrer le service</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -H service uwsgi start searx
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Tester localement pour vérifier : <code class="language-plaintext highlighter-rouge">curl --location --verbose --head --insecure localhost:8888</code></p>
|
|||
|
|
|||
|
<p>Tester à partir d’un poste distant<br />
|
|||
|
Exécuter sur un poste distant</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 9500:localhost:8888 hmsuser@45.145.166.178 -p 55178 -i /home/yann/.ssh/server32771
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Sur le même poste , ouvrir le navigateur avec un lien <a href="http://localhost:9500">http://localhost:9500</a></p>
|
|||
|
|
|||
|
<p><img src="/images/searx.ouestyan.fr.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p class="info">Après toute modification du fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/searx/settings.yml</code>, il faut redémarrer le service <strong>uwsgi</strong> par la commande <code class="language-plaintext highlighter-rouge">sudo systemctl restart uwsgi</code></p>
|
|||
|
|
|||
|
<h4 id="nginx-proxy-searx">nginx proxy searx</h4>
|
|||
|
|
|||
|
<p>Le fichier de configuration nginx <code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/searx.ouestyan.fr.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
|
|||
|
listen 80;
|
|||
|
listen [::]:80;
|
|||
|
server_name searx.ouestyan.fr;
|
|||
|
return 301 https://$host$request_uri;
|
|||
|
}
|
|||
|
server {
|
|||
|
listen 443 ssl http2;
|
|||
|
listen [::]:443 ssl http2;
|
|||
|
server_name searx.ouestyan.fr;
|
|||
|
|
|||
|
include /etc/nginx/conf.d/security.conf.inc;
|
|||
|
|
|||
|
location / {
|
|||
|
proxy_pass http://127.0.0.1:8888;
|
|||
|
|
|||
|
proxy_set_header Host $host;
|
|||
|
proxy_set_header Connection $http_connection;
|
|||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|||
|
proxy_set_header X-Scheme $scheme;
|
|||
|
proxy_buffering off;
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Valider et recharger ginx</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
|
|||
|
sudo systemctl reload nginx
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lien <a href="https://searx.ouestyan.fr">https://searx.ouestyan.fr</a></p>
|
|||
|
|
|||
|
<h3 id="nextcloud">Nextcloud</h3>
|
|||
|
|
|||
|
<p><a href="/2022/10/19/Nextcloud_Hub_3_(v25+).html">Nextcloud Hub 3 (v25+)</a></p>
|
|||
|
|
|||
|
<h4 id="transmission-torrent">Transmission Torrent</h4>
|
|||
|
|
|||
|
<p><a href="/2020/11/07/debian-transmission-daemon.html">Installation Transmission Torrent</a></p>
|
|||
|
|
|||
|
<h4 id="installer-transmission-daemon">Installer transmission-daemon</h4>
|
|||
|
|
|||
|
<p>Liste des commandes</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>transmission-cli transmission-common transmission-daemon
|
|||
|
<span class="nb">sudo </span>systemctl stop transmission-daemon
|
|||
|
<span class="nb">sudo </span>usermod <span class="nt">-a</span> <span class="nt">-G</span> debian-transmission <span class="nv">$USER</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="proxy-nginx">Proxy nginx</h4>
|
|||
|
|
|||
|
<p>Reverse proxy nginx <code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/transmission.ouestyan.fr.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upstream transmission {
|
|||
|
server 127.0.0.1:9091;
|
|||
|
}
|
|||
|
|
|||
|
server {
|
|||
|
listen 80;
|
|||
|
listen [::]:80;
|
|||
|
server_name transmission.ouestyan.fr;
|
|||
|
return 301 https://$host$request_uri;
|
|||
|
}
|
|||
|
server {
|
|||
|
listen 443 ssl http2;
|
|||
|
listen [::]:443 ssl http2;
|
|||
|
server_name transmission.ouestyan.fr;
|
|||
|
|
|||
|
include /etc/nginx/conf.d/security.conf.inc;
|
|||
|
|
|||
|
access_log /var/log/nginx/trans-access.log;
|
|||
|
error_log /var/log/nginx/trans-error.log;
|
|||
|
|
|||
|
location / {
|
|||
|
return 301 https://$server_name/transmission/;
|
|||
|
location ^~ /transmission {
|
|||
|
proxy_set_header X-Real-IP $remote_addr;
|
|||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|||
|
proxy_set_header Host $http_host;
|
|||
|
proxy_set_header Connection "";
|
|||
|
proxy_pass_header X-Transmission-Session-Id;
|
|||
|
|
|||
|
location /transmission/rpc {
|
|||
|
proxy_pass http://transmission;
|
|||
|
}
|
|||
|
location /transmission/web/ {
|
|||
|
proxy_pass http://transmission;
|
|||
|
}
|
|||
|
location /transmission/upload {
|
|||
|
proxy_pass http://transmission;
|
|||
|
}
|
|||
|
location /transmission/web/style/ {
|
|||
|
alias /usr/share/transmission/web/style/;
|
|||
|
}
|
|||
|
location /transmission/web/javascript/ {
|
|||
|
alias /usr/share/transmission/web/javascript/;
|
|||
|
}
|
|||
|
location /transmission/web/images/ {
|
|||
|
alias /usr/share/transmission/web/images/;
|
|||
|
}
|
|||
|
location /transmission/ {
|
|||
|
return 301 http://$server_name/transmission/web;
|
|||
|
}
|
|||
|
location /transmission/downloads/ {
|
|||
|
alias /srv/transmission/completed/;
|
|||
|
charset UTF-8;
|
|||
|
autoindex on;
|
|||
|
autoindex_exact_size off;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="dossiers-et-configuration">Dossiers et configuration</h4>
|
|||
|
|
|||
|
<p>Créer les différents dossiers pour le suivi des téléchargements</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /srv/transmission/<span class="o">{</span>watched,completed,progress<span class="o">}</span>
|
|||
|
<span class="c"># les droits</span>
|
|||
|
<span class="nb">chown </span>debian-transmission:www-data <span class="nt">-R</span> /srv/transmission/completed
|
|||
|
<span class="nb">chown </span>debian-transmission:debian-transmission <span class="nt">-R</span> /srv/transmission/<span class="o">{</span>watched,progress<span class="o">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifier le fichier <code class="language-plaintext highlighter-rouge">/var/lib/transmission-daemon/info/settings.json</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"download-dir": "/srv/transmission/completed",
|
|||
|
"incomplete-dir": "/srv/transmission/progress",
|
|||
|
|
|||
|
"rpc-authentication-required": true, // Activation de l’auth par mot de passe
|
|||
|
"rpc-url": "/",
|
|||
|
"rpc-bind-address": "0.0.0.0", // 127.0.0.1 pour écouter en local
|
|||
|
"rpc-enabled": true, // Activation de l’interface web
|
|||
|
"rpc-password": "MOT_DE_PASSE", // Tapez votre mot de passe, il sera salé au reload
|
|||
|
"rpc-port": 9091, // Port d’écoute
|
|||
|
"rpc-url": "/transmission/", // Correspond à l’URL d’accès
|
|||
|
"rpc-username": "UTILISATEUR", // Nom d’utilisateur pour l’auth
|
|||
|
"rpc-host-whitelist": "",
|
|||
|
"rpc-host-whitelist-enabled": false,
|
|||
|
"rpc-whitelist": "127.0.0.1", // IPs à whitelist
|
|||
|
"rpc-whitelist-enabled": true, // Activation de la whitelist
|
|||
|
|
|||
|
# en fin de fichier
|
|||
|
"utp-enabled": true,
|
|||
|
"watch-dir": "/srv/transmission/watched",
|
|||
|
"watch-dir-enabled": true
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>le fichier json complet</p>
|
|||
|
|
|||
|
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-down"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-time-begin"</span><span class="p">:</span><span class="w"> </span><span class="mi">540</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-time-day"</span><span class="p">:</span><span class="w"> </span><span class="mi">127</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-time-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-time-end"</span><span class="p">:</span><span class="w"> </span><span class="mi">1020</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"alt-speed-up"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"bind-address-ipv4"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.0.0"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"bind-address-ipv6"</span><span class="p">:</span><span class="w"> </span><span class="s2">"::"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"blocklist-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"blocklist-url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.example.com/blocklist"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"cache-size-mb"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"dht-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"download-dir"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/srv/transmission/completed"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"download-queue-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"download-queue-size"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"encryption"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"idle-seeding-limit"</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"idle-seeding-limit-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"incomplete-dir"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/srv/transmission/progress"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"incomplete-dir-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"lpd-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"message-level"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-congestion-algorithm"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-id-ttl-hours"</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-limit-global"</span><span class="p">:</span><span class="w"> </span><span class="mi">200</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-limit-per-torrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-port"</span><span class="p">:</span><span class="w"> </span><span class="mi">51413</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-port-random-high"</span><span class="p">:</span><span class="w"> </span><span class="mi">65535</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-port-random-low"</span><span class="p">:</span><span class="w"> </span><span class="mi">49152</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-port-random-on-start"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"peer-socket-tos"</span><span class="p">:</span><span class="w"> </span><span class="s2">"default"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"pex-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"port-forwarding-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"preallocation"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"prefetch-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"queue-stalled-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"queue-stalled-minutes"</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"ratio-limit"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"ratio-limit-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rename-partial-files"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-authentication-required"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-bind-address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-host-whitelist"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-host-whitelist-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{971fed709da0e448d0dec7ed65fe2600ce3ce916OvFJeoc6"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-port"</span><span class="p">:</span><span class="w"> </span><span class="mi">9091</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/transmission/"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yannick"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-whitelist"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1,::1"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"rpc-whitelist-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"scrape-paused-torrents-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"script-torrent-done-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"script-torrent-done-filename"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"seed-queue-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"seed-queue-size"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"speed-limit-down"</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"speed-limit-down-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"speed-limit-up"</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"speed-limit-up-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"start-added-torrents"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"trash-original-torrent-files"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"umask"</span><span class="p">:</span><span class="w"> </span><span class="mi">18</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"upload-slots-per-torrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">14</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"utp-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"watch-dir"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/srv/transmission/watched"</span><span class="p">,</span><span class="w">
|
|||
|
</span><span class="nl">"watch-dir-enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
|
|||
|
</span><span class="p">}</span><span class="w">
|
|||
|
</span></code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour éviter l’erreur “ transmission UDP Failed to set receive buffer …” , en mode su</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-s</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">"net.core.rmem_max = 4194304"</span> <span class="o">>></span> /etc/sysctl.conf
|
|||
|
<span class="nb">echo</span> <span class="s2">"net.core.wmem_max = 1048576"</span> <span class="o">>></span> /etc/sysctl.conf
|
|||
|
sysctl <span class="nt">-p</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer le service</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start transmission-daemon
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>A chaque modification (en mode su)</p>
|
|||
|
|
|||
|
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl stop transmission-daemon
|
|||
|
<span class="nb">rm</span> /var/lib/transmission-daemon/.config/transmission-daemon/settings.json
|
|||
|
<span class="nb">rm</span> /etc/transmission-daemon/settings.json
|
|||
|
<span class="c"># créer</span>
|
|||
|
nano /var/lib/transmission-daemon/info/settings.json
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="transmissionouestyanfr">transmission.ouestyan.fr</h4>
|
|||
|
|
|||
|
<p>Connexion sur le lien <a href="https://transmission.ouestyan.fr">https://transmission.ouestyan.fr</a><br />
|
|||
|
<img src="/images/transmission.ouestyan.fr01.png" alt="" /><br />
|
|||
|
Saisir “yannick” et son mot de passe</p>
|
|||
|
|
|||
|
<h3 id="test-de-sécurité">Test de sécurité</h3>
|
|||
|
|
|||
|
<p><a href="https://www.ssllabs.com/ssltest/index.html">Analyse SSL</a> contre le site Web pour trouver le score et la vulnérabilité essentielle.<br />
|
|||
|
<img src="/images/ssllabs-ouestyan.fr.png" alt="" /><br />
|
|||
|
<a href="https://www.ssllabs.com/ssltest/analyze.html?d=ouestyan.fr">https://www.ssllabs.com/ssltest/analyze.html?d=ouestyan.fr</a></p>
|
|||
|
|
|||
|
<p>Les entêtes <a href="https://securityheaders.com/">https://securityheaders.com/</a> <br />
|
|||
|
<img src="/images/securityheaders-ouestyan.fr.png" alt="" /><br />
|
|||
|
ouestyan.fr</p>
|
|||
|
|
|||
|
<p><img src="/images/securityheaders-cloud.ouestyan.fr.png" alt="" />
|
|||
|
cloud.ouestyan.fr</p>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2022-07-21T00: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>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2022/06/24/Yunohost_Debian_Bullseye_image_de_nuage_Qcow2.html">Qemu/KVM - Virtuel Yunohost ouestyan.xyz (debian 11 image cloud Qcow2)</a></div><div class="next"><span>SUIVANT</span><a href="/2022/07/21/Matrix_Synapse_Home_Server.html">Matrix Synapse Home Server</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} {title}</a> (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>
|
|||
|
|