yannstatic/static/2020/09/24/Serveur-Debian10-Carte-ASRock-QC5000M.html

3847 lines
264 KiB
HTML
Raw Permalink Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Serveur Debian10 - YannStatic</title>
<meta name="description" content="ASRock QC5000M Quad-Core APU">
<link rel="canonical" href="https://static.rnmkcy.eu/2020/09/24/Serveur-Debian10-Carte-ASRock-QC5000M.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Serveur Debian10</h1></header></div><meta itemprop="headline" content="Serveur Debian10"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=debian">debian</a>
2024-10-31 20:18:37 +01:00
</li><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=serveur">serveur</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">24&nbsp;sept.&nbsp;2020</span></li></ul></div><meta itemprop="datePublished" content="2020-09-24T00:00:00+02:00">
<meta itemprop="keywords" content="debian,serveur"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h2 id="asrock-qc5000m-quad-core-apu">ASRock QC5000M Quad-Core APU</h2>
<p><a href="https://static.rnmkcy.eu/files/QC5000M.pdf">ASRock QC5000M (pdf)</a></p>
<p><img src="/images/asrock-qc500m.png" alt="ASRock QC5000M" title="ASRock QC5000M" /></p>
<ul>
<li>Platform
<ul>
<li>Micro ATX Form Factor</li>
<li>Solid Capacitor design</li>
<li>High Density Glass Fabric PCB</li>
</ul>
</li>
<li>CPU
<ul>
<li>AMD FT3 Kabini A4-5050/5000 Quad-Core APU</li>
</ul>
</li>
<li>Memory
<ul>
<li>2 x DDR3 DIMM Slots</li>
<li>Supports DDR3 1600/1333/1066 non-ECC, un-buffered memory</li>
<li>Max. capacity of system memory: 32GB (see CAUTION1)</li>
</ul>
</li>
<li>Expansion Slot
<ul>
<li>1 x PCI Express 2.0 x16 Slot (PCIE2: x4 mode)</li>
<li>2 x PCI Express 2.0 x1 Slot</li>
</ul>
</li>
<li>Graphics
<ul>
<li>Integrated AMD RadeonTM HD 8330 Graphics</li>
<li>DirectX 11.1, Pixel Shader 5.0</li>
<li>Max. shared memory 2GB</li>
<li>Dual graphics output: support D-Sub and HDMI ports by independent display controllers (see CAUTION2)</li>
<li>Supports HDMI with max. resolution up to 4K × 2K (4096x2160) @ 24Hz or 4K × 2K (3840x2160) @ 30Hz</li>
<li>Supports D-Sub with max. resolution up to 2048x1536 @ 60Hz</li>
<li>Supports Auto Lip Sync, Deep Color (12bpc), xvYCC and HBR (High Bit Rate Audio) with HDMI Port (Compliant HDMI monitor is required)</li>
<li>Supports HDCP with HDMI Port</li>
<li>Supports Full HD 1080p Blu-ray (BD) playback with HDMI Port</li>
</ul>
</li>
<li>Audio
<ul>
<li>7.1 CH HD Audio (Realtek ALC887 Audio Codec) * To configure 7.1 CH HD Audio, it is required to use an HD front panel audio module and enable the multi-channel audio feature through the audio driver.</li>
<li>Supports Surge Protection (ASRock Full Spike Protection)</li>
<li>ELNA Audio Caps</li>
</ul>
</li>
<li>LAN
<ul>
<li>PCIE x1 Gigabit LAN 10/100/1000 Mb/s</li>
<li>Rea ltek RTL 8111GR</li>
<li>S u p p o r t s Wa k e - O n -WA N</li>
<li>Suppor t s Wa ke- On-L A N</li>
<li>Supports Lightning/ESD Protection (ASRock Full Spike Protection)</li>
<li>Supports LAN Cable Detection</li>
<li>Supports Energy Efficient Ethernet 802.3az</li>
<li>Supports PXE</li>
</ul>
</li>
<li>Rear Panel I/O
<ul>
<li>1 x PS/2 Mouse/Keyboard Port</li>
<li>1 x Serial Port: COM1</li>
<li>1 x D-Sub Port</li>
<li>1 x HDMI Port</li>
<li>4 x USB 2.0 Ports (Supports ESD Protection (ASRock Full Spike Protection))</li>
<li>2 x USB 3.0 Ports (Supports ESD Protection (ASRock Full Spike Protection))</li>
<li>1 x RJ-45 LAN Port with LED (ACT/LINK LED and SPEED LED)</li>
<li>HD Audio Jacks: Line in / Front Speaker / Microphone</li>
</ul>
</li>
<li>Storage
<ul>
<li>2 x SATA3 6.0 Gb/s Connectors, support NCQ, AHCI and Hot Plug</li>
</ul>
</li>
<li>Connector
<ul>
<li>1 x TPM Header</li>
<li>1 x CPU Fan Connector (3-pin)</li>
<li>2 x Chassis Fan Connectors (1 x 4-pin, 1 x 3-pin)</li>
<li>1 x 24 pin ATX Power Connector</li>
<li>1 x Front Panel Audio Connector</li>
<li>2 x USB 2.0 Headers (Support 4 USB 2.0 ports) (Supports ESD Protection (ASRock Full Spike Protection))</li>
</ul>
</li>
<li>BIOS Feature
<ul>
<li>32Mb AMI UEFI Legal BIOS with multilingual GUI support</li>
<li>Supports “Plug and Play”</li>
<li>ACPI 1.1 compliance wake up events</li>
<li>SMBIOS 2.3.1 support</li>
<li>DRAM Voltage multi-adjustment</li>
</ul>
</li>
<li>HardwareMonitor
<ul>
<li>CPU/Chassis temperature sensing</li>
<li>CPU/Chassis Fan Tachometer</li>
<li>CPU/Chassis Quiet Fan</li>
<li>CPU/Chassis Fan multi-speed control</li>
<li>Voltage monitoring: +12V, +5V, +3.3V, Vcore</li>
</ul>
</li>
<li>OS
<ul>
<li>Microsoft® Windows® 10 64-bit / 8.1 32-bit / 8.1 64-bit / 8 32-bit / 8 64-bit / 7 32-bit / 7 64-bit / XP 32-bit / XP 64-bit*</li>
<li>USB 3.0 is not supported by Windows® XP* For the updated Windows® 10 driver, please visit ASRocks website for details: http://www.asrock.com</li>
</ul>
</li>
<li>Certifica-tions
<ul>
<li>FCC, CE, WHQL</li>
<li>ErP/EuP ready (ErP/EuP ready power supply is required)</li>
</ul>
</li>
</ul>
<h2 id="boot-sur-usb-partedmagic">Boot sur USB “partedmagic”</h2>
<p><img src="/images/debian-buster-logo1.png" alt="" width="200" /></p>
<h3 id="partitionnement-du-disque">Partitionnement du disque</h3>
<ul>
<li>2MB, type EF02 (BIOS partition). Utilisé par GRUB2/BIOS-GPT. (/dev/sda1)</li>
<li>512MB, type 8300 (Linux). Pour le boot linux /boot (/dev/sda2)</li>
<li>4GB, type 8200 (swap). Partition swap (en dehors de lvm). (/dev/sda3)</li>
<li>Espace restant, type 8E00 (LVM). Pour le root / + /home et autres. (/dev/sda4).</li>
</ul>
<p>Partitionnement du reste du disque SSD 120G GPT + LVM</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdisk /dev/sda
</code></pre></div></div>
<p>On passe en mode expert : x<br />
On efface tout : z<br />
On relance gdisk</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdisk /dev/sda
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GPT fdisk (gdisk) version 0.8.6
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries.
Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-937703054, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-937703054, default = 937703054) or {+-}size{KMGTP}: +2M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-937703054, default = 6144) or {+-}size{KMGTP}:
Last sector (6144-937703054, default = 937703054) or {+-}size{KMGTP}: +512M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
Command (? for help): n
Partition number (3-128, default 3):
First sector (34-937703054, default = 1054720) or {+-}size{KMGTP}:
Last sector (1054720-937703054, default = 937703054) or {+-}size{KMGTP}: +4G
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8200
Changed type of partition to 'Linux swap'
Command (? for help): n
Partition number (4-128, default 4):
First sector (34-937703054, default = 9443328) or {+-}size{KMGTP}:
Last sector (9443328-937703054, default = 937703054) or {+-}size{KMGTP}:
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to 'Linux LVM'
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sda.
The operation has completed successfully.
</code></pre></div></div>
<p>CT480M</p>
<h3 id="installation-debian-10">Installation debian 10</h3>
<ul>
<li>Installation effectuée à partir dune clé USB bootable , fichier debian+firmware ISO : <strong>firmware-10.4.0-amd64-netinst.iso</strong></li>
<li>Choix “partitionnement manuel”</li>
</ul>
<p><img src="/images/debian-buster-logo.png" alt="Debian 10" width="100" /></p>
<ul>
<li>Serveur virtuel 64 bits VirtualBox : <strong>Debian Buster</strong></li>
<li>machine : <strong>srvct</strong></li>
<li>domaine :</li>
<li>root : <strong>ytreu49</strong></li>
<li>Utilisateur : <strong>ctuser</strong></li>
<li>Mot de passe : <strong>ctuser49</strong></li>
<li>Adresse IP : <strong>192.168.0.45</strong></li>
<li>Accès
<ul>
<li>SSH : <strong>ssh bust@192.168.0.45</strong></li>
<li>
<s>SSH + clé : **ssh -i ~/.ssh/vbox-vmbust-ed25519 bust@192.168.0.49** (facultatif)</s>
</li>
<li>
<s>Transfert de fichier : **scp -P 55022 -i ~/.ssh/vbox-vmbust-ed25519 fichiera fichierb bust@192.168.0.49:/home/bust** (facultatif)</s>
</li>
</ul>
</li>
</ul>
<p>Partitionnement</p>
<table>
<thead>
<tr>
<th>Partition</th>
<th>Taille</th>
<th>_</th>
<th>Type</th>
<th>Commentaire</th>
<th>_</th>
</tr>
</thead>
<tbody>
<tr>
<td>n°1</td>
<td>2.1 MB</td>
<td>K</td>
<td>biosgrub Bios</td>
<td>BIOS boot partition</td>
<td> </td>
</tr>
<tr>
<td>n°2</td>
<td>536.9 MB</td>
<td> </td>
<td>ext2</td>
<td>Linux filesys</td>
<td>/boot</td>
</tr>
<tr>
<td>n°3</td>
<td>4.3 GB</td>
<td>F</td>
<td>swap</td>
<td>Linux swap</td>
<td>swap</td>
</tr>
</tbody>
</table>
<p>Créer un volume de groupe vg-ct480 sur /dev/sda4<br />
Créer un volume logique lv-root de 35Go<br />
Créer la partition “root” avec le volume logique “lv-root”</p>
<p>Sélection des logiciels</p>
<ul>
<li>serveur SSH</li>
<li>utilitaires usuels du système</li>
</ul>
<p>Oter la clé après installation</p>
<h3 id="connexion-ssh">Connexion SSH</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh ctuser@192.168.0.45
</code></pre></div></div>
<p>Passer en root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su
</code></pre></div></div>
<p>Mise à jour</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update &amp;&amp; apt upgrade -y
</code></pre></div></div>
<p>Installer les outils et sudo</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install rsync curl tmux jq figlet tree git -y
</code></pre></div></div>
<p>Installer sudo</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install sudo
</code></pre></div></div>
<p>Visudo pour les accès root via utilisateur bust</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "ctuser ALL=(ALL) NOPASSWD: ALL" &gt;&gt; /etc/sudoers
</code></pre></div></div>
<h3 id="historique-de-la-ligne-de-commande">Historique de la ligne de commande</h3>
<p>Ajoutez la recherche dhistorique de la ligne de commande au terminal.
Tapez un début de commande précédent, puis utilisez shift + up (flèche haut) pour rechercher lhistorique filtré avec le début de la commande.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Global, tout utilisateur
echo '"\e[1;2A": history-search-backward' | sudo tee -a /etc/inputrc
echo '"\e[1;2B": history-search-forward' | sudo tee -a /etc/inputrc
</code></pre></div></div>
<h3 id="openssh-clé-et-script">OpenSSH, clé et script</h3>
<p><img src="/images/ssh_logo1.png" alt="OpenSSH" width="100" /></p>
<p><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) nommé <strong>srvct-ed25519</strong> pour une liaison SSH avec le serveur KVM.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/srvct-ed25519
</code></pre></div></div>
<p>Envoyer la clé publique sur le serveur KVM</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scp ~/.ssh/srvct-ed25519.pub ctuser@192.168.0.45:/home/ctuser/
</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 ctuser@192.168.0.45
</code></pre></div></div>
<p>Copier le contenu de la clé publique dans /home/$USER/.ssh/authorized_keys</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
</code></pre></div></div>
<p>Sur le KVM ,créer un dossier .ssh</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> .ssh
<span class="nb">cat</span> <span class="nv">$HOME</span>/srvct-ed25519.pub <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.ssh/authorized_keys
</code></pre></div></div>
<p>et donner les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 600 $HOME/.ssh/authorized_keys
</code></pre></div></div>
<p>effacer le fichier de la clé</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm $HOME/srvct-ed25519.pub
</code></pre></div></div>
<p>Modifier la configuration serveur SSH</p>
<p>Port = 55035 # changement numéro port , facultatif<br />
PasswordAuthentication no # Utilise la clé comme authentification</p>
<p>Exécuter les commande ci-dessous</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sed -i 's/#Port 22/Port 55035/g' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
</code></pre></div></div>
<p>Modifier</p>
<p><u>session SSH ne se termine pas correctement lors d'un "reboot" à distance</u><br />
Si vous tentez de <strong>redémarrer/éteindre</strong> une machine distance par <strong>ssh</strong>, vous pourriez constater que votre session ne se termine pas correctement, vous laissant avec un terminal inactif jusquà lexpiration dun long délai dinactivité. Il existe un bogue 751636 à ce sujet. Pour linstant, la solution de contournement à ce problème est dinstaller :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install libpam-systemd # Installé par défaut sur debian buster
</code></pre></div></div>
<p>cela terminera la session ssh avant que le réseau ne tombe.<br />
Veuillez noter quil est nécessaire que PAM soit activé dans sshd.</p>
<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 -p 55035 -i ~/.ssh/srvct-ed25519 ctuser@192.168.0.45
</code></pre></div></div>
<h3 id="hostname">Hostname</h3>
<p>Vérifier le nom</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostnamectl
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Static hostname: srvct
Icon name: computer-desktop
Chassis: desktop
Machine ID: b65c705c91e04653ad975d9c29f50ed0
Boot ID: 10aa2c2367a845a3acddb3d72ab7df3f
Operating System: Debian GNU/Linux 10 (buster)
Kernel: Linux 4.19.0-10-amd64
Architecture: x86-64
</code></pre></div></div>
<h3 id="journalctl">Journalctl</h3>
<p>Ajout utilisateur courant au groupe systemd-journal et adm</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a $USER systemd-journal
sudo gpasswd -a $USER adm
</code></pre></div></div>
<p>Lignes non tronquées ,ajouter au fichier <strong>~/.bashrc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "export SYSTEMD_LESS=FRXMK journalctl" &gt;&gt; /home/$USER/.bashrc
</code></pre></div></div>
<p>Prise en compte après déconnexion/reconnexion</p>
<hr />
<p>Logo ascii</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/motd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
___ _ _ __ ____ __ ___
(_-&lt;| '_|\ V /\ \ // _ \
/__/|_| \_/ /_\_\\___/
__ __ ___ _ _ (_) ___ ___ __ __ _ _ ___
\ \ // _ \| || || ||_ // -_) _ \ \ /| || ||_ /
/_\_\\___/ \_, ||_|/__|\___|(_)/_\_\ \_, |/__|
|__/ |__/
</code></pre></div></div>
<h2 id="nfs-serveur">NFS serveur</h2>
<p><img src="/images/nfs-ufw.png" alt="" /><br />
<em>NFS (pour Network File System, système de fichiers en réseau) est un protocole qui permet à un ordinateur daccéder à des fichiers via un réseau.</em></p>
<h3 id="installation-nfs">Installation NFS</h3>
<p><img src="/images/nfs-new-logo.png" alt="" width="60" /></p>
<p>on passe en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>Installation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install nfs-kernel-server
</code></pre></div></div>
<p>Vérification serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rpcinfo -p | grep nfs
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100003 3 udp 2049 nfs
</code></pre></div></div>
<p>Vérifier que le système supporte effectivement NFS</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /proc/filesystems | grep nfs
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nodev nfsd
</code></pre></div></div>
<p>Si la commande précédente ne renvoie rien, il se peut que le module NFS ne soit pas chargé, auquel cas, il faut le charger <code class="language-plaintext highlighter-rouge">modprobe nfs</code><br />
Enfin, vérifions que portmap attend les instructions sur le port 111</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rpcinfo -p | grep portmap
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper
</code></pre></div></div>
<h3 id="configuration-du-partage">Configuration du partage</h3>
<p>Passage en su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>indiquer au serveur les répertoires qui seront partagés, les machines qui y auront accès et les conditions de ce partage.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/exports
</code></pre></div></div>
<p>Ajouter en fin de fichier <strong>/etc/exports</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/srv/data 192.168.0.0/24(rw,sync,no_subtree_check,no_root_squash)
/srv/nfs 192.168.0.0/24(rw,sync,no_subtree_check,no_root_squash)
</code></pre></div></div>
<p>Exporter</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>exportfs -ar
</code></pre></div></div>
<h3 id="sécurisation-nfs">Sécurisation NFS</h3>
<p>Passage en su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>Le protocole RPC na pas la réputation dêtre bien sécurisé, mais la version 4 de NFS entend corriger ce problème, elle est donc à privilégier. Il est déconseillé deffectuer un partage NFS via internet, ou bien dans ce cas, opter pour un tunnel crypté.</p>
<ul>
<li>Sassurer que les partages sont réservés à certaines IP dans /etc/exports</li>
<li>Sappuyer sur rpcbind (/etc/hosts.deny et /etc/hosts.allow) pour sécuriser laccès au serveur NFS</li>
<li>Configurer convenablement iptables</li>
</ul>
<p><strong>hosts.deny , hosts.allow</strong><br />
Tout le monde est interdit, puis le LAN est autorisé:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "rpcbind mountd nfsd statd lockd rquotad : ALL" &gt;&gt; /etc/hosts.deny
echo "rpcbind mountd nfsd statd lockd rquotad: 192.168.0." &gt;&gt; /etc/hosts.allow
</code></pre></div></div>
<p><strong>iptables (NFS)</strong><br />
Par défaut, les différents services NFS (lockd, statd, mountd, etc.) demandent des assignations de ports aléatoires à partir du portmapper (portmap/rpcbind), ce qui signifie que la plupart des administrateurs doivent ouvrir une gamme de ports dans leur base de règles de pare-feu pour que NFS fonctionne.</p>
<p>Il va donc falloir fixer les ports de ces services afin de créer les règles iptables.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo 'STATDOPTS="--port 32765 --outgoing-port 32766"' &gt;&gt; /etc/default/nfs-common
echo 'RPCMOUNTDOPTS="-p 32767"' &gt;&gt; /etc/default/nfs-kernel-server
echo 'RPCRQUOTADOPTS="-p 32769"' &gt;&gt; /etc/default/quota
</code></pre></div></div>
<p>Relance sysctl</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl --system
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/protect-links.conf ...
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.conf ...
</code></pre></div></div>
<p>Relancer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart nfs-kernel-server
</code></pre></div></div>
<p>Voici les règles à fixer dans le parefeu</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -A INPUT -s 192.168.0.0/24 -p tcp -m multiport --ports 111,2049,32764:32769 -j ACCEPT -m comment --comment "NFS Server"
iptables -A INPUT -s 192.168.0.0/24 -p udp -m multiport --ports 111,2049,32764:32769 -j ACCEPT -m comment --comment "NFS Server"
</code></pre></div></div>
<h3 id="configurer-le-partage-nfs-avec-setgid">Configurer le partage NFS avec SetGID</h3>
<p>Maintenant que le serveur NFS est configuré avec le point de montage NFS de base /srv/nfs, nous devons configurer SetGID dans ce répertoire, comme indiqué ci-dessous.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod 2770 /srv/nfs
</code></pre></div></div>
<p>Cela a également défini les autorisations 770 sur le répertoire, de sorte que lutilisateur racine et le groupe défini disposent dautorisations complètes. Le 2 permet setgid.</p>
<p>Ensuite, nous créons un groupe appelé partage et modifions le répertoire /srv/nfs afin que le propriétaire du groupe soit ce groupe partage.<br />
Nous spécifions également manuellement le GID qui sera utilisé pour le groupe en tant que 9999; il doit sagir dun <u>numéro libre sur votre client et votre serveur</u>.</p>
<p>Exécuter <code class="language-plaintext highlighter-rouge">groupadd</code> sur le client et sur le serveur, et ajouter un utilisateur à ce groupe.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo groupadd -g 9999 partage # sur client et serveur
sudo usermod -a -G partage $USER # sur client et serveur
sudo chgrp partage /srv/nfs # serveur uniquement
</code></pre></div></div>
<blockquote>
<p>NE PAS OUBLIER DE SE DECONNECTER/CONNECTER</p>
</blockquote>
<p>Nous pouvons confirmer que setgid est en place, comme indiqué ci-dessous, où le bit dexécution pour les autorisations de groupe est une minuscule. Cela passera à une majuscule S si le groupe ne dispose pas de lautorisation dexécution et que seul setgid est en place.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la /srv/nfs/
</code></pre></div></div>
<p>drwxrws— 5 root partage 4096 mars 16 07:57 .</p>
<p>Désormais, tous les fichiers ou répertoires créés dans /srv/nfs se verront automatiquement attribuer le propriétaire du groupe partage, ce qui permettra essentiellement la collaboration de groupe, car tout utilisateur appartenant au groupe partage pourra désormais accéder aux fichiers créés par dautres utilisateurs du groupe. même groupe dans le répertoire /srv/nfs.</p>
<h2 id="samba-client">Samba client</h2>
<p>Configuration du client SAMBA</p>
<p>Cela devrait fonctionner sans problème si vous installez <strong>cifs-utils</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install cifs-utils smbclient
</code></pre></div></div>
<p>Utilsation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>smbclient -L &lt;nom-de-l'ordinateur&gt; (nécessite le paquet smbclient)
</code></pre></div></div>
<h2 id="parefeu-iptables">Parefeu (iptables)</h2>
<p><img src="/images/iptables-logo.png" alt="" /></p>
<h3 id="sbiniptables-firewallsh">/sbin/iptables-firewall.sh</h3>
<p>On utilise un service systemd<br />
Créer le fichier le script <strong>/sbin/iptables-firewall.sh</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /sbin/iptables-firewall.sh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
# Configure iptables firewall
# Limit PATH
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
# iptables configuration
firewall_start() {
###################
# IPv4 #
###################
# refuser input et forward par défaut, accepter output
iptables -t filter -P INPUT DROP
iptables -t filter -P FORWARD DROP
iptables -t filter -P OUTPUT ACCEPT
# interface lo (loop) accessible
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# maintenir les connexions établies
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# accepter en entrée le ping (icmp), et les
# connexions sur les ports nécessaires.
iptables -A INPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 55035 -j ACCEPT
# NFSV4
iptables -A INPUT -s 192.168.0.0/24 -p tcp -m multiport --ports 111,2049,32764:32769 -j ACCEPT -m comment --comment "NFS Server"
iptables -A INPUT -s 192.168.0.0/24 -p udp -m multiport --ports 111,2049,32764:32769 -j ACCEPT -m comment --comment "NFS Server"
# accepter en sortie le ping, les requêtes HTTP(S), DNS,
# et les connexions sur les ports nécessaires.
iptables -A OUTPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
###################
# IPv6 #
###################
# refuser input et forward par défaut, accepter output
ip6tables -t filter -P INPUT DROP
ip6tables -t filter -P FORWARD DROP
ip6tables -t filter -P OUTPUT ACCEPT
# interface lo (loop) accessible
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
# maintenir les connexions établies
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# NDP pour toute interface de type broadcast
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-solicitation -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
# accepter en entrée le ping (icmpv6), les
# connexions entrantes déjà établies et les connexions sur les ports nécessaires.
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m conntrack --ctstate NEW -m limit --limit 1/s --limit-burst 1 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 55035 -j ACCEPT
ip6tables -A INPUT -p udp --dport 55035 -j ACCEPT
# accepter en sortie le ping, les requêtes HTTP(S), DNS,
# et les connexions sur les ports nécessaires.
ip6tables -t filter -A OUTPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 53 -j ACCEPT
}
# clear iptables configuration
firewall_stop() {
iptables -F
iptables -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
ip6tables -F
ip6tables -X
ip6tables -P INPUT ACCEPT
ip6tables -P FORWARD ACCEPT
ip6tables -P OUTPUT ACCEPT
}
# execute action
case "$1" in
start|restart)
echo "Starting firewall"
firewall_stop
firewall_start
;;
stop)
echo "Stopping firewall"
firewall_stop
;;
esac
</code></pre></div></div>
<p>Les droits et exécutable</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown root:root /sbin/iptables-firewall.sh
sudo chmod 750 /sbin/iptables-firewall.sh
</code></pre></div></div>
<h3 id="systemd---iptables-firewallservice">systemd - iptables-firewall.service</h3>
<p>Créer le service systemd <strong>iptables-firewall.service</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat &lt;&lt; EOF | sudo tee /etc/systemd/system/iptables-firewall.service
[Unit]
Description=iptables firewall service
After=network.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-firewall.sh start
RemainAfterExit=true
ExecStop=/sbin/iptables-firewall.sh stop
StandardOutput=journal
[Install]
WantedBy=multi-user.target
EOF
</code></pre></div></div>
<p>Recharger systemd manager</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
</code></pre></div></div>
<p>Lancer le service iptables et lactiver</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start iptables-firewall
sudo systemctl enable iptables-firewall
</code></pre></div></div>
<h2 id="sauvegardes-et-synchronisation">Sauvegardes et synchronisation</h2>
<h3 id="borgbackup">BorgBackup</h3>
<p><img src="/images/borg-logo.png" alt="" /></p>
<h4 id="machine-qui-stocke-les-sauvegardes--xoyizexyz---192168045">Machine qui stocke les sauvegardes → xoyize.xyz - 192.168.0.45</h4>
<p><strong><u>Installation BorgBackup et ajout clé publique sur le serveur de sauvegarde xoyize.xyz</u></strong><br />
On se connecte sur la machine et on passe en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>Installer borgbackup</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install borgbackup
</code></pre></div></div>
<p>Créer un utilisateur borg dédié aux sauvegardes par BorgBackup :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd borg --create-home --home-dir /srv/data/borg-backups/
</code></pre></div></div>
<p>Vérifier le propriétaire des dossiers “borg” , sinon modifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown borg.borg -R /srv/data/borg-backups/
</code></pre></div></div>
<p>Cet utilisateur na pas de mot de passe, nous nous y connecterons uniquement avec une clef SSH ,ajout de la clé publique</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /srv/data/borg-backups/.ssh
cat &gt;&gt; /srv/data/borg-backups/.ssh/authorized_keys
</code></pre></div></div>
<p>Copier/coller le contenu du fichier du fichier de clef publique (fichier /root/.ssh/yanspm_ed25519.pub de la machine à sauvegarder ) dans ce terminal, et presser [Ctrl]+[D] pour valider.</p>
<p>Autoriser utilisateur <strong>borg</strong> à exécuter <em>/usr/bin/borg</em> uniquement</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "borg ALL=NOPASSWD: /usr/bin/borg" &gt;&gt; /etc/sudoers
</code></pre></div></div>
<h4 id="machines-autorisés-à-effectuer-leur-backup">Machines autorisés à effectuer leur backup</h4>
<p>Le dossier de base pour les sauvegardes sur le serveur xoyize.xyz : <strong>/srv/data/borg-backups/</strong> <br />
Pour info les machines autorisés à effectuer leur backup sur cette machine :<br />
yannick-pc e6230</p>
<h3 id="rsync">Rsync</h3>
<p><img src="/images/rsync.png" alt="" /></p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Source</th>
<th>Destination</th>
<th>Commentaire</th>
</tr>
</thead>
<tbody>
<tr>
<td>rsync</td>
<td><code class="language-plaintext highlighter-rouge">usernl@xoyaz.xyz:/srv/data/borg-backups/*</code></td>
<td><code class="language-plaintext highlighter-rouge">/srv/data/borg-backups/</code> (xoyize.xyz)</td>
<td>(rsync over ssh)</td>
</tr>
<tr>
<td>rsync</td>
<td><code class="language-plaintext highlighter-rouge">/srv/data/music/* </code>(xoyize.xyz)</td>
<td><code class="language-plaintext highlighter-rouge">usernl@xoyaz.xyz:/home/usernl/backup/musique/</code></td>
<td>(rsync over ssh)</td>
</tr>
<tr>
<td>rsync</td>
<td><code class="language-plaintext highlighter-rouge">/srv/data/CalibreTechnique/*</code> (xoyize.xyz)</td>
<td><code class="language-plaintext highlighter-rouge">usernl@xoyaz.xyz:/home/usernl/backup/CalibreTechnique/</code></td>
<td>(rsync over ssh)</td>
</tr>
</tbody>
</table>
<h4 id="synchronisation-dossier-de-sauvegarde-borg-entre-xoyazxyz-et-xoyizexyz">Synchronisation dossier de sauvegarde borg entre xoyaz.xyz et xoyize.xyz</h4>
<p><em>Pour les serveurs yanspm.com yanfi.net et cinay.xyz ,les sauvegardes sont effectuées en utilisant le logiciel borg ,vers le serveur de backup xoyaz.xyz et on utilise rsync pour les transférer localement</em></p>
<p><strong>connexion avec clé</strong><br />
<u>sur le serveur appelant srvxo (xoyize.xyz - 192.168.0.45)</u>
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) nommé <strong>xoyaz_ed25519</strong> pour une liaison SSH avec le serveur KVM.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/xoyaz_ed25519
</code></pre></div></div>
<p>Ajouter la clé publique au fichier <strong>~/.ssh/authorized_keys</strong> du serveur de backup xoyaz.xyz</p>
<p>Test connexion</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -p 55036 -i /home/xoyi/.ssh/xoyaz_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null usernl@xoyaz.xyz
</code></pre></div></div>
<p>Créer la commande rsync avec son fichier dexclusion</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano .ssh/exclude-list.txt
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.bash_logout
.bashrc
.profile
.ssh
</code></pre></div></div>
<p>Lancer la commande rsync dans une fenêtre terminal tmux en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux
sudo -s
rsync -avz --progress --stats --human-readable --exclude-from '/home/xoyi/.ssh/exclude-list.txt' --rsync-path="sudo rsync" -e "ssh -p 55036 -i /home/xoyi/.ssh/xoyaz_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/
</code></pre></div></div>
<p>Paramétrer pour une exécution chaque jour à 2h30</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo crontab -e
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Synchro Backup entre serveur distant xoyaz.xyz (contient les backup des serveurs VPS) et le serveur local xoyize.xyz
30 02 * * * rsync -avz --progress --stats --delete --human-readable --exclude-from '/home/xoyi/.ssh/exclude-list.txt' --rsync-path="sudo rsync" -e "ssh -p 55036 -i /home/xoyi/.ssh/xoyaz_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ ; if [ $? -eq 0 ]; then echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation OK" | systemd-cat -t rsync-cron -p info ; else echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation ERREUR" | systemd-cat -t rsync-cron -p emerg ; fi
</code></pre></div></div>
<p><strong>Explications sur la commande</strong><br />
On redirige le résultat de la commande ($?) vers le journal avec <strong>systemd-cat</strong> <br />
<code class="language-plaintext highlighter-rouge">if [ $? -eq 0 ]; then echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation OK" | systemd-cat -t rsync-cron -p info ; else echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation ERREUR" | systemd-cat -t rsync-cron -p emerg ; fi</code></p>
<p>la ligne de commande décortiquée:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [ $? -eq 0 ]
then
echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation OK" | systemd-cat -t rsync-cron -p info
else
echo "Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ :Erreur Synchronisation" | systemd-cat -t rsync-cron -p emerg
fi
</code></pre></div></div>
<p>On peut lire le journal avec lidentifiant <em>rsync-cron</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl -t rsync-cron
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- Logs begin at Thu 2019-08-29 11:07:55 CEST, end at Tue 2019-09-17 17:50:32 CEST. --
sept. 17 17:50:32 srvxo rsync-cron[11728]: Rsync usernl@xoyaz.xyz:/srv/data/borg-backups/* /srv/data/borg-backups/ : Synchronisation OK
</code></pre></div></div>
<h4 id="synchronisation-dossiers-music-calibre-entre-xoyizexyz-et-xoyazxyz">Synchronisation dossiers music Calibre entre xoyize.xyz et xoyaz.xyz</h4>
<p>Ajouter au lanceur de tâches programmées</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo crontab -e
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Sauvegarde de dossiers /srv/data/{music,CalibreTechnique} sur serveur distant backup (nl) xoyaz.xyz
# Synchro music avec Backup
00 02 * * * rsync -avz --progress --stats --human-readable --delete --exclude-from '/home/xoyi/.ssh/exclude-list.txt' --rsync-path="sudo rsync" -e "ssh -p 55036 -i /home/xoyi/.ssh/xoyaz_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" /srv/data/music/* usernl@xoyaz.xyz:/home/usernl/backup/musique/ ; if [ $? -eq 0 ]; then echo "Rsync /srv/data/music/* usernl@xoyaz.xyz:/home/usernl/backup/musique/ : Synchronisation OK" | systemd-cat -t rsync-cron -p info ; else echo "Rsync /srv/data/music/* usernl@xoyaz.xyz:/home/usernl/backup/musique/ : Synchronisation ERREUR" | systemd-cat -t rsync-cron -p emerg ; fi
# Synchro CalibreTechnique avec Backup
10 02 * * * rsync -avz --progress --stats --human-readable --exclude-from '/home/xoyi/.ssh/exclude-list.txt' --rsync-path="sudo rsync" -e "ssh -p 55036 -i /home/xoyi/.ssh/xoyaz_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" /srv/data/CalibreTechnique/* usernl@xoyaz.xyz:/home/usernl/backup/CalibreTechnique/ ; if [ $? -eq 0 ]; then echo "Rsync /srv/data/CalibreTechnique/* usernl@xoyaz.xyz:/home/usernl/backup/CalibreTechnique/ : Synchronisation OK" | systemd-cat -t rsync-cron -p info ; else echo "Rsync /srv/data/CalibreTechnique/* usernl@xoyaz.xyz:/home/usernl/backup/CalibreTechnique/ : Synchronisation ERREUR" | systemd-cat -t rsync-cron -p emerg ; fi
</code></pre></div></div>
<h4 id="synchronisation-dossier-osm-new-avec-mapcinayxyz">Synchronisation dossier osm-new avec map.cinay.xyz</h4>
<p>Tâche programmée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo crontab -e
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>10 02 * * * rsync -avz --progress --stats --human-readable --rsync-path="sudo rsync" -e "ssh -p 55031 -i /home/xoyi/.ssh/kvm-vps591606 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" /srv/data/devel/ouestline/osm-new/* debadm@cinay.xyz:/srv/osm-new/ ; if [ $? -eq 0 ]; then echo "Rsync /srv/data/devel/ouestline/osm-new/* debadm@cinay.xyz:/srv/osm-new/ : Synchronisation OK" | systemd-cat -t rsync-osm -p info ; else echo "Rsync /srv/data/devel/ouestline/osm-new/* debadm@cinay.xyz:/srv/osm-new/ : Synchronisation ERREUR" | systemd-cat -t rsync-osm -p emerg ; fi
</code></pre></div></div>
<h2 id="unbound---dns">Unbound - DNS</h2>
<p><img src="/images/unbound-250.png" alt="" /></p>
<p><em>Unbound est un résolveur DNS validateur, cache, récursif développé par NLnet Labs, VeriSign Inc., Nominet, et Kirei. Le logiciel est distribué sous licence BSD.</em></p>
<h3 id="installer-et-configurer-unbound">Installer et configurer Unbound</h3>
<ul>
<li><a href="/2018/04/27/unbound-resolveur-DNS.html">Résolveur DNS Unbound</a></li>
</ul>
<p>Installer resolvconf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
apt install resolvconf -y
echo "nameserver 127.0.0.1" &gt;&gt; /etc/resolvconf/resolv.conf.d/head
</code></pre></div></div>
<blockquote>
<p>Une fois le paquet « resolvconf » installé, il ne faut plus modifier le fichier « /etc/resolv.conf », car le contenu de celui-ci sera automatiquement géré et remplacé par « resolvconf ».</p>
</blockquote>
<h3 id="blocage-des-dmp-avec-unbound-non-implante">Blocage des DMP avec Unbound (NON IMPLANTE)</h3>
<p><em>Configuration nécessaire pour Unbound afin de bloquer certaines « Data Management Platforms » (DMP) utilisées par de plus en plus de sites (liberation.fr, oui.scnf, lemonde.fr, fnac.com…) et qui échappent pour linstant aux bloqueurs de traqueurs traditionnels (uBlock Origin ou uMatrix par exemple)<a href="https://gitea.cinay.eu/yann/blocage-dmp-unbound">https://gitea.cinay.eu/yann/blocage-dmp-unbound</a></em></p>
<p><strong>Le cœur du problème</strong> <br />
Dernièrement, une conjoncture déléments est venue semer le trouble chez nos aspirateurs :</p>
<ul>
<li>Lentrée en vigueur du RGPD en Europe</li>
<li>La part de plus en plus grande dinternautes utilisant des bloqueurs de publicités</li>
<li>La volonté des éditeurs de navigateurs web (Chrome et Firefox et donc leurs dérivés) de bloquer par défaut les traqueurs ou les cookies tiers.</li>
</ul>
<p>Un mouchard est dit tiers ou 3rd-party quand on est disruptif quand il nest pas chargé depuis le domaine (ou un de ses sous domaines) que vous visitez. Par exemple quand on visite https://liberation.fr/, le script chargé depuis www.google-analytics.com est tiers. Si le même mouchard est chargé depuis un sous-domaine de liberation.fr, il est dit 1st-party (primaire a priori en bon français).
Le hic, pour nos amis start-uppers est que les mouchards/cookies tiers sont triviaux à bloquer. Ne pas charger les cookies tiers est dailleurs une option répandue dans les navigateurs depuis des années.</p>
<p><strong>La fourberie</strong><br />
La technique développée par les marketeux pour ne pas voir les juteuses données personnelles leur échapper est à la fois techniquement très simple et redoutable. Il suffit de transformer les crasses 3rd-party en 1st-party afin de les cacher sous le cyber-tapis pour reprendre lexpression de Reflets. Et pour se faire passer par le DNS et ses possiblités.</p>
<p><strong>Bloquer les indésirables avec Unbound</strong><br />
On entre dans la partie technique, pour faire court, on va décréter à Unbound que nous contrôlons les domaines indésirables (eulerian.net par exemple) afin de faire échouer la résolution DNS. La technique est <a href="https://www.shaftinc.fr/escalade-traque-eulerian.html">développée plus en détail sur un blog</a>.</p>
<p>Pour mémoire :</p>
<ul>
<li>On crée un fichier de zone (<strong>blocked.zone</strong>) où lon met un enregistrement SOA.</li>
<li>On lassocie à chaque domaine à bloquer dans la configuration dUnbound (<strong>adblock-war.conf</strong>)</li>
</ul>
<p>Cette technique sera valable, pour les versions dUnbound supérieures à 1.7.0.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/var/lib/unbound/blocked.zone
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 10800
@ IN SOA localhost. nobody.invalid. (
1
3600
1200
604800
10800
)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/unbound/unbound.conf.d/adblock-war.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># À n'utiliser qu'avec une version d'Unbound supérieure à la 1.7.0
auth-zone:
name: "eulerian.net."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "eulerian.fr."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "eulerian.com."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "dnsdelegation.io."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "a.20mn.fr."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "at-o.net."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "keyade.com."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "storetail.io."
zonefile: "/var/lib/unbound/blocked.zone"
auth-zone:
name: "omtrdc.net."
zonefile: "/var/lib/unbound/blocked.zone"
</code></pre></div></div>
<p>Redémarrer unbound</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart unbound
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig v.oui.sncf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; &lt;&lt;&gt;&gt; DiG 9.11.5-P4-5.1-Debian &lt;&lt;&gt;&gt; v.oui.sncf
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NXDOMAIN, id: 23289
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;v.oui.sncf. IN A
;; ANSWER SECTION:
v.oui.sncf. 2822 IN CNAME voyages-sncf.eulerian.net.
;; AUTHORITY SECTION:
eulerian.net. 10021 IN SOA localhost. nobody.invalid. 1 3600 1200 604800 10800
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: ven. nov. 15 16:07:19 CET 2019
;; MSG SIZE rcvd: 137
</code></pre></div></div>
<p>La requête nest pas servie (NXDOMAIN)</p>
<h2 id="autorité-de-certification--certificats-clients">Autorité de certification + Certificats clients</h2>
<p><img src="/images/certificat.png" alt="" /></p>
<h3 id="création-dune-autorité-de-certification">Création dune autorité de certification</h3>
<p><a href="/2019/07/10/Autorite-de-certification-et-certificats-OpenSSL.html">Autorité de certification et authentification par certificat client (OpenSSL,nginx)</a></p>
<p>On cherche le fichier CA.pl <code class="language-plaintext highlighter-rouge">sudo find / -type f -name "CA.pl"</code><br />
/usr/lib/ssl/misc/CA.pl</p>
<p>Créer une autorité de certification basée sur un certificat ayant une durée de validité de 10 ans dont la racine est « /etc/ssl/CertificateAuthority » , modifier les variables » CADAYS » et « CATOP » dans le fichier du script <strong>/usr/lib/ssl/misc/CA.pl</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my $CADAYS = "-days 3650"; # 10 years
my $CATOP = "/etc/ssl/CertificateAuthority";
</code></pre></div></div>
<p>ainsi que la valeur de « dir » dans « <strong>/etc/ssl/openssl.cnf</strong> »</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ CA_default ]
dir = /etc/ssl/CertificateAuthority # Where everything is kept
</code></pre></div></div>
<p>Création</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/lib/ssl/misc/CA.pl -newca # Répondre aux différentes questions ,une "passphrase" sera demandée pour le fichier cakey.pem (conserver la "passphrase")
</code></pre></div></div>
<p>A la fin ,la structure</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tree /etc/ssl/CertificateAuthority/
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/ssl/CertificateAuthority/
├── cacert.pem
├── careq.pem
├── certs
├── crl
├── crlnumber
├── index.txt
├── index.txt.attr
├── index.txt.old
├── newcerts
│   └── 0DDDBF9FF301DFEC10C1E57CEBB38DAD6E7A6251.pem
├── private
│   └── cakey.pem
└── serial
</code></pre></div></div>
<p>Le « hash » du certificat <strong>cacert.pem</strong> (hachage du DN) est retourné par :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 -hash -noout -in /etc/ssl/CertificateAuthority/cacert.pem
ecd697ae
</code></pre></div></div>
<p>Créer le lien “/etc/ssl/CertificateAuthority/certs/ecd697ae.0” (.0, premier index) pointant vers “/etc/ssl/CertificateAuthority/cacert.pem”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ln -s /etc/ssl/CertificateAuthority/cacert.pem /etc/ssl/CertificateAuthority/certs/ecd697ae.0
</code></pre></div></div>
<h3 id="création-certificat-client">Création certificat client</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Certificat client Yannick
sudo -s
cd /etc/ssl/CertificateAuthority/
openssl ecparam -out yannick.key -name prime256v1 -genkey
openssl req -new -key yannick.key -out yannick.csr -sha256 # Renseigner Common Name obligatoirement (Yannick)
openssl req -x509 -in yannick.csr -key yannick.key &gt; admin-linux.crt
openssl ca -policy policy_anything -out yannick.crt -infiles yannick.csr # signature et valable 365 jours , mp cakey.pem demandé
openssl pkcs12 -export -out yannick.pfx -inkey yannick.key -in yannick.crt -certfile cacert.pem # il faut saisir un mot de passe d'exportation pour le certificat client (mp yannick)
cp yannick.pfx /srv/nfs/
chmod 775 /srv/nfs/yannick.pfx
# Certificat client Yann
sudo -s
cd /etc/ssl/CertificateAuthority/
openssl ecparam -out yann.key -name prime256v1 -genkey
openssl req -new -key yann.key -out yann.csr -sha256 # Renseigner Common Name obligatoirement (Yann)
openssl req -x509 -in yann.csr -key yann.key &gt; admin-linux.crt
openssl ca -policy policy_anything -out yann.crt -infiles yann.csr # signature et valable 365 jours , mp cakey.pem demandé
openssl pkcs12 -export -out yann.pfx -inkey yann.key -in yann.crt -certfile cacert.pem # il faut saisir un mot de passe d'exportation pour le certificat client (mp yann)
cp yann.pfx /srv/nfs/
chmod 775 /srv/nfs/yann.pfx
</code></pre></div></div>
<h2 id="nginx--php74--mariadb--ssltls13">Nginx + PHP7.4 + MariaDB + SSL/TLS1.3</h2>
<p><img src="/images/nginx-php7-mariadb.png" alt="lemp" width="150" /></p>
<h3 id="installation-nginx--php74--mariadb--ssltls13">Installation Nginx + PHP7.4 + MariaDB + SSL/TLS1.3</h3>
<p>Ce script bash compile et installe nginx ,le service nginx (systemd) pour le démarrage, PHP7.4 et mariadb.<br />
Exécuter les instructions suivantes pour lancer la compilation</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-s</span> <span class="c"># Passer en mode super utilisateur (su ou sudo) </span>
wget <span class="nt">-O</span> compil.sh <span class="s2">"https://yann.cinay.eu/files/debian10-compilation-nginx-tls1.3-php7.4-MariaDB.sh"</span> <span class="c"># Télécharger le script</span>
<span class="nb">chmod</span> +x compil.sh <span class="c"># Rendre le script exécutable </span>
./compil.sh <span class="c"># Exécuter le script</span>
<span class="c">#******** Patienter **********</span>
</code></pre></div></div>
<p>Patienter de 5 à 10 minutes… <br />
Résultat</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Versions Nginx OpenSSL MariaDB et PHP
nginx version: nginx/1.16.1
OpenSSL 1.1.1d 10 Sep 2019
mysql Ver 15.1 Distrib 10.3.22-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Mot de passe MySql/MariaDB : /etc/mysql/mdp
PHP 7.4.3 (cli) (built: Feb 24 2020 18:39:14) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
</code></pre></div></div>
<p>Les paramètres de compilation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -V
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx version: nginx/1.16.1
built by gcc 8.3.0 (Debian 8.3.0-6)
built with OpenSSL 1.1.1d 10 Sep 2019
TLS SNI support enabled
configure arguments: \
--with-cc-opt='-g -O2 -fdebug-prefix-map=/usr/src/nginx-custom/$stable_nginx=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now,-rpath,/usr/local/lib' \
--prefix=/usr/share/nginx \
--user=nginx \
--group=nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--modules-path=/usr/lib/nginx/modules \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_slice_module \
--with-threads \
--with-http_addition_module \
--with-http_flv_module \
--with-http_geoip_module=dynamic \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_image_filter_module=dynamic \
--with-http_mp4_module \
--with-http_perl_module=dynamic \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_sub_module \
--with-http_xslt_module=dynamic \
--with-mail=dynamic \
--with-mail_ssl_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-http_ssl_module \
--add-dynamic-module=../modules/nginx-auth-pam \
--add-dynamic-module=../modules/ngx-fancyindex
</code></pre></div></div>
<p>On change le dossier racine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /var/www/default-www
sudo mv /var/www/{index.html,info.php} /var/www/default-www/
</code></pre></div></div>
<h3 id="configuration-nginx">Configuration nginx</h3>
<h4 id="etcnginxnginxconf"><strong>/etc/nginx/nginx.conf</strong></h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
server_names_hash_bucket_size 64;
upstream php-handler {
server unix:/run/php/php7.4-fpm.sock;
}
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
##
# Authentification par certificat client
# limité à certains utilisateurs
##
map $ssl_client_s_dn $ssl_access {
default 0;
"~CN=Yannick" 1;
"~CN=Yann" 1;
"~CN=Jean Dupondt Stagiaire" 1;
# etc.
}
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
}
</code></pre></div></div>
<h4 id="diffie-hellman-ssl-tls12-tls13-headers-ocsp-certificats-clients">Diffie-Hellman, ssl (tls1.2 tls1.3) Headers OCSP, certificats clients</h4>
<p>Diffie-Hellman</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
</code></pre></div></div>
<p>Regroupement dans le fichier <strong>/etc/nginx/ssl_dh_header_ocsp</strong> → ssl (tls1.2 tls1.3) , Headers et OCSP</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ##
# SSL Settings
##
ssl_certificate /etc/ssl/private/xoyize.xyz-fullchain.pem;
ssl_certificate_key /etc/ssl/private/xoyize.xyz-key.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_dhparam /etc/ssl/private/dh2048.pem;
# 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;
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';
add_header Referrer-Policy "no-referrer" always;
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
#ssl_trusted_certificate /etc/ssl/private/xoyize.xyz-fullchain.pem;
ssl_trusted_certificate /etc/ssl/private/ocsp-certs.pem;
resolver 127.0.0.1;
</code></pre></div></div>
<h4 id="accès-par-certificats-clients">Accès par certificats clients</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/nginx/auth_certificat_client
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Certificat client
ssl_client_certificate /etc/ssl/CertificateAuthority/cacert.pem;
# rendre la vérification optionnelle
# afin de pouvoir afficher un message 403
# à ceux qui échouent à l'authentification
ssl_verify_client optional;
if ( $ssl_access = 0 ) {
return 403 "&lt;h2&gt;Zone Interdite, absence de certificat client !!!&lt;/h2&gt;" ; # =&gt; forbidden
}
</code></pre></div></div>
<blockquote>
<p>Pour activer le certificat client dans laccès dunsite ,il faut ajouter la directive <code class="language-plaintext highlighter-rouge">include auth_certificat_client;</code> dans le fichier de configuration .conf du vhost</p>
</blockquote>
<h2 id="xoyizexyz">xoyize.xyz</h2>
<h3 id="configuration-de-base">Configuration de base</h3>
<p>Configuration de base avec SSL et sécurité + letsencrypt (renouvellement)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/xoyize.xyz.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name xoyize.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name xoyize.xyz;
#### Locations
# On cache les fichiers statiques
location ~* \.(html|css|js|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires max; }
# On interdit les dotfiles
location ~ /\. { deny all; }
root /var/www/default-www ;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.4-fpm.sock; # PHP7.4
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# if folder xoyize.xyz.d , uncomment the following directive
#include conf.d/xoyize.xyz.d/*.conf;
access_log /var/log/nginx/xoyize.xyz-access.log;
error_log /var/log/nginx/xoyize.xyz-error.log;
}
</code></pre></div></div>
<p>Effacer ancien fichier de config</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/nginx/conf.d/default.conf
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
</code></pre></div></div>
<p>relancer nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart nginx
</code></pre></div></div>
<p>Vérifier le lien <a href="https://xoyize.xyz">https://xoyize.xyz</a> , le tls 1.3</p>
<p><img src="/images/tlsv1.3-xoyize.xyz.png" alt="" width="500" /></p>
<h3 id="dévelopment---develxoyizexyz">Dévelopment - devel.xoyize.xyz</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ____ _ _
| _ \ _____ _____| | ___ _ __ _ __ ___ ___ _ __ | |_
| | | |/ _ \ \ / / _ \ |/ _ \| '_ \| '_ ` _ \ / _ \ '_ \| __|
| |_| | __/\ V / __/ | (_) | |_) | | | | | | __/ | | | |_
|____/ \___| \_/ \___|_|\___/| .__/|_| |_| |_|\___|_| |_|\__|
|_|
</code></pre></div></div>
<p>Accès dossier “développement” <strong>/srv/data/devel/ouestline</strong> partagé avec PC1 <br />
Fichier de configuration nginx <strong>/etc/nginx/conf.d/devel.xoyize.xyz.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/nginx/conf.d/devel.xoyize.xyz.conf
##
# Virtual Host devel.xoyize.xyz
##
server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name devel.xoyize.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name devel.xoyize.xyz;
#### Locations
# On cache les fichiers statiques
location ~* \.(html|css|js|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires max; }
# On interdit les dotfiles
location ~ /\. { deny all; }
include ssl_dh_header_ocsp;
include auth_certificat_client;
#autoindex on;
fancyindex on; # Enable fancy indexes.
fancyindex_exact_size off; # Output human-readable file sizes.
root /srv/data/devel/ouestline/ ;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.4-fpm.sock; # php7.4
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# if folder devel.xoyize.xyz.d , uncomment the following directive
#include conf.d/devel.xoyize.xyz.d/*.conf;
access_log /var/log/nginx/develop-access.log;
error_log /var/log/nginx/develop-error.log;
}
</code></pre></div></div>
<p>Vérifier et relancer nginx</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>
<blockquote>
<p>Problème de compilation du module <code class="language-plaintext highlighter-rouge">--add-dynamic-module=../modules/lua-nginx-module</code> <br />
<a href="https://medium.com/@technospace/nginx-as-an-openid-connect-rp-with-wso2-identity-server-part-2-492ab6bf5cc9">NGINX as an OpenID Connect RP with WSO2 Identity Server — Part 2</a></p>
</blockquote>
<h3 id="airsonic-streaming-audio---subxoyizexyz">Airsonic (streaming audio) - sub.xoyize.xyz</h3>
<p><img src="/images/airsonic-logo.png" alt="" width="150" /></p>
<p><em>Airsonic, a Free and Open Source community driven media server, providing ubiquitous access to your music.</em></p>
<ul>
<li>Installer openjdk version 8 → <a href="/2020/03/11/OpenJDK8-sur-Debian10(Buster).html">OpenJDK 8 sur Debian 10 (Buster)</a></li>
<li><a href="https://airsonic.github.io/docs/install/war-standalone/">Installer airsonic en standalone</a></li>
</ul>
<p>On utilise <strong>systemd</strong><br />
Pour aller un peu plus loin que le simple pilotage manuel de airsonic, on peut mettre en place une intégration avec Systemd. Systemd est un système init pour la plupart des systèmes linux. Il permet dexécuter lairsonic au démarrage. Les étapes ci-dessous ont été réalisées sur un hôte Fedora, mais les étapes devraient être similaires pour les autres distributions Linux.</p>
<p>En suivant ces instructions de configuration de Systemd, Airsonic sera disponible sur http://localhost:4040/airsonic.</p>
<p>Configuration de lutilisateur dédié à Airsonic :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd airsonic
</code></pre></div></div>
<p>Création des dossiers</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /var/airsonic
sudo chown airsonic /var/airsonic
</code></pre></div></div>
<p>Télécharger le “war”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
wget -4 https://github.com/airsonic/airsonic/releases/download/v10.5.0/airsonic.war --output-document=/var/airsonic/airsonic.war
</code></pre></div></div>
<p>Créer le service systemd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget -4 https://raw.githubusercontent.com/airsonic/airsonic/master/contrib/airsonic.service -O /etc/systemd/system/airsonic.service
wget -4 https://raw.githubusercontent.com/airsonic/airsonic/master/contrib/airsonic-systemd-env -O /etc/default/airsonic
</code></pre></div></div>
<p>Modifier le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/systemd/system/airsonic.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
Environment="PORT=4040"
Environment="CONTEXT_PATH=/"
[...]
</code></pre></div></div>
<p>Lancer et activer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl daemon-reload
systemctl start airsonic.service
systemctl enable airsonic.service
</code></pre></div></div>
<p>Fichier de configuration nginx <strong>/etc/nginx/conf.d/sub.xoyize.xyz.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/sub.xoyize.xyz.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/nginx/conf.d/sub.xoyize.xyz.conf
##
# Virtual Host sub.xoyize.xyz (Subsonic)
##
server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name sub.xoyize.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name sub.xoyize.xyz;
include ssl_dh_header_ocsp;
# Proxy to the Airsonic server
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Host $http_host;
proxy_max_temp_file_size 0;
proxy_pass http://127.0.0.1:4040;
proxy_redirect http:// https://;
}
}
</code></pre></div></div>
<p>Redémarrer nginx , <code class="language-plaintext highlighter-rouge">sudo systemctl restart nginx</code> <br />
Accès https://sub.xoyize.xyz ,admin/admin</p>
<ul>
<li>Changer le mot de passe administrateur</li>
<li>Définir le répertoire media : /srv/data/Musique</li>
<li>Changer le thème (facultatif)</li>
<li>Valider loption accès au dossier media par admin</li>
<li>Scanner le dossier media</li>
</ul>
<p><strong>DESINSTALLER</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
systemctl stop airsonic
systemctl disable airsonic
rm /etc/systemd/system/airsonic.service
systemctl daemon-reload
rm /var/airsonic/airsonic.war
mv /etc/nginx/conf.d/sub.xoyize.xyz.conf /etc/nginx/conf.d/sub.xoyize.xyz.conf.sav
systemctl restart nginx
ocsp_cache
apt remove adoptopenjdk-8-hotspot
apt autoremove
# Ouvrir le fichier /etc/apt/sources.list
# supprimer les 2 lignes qui contiennent 'https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/'
apt update
</code></pre></div></div>
<h3 id="phpmyadmin---sqlxoyizexyz">PhpMyadmin - sql.xoyize.xyz</h3>
<p><img src="/images/php-my-admin.png" alt="" width="150" /></p>
<p><em>phpMyAdmin (PMA) est une application Web de gestion pour les systèmes de gestion de base de données MySQL réalisée principalement en PHP et distribuée sous licence GNU GPL.<a href="https://fr.wikipedia.org/wiki/PhpMyAdmin">Wikipedia</a></em></p>
<ul>
<li><a href="/2020/02/21/PhpMyAdmin.html">PhpMyAdmin (gestionnaire bases mysql/mariadb)</a></li>
</ul>
<p>Installation<br />
Prérequis : PHP mbstring zip et gd installés</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
# la dernière version en cours https://files.phpmyadmin.net/phpMyAdmin/
wget -4 https://files.phpmyadmin.net/phpMyAdmin/5.0.1/phpMyAdmin-5.0.1-all-languages.zip
unzip phpMyAdmin-5.0.1-all-languages.zip
mv phpMyAdmin-5.0.1-all-languages /usr/share/phpmyadmin
#
mkdir -p /var/lib/phpmyadmin/tmp
chown -R www-data:www-data /var/lib/phpmyadmin
cp /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<p>Configurer <strong>/usr/share/phpmyadmin/config.inc.php</strong><br />
La base mysql</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql -uroot -p$(cat /etc/mysql/mdp) &lt; /usr/share/phpmyadmin/sql/create_tables.sql
mysql -uroot -p$(cat /etc/mysql/mdp) -e "GRANT SELECT, INSERT, UPDATE, DELETE ON phpmyadmin.* TO 'pma'@'localhost' IDENTIFIED BY 'qzbXEHio0lwq';"
mysql -uroot -p$(cat /etc/mysql/mdp) -e "GRANT ALL PRIVILEGES ON *.* TO 'yanspm'@'localhost' IDENTIFIED BY 'DxShMzcc4v' WITH GRANT OPTION;"
ln -s /usr/share/phpmyadmin /var/www/default-www/rienavoir
</code></pre></div></div>
<p>Ajouter à <strong>/usr/share/phpmyadmin/config.inc.php</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;?php
[...]
$cfg['Servers'][$i]['AllowRoot'] = false;
</code></pre></div></div>
<p>passerelle dauthentification<br />
Prérequis, le module nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sh -c "echo -n 'yanspm:' &gt;&gt; /etc/nginx/.pma_pass"
sudo sh -c "openssl passwd -apr1 &gt;&gt; /etc/nginx/.pma_pass" # même mot de passe yanspm
mkdir -p /etc/nginx/conf.d/xoyize.xyz.d/ # créer le dossier si inexistant
</code></pre></div></div>
<p>Créer le fichier passerelle <strong>/etc/nginx/conf.d//xoyize.xyz.d/phpadmin.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>location /rienavoir {
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/.pma_pass;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
</code></pre></div></div>
<p>Vérifier et recharger nginx</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>Tester https://xoyize.xyz/rienavoir</p>
<p>Fichier de configuration nginx <strong>/etc/nginx/conf.d/sql.xoyize.xyz.conf</strong> avec accès clients autorisés</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/nginx/conf.d/sql.xoyize.xyz.conf
##
# Virtual Host sql.xoyize.xyz (PhpMyAdmin)
##
server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name sql.xoyize.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name sql.xoyize.xyz;
include ssl_dh_header_ocsp;
# Authentification par certificat client
include auth_certificat_client;
root /var/www/default-www/rienavoir/;
index index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.4-fpm.sock; # PHP7.4
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_index index.php;
include fastcgi_params;
}
access_log /var/log/nginx/sql-access.log;
error_log /var/log/nginx/sql-error.log;
}
</code></pre></div></div>
<p>Accès par https://sql.xoyize.xyz <br />
Refuser laccès par https://xoyize.xyz/phpmyadmin</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/xoyize.xyz.d/phpmyadmin.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>location /phpmyadmin {
return 403; # =&gt; forbidden
}
</code></pre></div></div>
<h2 id="msmtp---envoi-de-message-en-ligne-de-commande">msmtp - envoi de message en ligne de commande</h2>
<ul>
<li><a href="/2020/03/29/msmtp-EnvoiMail-en-ligne-de-commande.html">msmtp - envoi de message en ligne de commande</a></li>
<li><a href="/2020/03/29/Utiliser-GPG-pour-chiffrer-dechiffrer-un-mot-de-passe.html">Utiliser GPG pour chiffrer-déchiffrer un mot de passe</a></li>
</ul>
<h3 id="gpg---chiffrerdéchiffrer">GPG - Chiffrer/Déchiffrer</h3>
<p>On a notre paire de clés avec identifiant <strong>900D4EF9</strong> (les 8 derniers caractères) et une adresse de messagerie ** xoyize-xyz@cinay.xyz**,on peut chiffrer et déchiffrer des documents</p>
<p><strong>CHIFFRER</strong><br />
fichier de message chiffré avec la méthode suivante (aucune trace dans lhistorique)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpg --encrypt -o .msmtp-xoyize-xyz.gpg -r xoyize-xyz@cinay.xyz -
</code></pre></div></div>
<p>Saisir le mot de passe que lon veut chiffrer puis tapez <Entrée> et enfin <Ctrl d=""> au clavier</Ctrl></Entrée></p>
<p>Vérifier la présence du fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls .msmtp-xoyize-xyz.gpg
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.msmtp-xoyize-xyz.gpg
</code></pre></div></div>
<p><strong>DECHIFFRER</strong><br />
Il faut saisir la phrase secrète de xoyize une fois</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpg --no-tty -q -d .msmtp-xoyize-xyz.gpg
</code></pre></div></div>
<p>Une resaisie de la phrase secrètetous les 12 heures (gpg-agent)</p>
<h3 id="msmtp---configuration-utilisateur-msmtprc">msmtp - configuration utilisateur ~/.msmtprc</h3>
<p>Serveur smtp = cinay.xyz<br />
Compte = yannick</p>
<p>On récupère lempreinte du serveur smtp que lon va utiliser</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msmtp --serverinfo --tls --tls-certcheck=off --host=cinay.xyz
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
Empreintes:
SHA256: 20:D3:6B:CD:B5:DA:90:06:B2:FF:B8:9D:C1:57:2D:1B:B8:FC:5E:6B:DF:C9:41:0A:CC:2C:C5:61:D0:02:F9:61
...
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/.msmtprc
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># fichier de configuration utilisateur ~/.msmtprc
# Définissez les valeurs par défaut pour tous les comptes suivants.
defaults
# Utilisez le port de soumission du courrier 587 au lieu du port SMTP 25.
port 587
# Utilisez toujours le TLS.
tls on
# Un service de courrier électronique gratuit
account cinay-xyz
# Nom d'hôte du serveur SMTP
host cinay.xyz
# Comme alternative au tls_trust_file/tls_crl_file, vous pouvez utiliser tls_fingerprint
# pour épingler un seul certificat. Vous devez mettre à jour l'empreinte digitale lorsque le
# le certificat du serveur change, mais un attaquant ne peut pas vous piéger pour que vous acceptiez
# un certificat frauduleux. Obtenez l'empreinte digitale avec
# msmtp --serverinfo --tls --tls-certcheck=off --host=smtp.freemail.example
tls_fingerprint 20:D3:6B:CD:B5:DA:90:06:B2:FF:B8:9D:C1:57:2D:1B:B8:FC:5E:6B:DF:C9:41:0A:CC:2C:C5:61:D0:02:F9:61
# Enveloppe - à partir de l'adresse
from yannick@cinay.xyz
# Authentification.
auth on
user yannick
# le mot de passe est dans un fichier crypté, indiquer à msmtp la commande à utiliser pour le décrypter.
# Cette commande est généralement utilisée avec GnuPG
# Habituellement, gpg-agent demande une fois le mot de passe de décryptage.
passwordeval gpg --no-tty -q -d ~/.msmtp-cinay-xyz.gpg
# Définir un compte par défaut
account default : cinay-xyz
</code></pre></div></div>
<h3 id="test-envoi-message">Test envoi message</h3>
<p>Loption de compte ( <code class="language-plaintext highlighter-rouge">--account=,-a</code> ) indique quel compte utiliser comme expéditeur:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "hello there username." | msmtp -a default username@domain.com
</code></pre></div></div>
<p>Ou, avec les adresses dans un fichier test.mail:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>To: username@domain.com
From: user12@gmail.com
Subject: A test
Hello there.
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat test.mail | msmtp -a default username@domain.com
</code></pre></div></div>
<h2 id="information-sur-la-structure">INFORMATION sur la structure</h2>
<p>Opérations effectuées sur serveur srvxo avec une clé bootable “Pmagic”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Transfert du home
mkdir -p /mnt/{home,homeOld}
mount /dev/ssd-vg/home /mnt/home
mount /dev/hdd-2g/home /mnt/homeOld/
rm -r /mnt/homeOld/lost+found/
rm -r /mnt/home/lost+found/
rsync -av /mnt/homeOld/*
umount /mnt/{home,homeOld}
lvremove /dev/hdd-2g/home
# Transfert data nfs su /srv
mkdir /mnt/srv
mount /dev/mapper/hdd--2g-lvhdd /mnt/srv/
rm -r /mnt/srv/lost+found/
mkdir -p /mnt/srv/{data,nfs}
mv /mnt/srv/{borg-backups,CalibreTechnique,devel,dplus,Musique,playlists,podcasts,virtuel} /mnt/srv/data/
mkdir /mnt/nfs
mount /dev/hdd-2g/nfs /mnt/nfs/
rsync -av /mnt/nfs/*
umount /mnt/srv
umount /mnt/nfs
# supprime /dev/hdd-2g/nfs
lvremove /dev/hdd-2g/nfs
# Vérification avant augmentation capacité volume
e2fsck -f /dev/hdd-2g/lvhdd
lvresize -l +100%FREE
resize2fs /dev/hdd-2g/lvhdd
# Modifier fstab et exports
mkdir /mnt/root
mount /dev/ssd-vg/rootb /mnt/root
nano /mnt/root/etc/fstab
nano /mnt/root/etc/exports
</code></pre></div></div>
<p>Résultats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@srvxo:/home/xoyi# pvs
PV VG Fmt Attr PSize PFree
/dev/sda4 ssd-vg lvm2 a-- &lt;107,29g &lt;67,29g
/dev/sdb1 hdd-2g lvm2 a-- &lt;1,82t 0
root@srvxo:/home/xoyi# vgs
VG #PV #LV #SN Attr VSize VFree
hdd-2g 1 1 0 wz--n- &lt;1,82t 0
ssd-vg 1 2 0 wz--n- &lt;107,29g &lt;67,29g
root@srvxo:/home/xoyi# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lvhdd hdd-2g -wi-ao---- &lt;1,82t
home ssd-vg -wi-ao---- 20,00g
rootb ssd-vg -wi-ao---- 20,00g
root@srvxo:/home/xoyi# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# &lt;file system&gt; &lt;mount point&gt; &lt;type&gt; &lt;options&gt; &lt;dump&gt; &lt;pass&gt;
/dev/mapper/ssd--vg-rootb / ext4 errors=remount-ro 0 1
# /boot was on /dev/sda2 during installation
UUID=6ff909c4-5117-4b17-a571-54bde94fd6b5 /boot ext2 defaults 0 2
/dev/mapper/ssd--vg-home /home ext4 defaults 0 2
# swap was on /dev/sda3 during installation
UUID=4afbc634-a79f-47c2-a15f-6ea17e62ceb7 none swap sw 0 0
/dev/mapper/hdd--2g-lvhdd /srv ext4 defaults 0 2
root@srvxo:/home/xoyi# cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
# exportfs -ar
#/srv/data 192.168.0.0/24(rw,sync,no_subtree_check,no_root_squash)
/srv 192.168.0.0/24(rw,sync,no_subtree_check,no_root_squash)
root@srvxo:/home/xoyi# df -h
Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur
udev 3,7G 0 3,7G 0% /dev
tmpfs 741M 8,7M 733M 2% /run
/dev/mapper/ssd--vg-rootb 20G 2,7G 16G 15% /
tmpfs 3,7G 0 3,7G 0% /dev/shm
tmpfs 5,0M 0 5,0M 0% /run/lock
tmpfs 3,7G 0 3,7G 0% /sys/fs/cgroup
/dev/sda2 504M 84M 395M 18% /boot
/dev/mapper/ssd--vg-home 20G 2,0G 17G 11% /home
/dev/mapper/hdd--2g-lvhdd 1,8T 324G 1,4T 19% /srv
tmpfs 741M 0 741M 0% /run/user/1000
</code></pre></div></div>
<h2 id="go-node">Go Node</h2>
<h3 id="go">Go</h3>
<p><img src="/images/golang-color-icon2.png" alt="golang" width="50" /></p>
<p>Go installation (Debian) , installer la dernière version de Go (https://golang.org/dl/)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.14.2.linux-amd64.tar.gz
rm go1.14.2.linux-amd64.tar.gz
</code></pre></div></div>
<p>Environnement de configuration</p>
<p>Bash: <strong>~/.bashrc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p $HOME/go
echo "export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin" &gt;&gt; ~/.bashrc
echo "export GOPATH=$HOME/go" &gt;&gt; ~/.bashrc
source ~/.bashrc
</code></pre></div></div>
<h3 id="nodejs">Nodejs</h3>
<p><img src="/images/Node_logo.png" alt="nodejs" width="50" /></p>
<p>Installer la version LTS de nodejs pour le frontend.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install curl software-properties-common -y
curl -sL https://deb.nodesource.com/setup_12.x | sudo bash -
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## Run `sudo apt-get install -y nodejs` to install Node.js 12.x and npm
## You may also need development tools to build native addons:
sudo apt-get install gcc g++ make
## To install the Yarn package manager, run:
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update &amp;&amp; sudo apt-get install yarn
</code></pre></div></div>
<p>Nodejs</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install -y nodejs
</code></pre></div></div>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-09-24T00:00:00+02:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/09/24/KVM_QEMU-Outils-de-virtualisation.html">KVM/QEMU Outils de virtualisation</a></div><div class="next"><span>SUIVANT</span><a href="/2020/09/28/InfluxDB-Telegraf-Grafana.html">InfluxDB Telegraf Grafana</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>