yannstatic/static/2021/01/11/BlueVPS_VPS_KVM-256_debian_10.html

2759 lines
225 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>BlueVPS VPS KVM-256 debian 10 - YannStatic</title>
<meta name="description" content="256 MB RAM, 10 GB Storage, 1 x vCPU Core, 1 x IPv4 Address, 4 x IPV6 Address">
<link rel="canonical" href="https://static.rnmkcy.eu/2021/01/11/BlueVPS_VPS_KVM-256_debian_10.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;">BlueVPS VPS KVM-256 debian 10</h1></header></div><meta itemprop="headline" content="BlueVPS VPS KVM-256 debian 10"><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=vps">vps</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">11&nbsp;janv.&nbsp;2021</span>
<span title="Modification" style="color:#00FF7F">&nbsp;2&nbsp;mars&nbsp;&nbsp;2021</span></li></ul></div><meta itemprop="datePublished" content="2021-03-02T00:00:00+01:00">
<meta itemprop="keywords" content="vps,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><p><a href="https://www.hostnamaste.com/"><img src="/images/bluevps.png" alt="bluevps" /></a><em>256 MB RAM, 10 GB Storage, 1 x vCPU Core, 1 x IPv4 Address, 4 x IPV6 Address</em></p>
<p><strong>KVM-256</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Produit/Service: BlueVPS Linux - bKVM 256
Domaine: blueyanone
1 x vCPU Core
256 MB RAM
10 GB Storage
Operating System: Debian 10 64bit
IPs primaires
51.210.73.163
IPs assignées
2001:41d0:403:2e5c::4fc6:954f
2001:41d0:403:2e5c::c86b:cf1b
2001:41d0:403:2e5c::e2f3:c904
2001:41d0:403:2e5c::f219:d4d8
Serveurs DNS
ns1
ns2
Location: Strasbourg, FR
</code></pre></div></div>
<h2 id="-debian-10"><img src="/images/debian-buster-logo1.png" alt="Debian Buster" width="100" /> Debian 10</h2>
<p>Connexion ssh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -p 56777 root@51.210.73.163
</code></pre></div></div>
<p>Mise à jour et reboot</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update &amp;&amp; apt -y upgrade
</code></pre></div></div>
<p><strong>Réseau</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip a
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3c:4f:19:80 brd ff:ff:ff:ff:ff:ff
inet 51.210.73.163/32 brd 51.210.73.163 scope global eth0
valid_lft forever preferred_lft forever
inet6 2001:41d0:403:2e5c::f219:d4d8/64 scope global
valid_lft forever preferred_lft forever
inet6 2001:41d0:403:2e5c::e2f3:c904/64 scope global
valid_lft forever preferred_lft forever
inet6 2001:41d0:403:2e5c::c86b:cf1b/64 scope global
valid_lft forever preferred_lft forever
inet6 2001:41d0:403:2e5c::4fc6:954f/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::216:3cff:fe4f:1980/64 scope link
valid_lft forever preferred_lft forever
</code></pre></div></div>
<p><strong>Disques</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>df -h
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Filesystem Size Used Avail Use% Mounted on
udev 102M 0 102M 0% /dev
tmpfs 24M 852K 23M 4% /run
/dev/vda1 9.9G 994M 8.4G 11% /
tmpfs 116M 0 116M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 116M 0 116M 0% /sys/fs/cgroup
tmpfs 24M 0 24M 0% /run/user/0
</code></pre></div></div>
<p><strong>Versions noyau et debian</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uname -a
</code></pre></div></div>
<p>Linux blueyanone 4.19.0-13-amd64 #1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux</p>
<h3 id="création-utilisateur">Création utilisateur</h3>
<p>Utilisateur <strong>wgyan</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /home/wgyan/ -s /bin/bash wgyan
</code></pre></div></div>
<p>Mot de passe <strong>wgyan</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd wgyan
</code></pre></div></div>
<p>Visudo pour les accès root via utilisateur <strong>wgyan</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install sudo
echo "wgyan ALL=(ALL) NOPASSWD: ALL" &gt;&gt; /etc/sudoers
</code></pre></div></div>
<p>Déconnexion “root” puis connexion utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>exit
ssh -p 56777 wgyan@51.210.73.163
</code></pre></div></div>
<p><strong>Hostname</strong> <code class="language-plaintext highlighter-rouge">sudo hostnamectl set-hostname blueyanone</code></p>
<h3 id="-openssh-clé-et-script"><img src="/images/openssh-logo.png" alt="OpenSSH" width="80" /> OpenSSH, clé et script</h3>
<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>wgkvm</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/wgkvm
</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 -P 56777 ~/.ssh/wgkvm.pub wgyan@51.210.73.163:/home/wgyan/
</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 -P 56777 wgyan@51.210.73.163
</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>/wgkvm.pub <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.ssh/authorized_keys
<span class="nb">chmod </span>600 <span class="nv">$HOME</span>/.ssh/authorized_keys <span class="c"># donner les droits</span>
<span class="nb">rm</span> <span class="nv">$HOME</span>/wgkvm.pub <span class="c"># effacer le fichier de la clé </span>
</code></pre></div></div>
<p>Modifier la configuration serveur SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/ssh/sshd_config
</code></pre></div></div>
<p>Modifier</p>
<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Port</span> <span class="m">56777</span>
<span class="n">PermitRootLogin</span> <span class="n">no</span>
<span class="n">PasswordAuthentication</span> <span class="n">no</span>
</code></pre></div></div>
<p><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 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 56777 -i ~/.ssh/wgkvm wgyan@51.210.73.163
</code></pre></div></div>
<h3 id="outils-scripts-motd-et-ssh_rc_bash">Outils, scripts motd et ssh_rc_bash</h3>
<p>Installer utilitaires</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install rsync curl tmux jq figlet git dnsutils tree wget -y
</code></pre></div></div>
<p>Motd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/motd &amp;&amp; sudo nano /etc/motd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> _
__ __ __ __ _ | |____ __ _ __
\ V V // _` || / /\ V /| ' \
\_/\_/ \__, ||_\_\ \_/ |_|_|_|
___ _ ___ _|___/ ____ ____ _ __ ____
| __|/ | |_ )/ | / \ |__ ||__ / / | / / |__ /
|__ \| | _ / / | || () |_ / / |_ \ _ | |/ _ \ |_ \
|___/|_|(_)/___||_| \__/(_)/_/ |___/(_)|_|\___/|___/
</code></pre></div></div>
<p>Script <strong>ssh_rc_bash</strong></p>
<blockquote>
<p><strong>ATTENTION!!! Les scripts sur connexion peuvent poser des problèmes pour des appels externes autres que ssh</strong></p>
</blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://static.xoyaz.xyz/files/ssh_rc_bash
chmod +x ssh_rc_bash # rendre le bash exécutable
./ssh_rc_bash # exécution
</code></pre></div></div>
<p><img src="/images/wgkvm.png" alt="" /></p>
<h2 id="-wireguard"><img src="/images/wireguard_icon.png" alt="wireguard" width="50" /> Wireguard</h2>
<ul>
<li><a href="https://www.wireguard.com/quickstart/">https://www.wireguard.com/quickstart/</a></li>
<li><a href="https://wiki.archlinux.org/index.php/WireGuard">https://wiki.archlinux.org/index.php/WireGuard</a></li>
<li><a href="https://www.cyberciti.biz/faq/ubuntu-20-04-set-up-wireguard-vpn-server/">Procedure: Ubuntu 20.04 set up WireGuard VPN server</a></li>
<li><a href="https://www.cyberciti.biz/faq/how-to-set-up-wireguard-vpn-server-on-alpine-linux/">Alpine Linux set up WireGuard VPN server</a></li>
</ul>
<h3 id="installer-noyau-58">Installer noyau 5.8+</h3>
<p><em>A partir du noyau 5.6 le module wireguard est intégré</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee /etc/apt/sources.list.d/unstable-wireguard.list
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' | sudo tee /etc/apt/preferences.d/limit-unstable
apt update &amp;&amp; apt upgrade
</code></pre></div></div>
<p>Rechercher limage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt search linux-image-5
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>linux-image-5.10.0-1-amd64/unstable 5.10.4-1 amd64
Linux 5.10 for 64-bit PCs (signed)
</code></pre></div></div>
<p>Installer le noyau</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install linux-image-5.10.0-1-amd64
</code></pre></div></div>
<blockquote>
<p><strong>REDEMARRER <code class="language-plaintext highlighter-rouge">systemctl reboot</code></strong></p>
</blockquote>
<p>Connexion SSH</p>
<p>Vérifications <code class="language-plaintext highlighter-rouge">uname -a</code> <br />
<em>Linux blueyanone 5.10.0-1-amd64 #1 SMP Debian 5.10.4-1 (2020-12-31) x86_64 GNU/Linux</em></p>
<p>Supprimer les images non utilisées</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt remove 4.19.0-13-amd64
</code></pre></div></div>
<h3 id="wireguard---base">Wireguard - base</h3>
<p><em>WireGuard est un serveur VPN à code source ouvert, gratuit, moderne et rapide, doté dune cryptographie de pointe. Il est plus rapide et plus simple que lIPSec et lOpenVPN</em></p>
<blockquote>
<p><strong>Toutes les commandes suivantes , en mode su</strong></p>
</blockquote>
<p>Wireguard est dans le noyau 5.6+</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install wireguard
</code></pre></div></div>
<p>**Autoriser le serveur Wireguard à relayer les paquets **</p>
<p>Autoriser le serveur Wireguard à relayer les paquets venant de ces clients vers linternet et de traiter les paquets retours (modifier <strong>/etc/sysctl.conf</strong>)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sed -i 's/^#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sed -i 's/^#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf
sysctl -p # prise en compte immédiate
</code></pre></div></div>
<p>Résultat</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.core.somaxconn = 1024
vm.swappiness = 1
</code></pre></div></div>
<p><strong>Générer une paire de clés</strong></p>
<p>On se positionne dans le dossier <strong>/etc/wireguard/</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/wireguard
</code></pre></div></div>
<p>WireGuard repose sur une authentification par clé publique/privée (cryptographie asymétrique), vous devez donc créer ces clés avec les sous-commandes wg genkey et wg pubkey<br />
La création de la clé privée se fait avec wg genkey et la clé publique est générée en la canalisant dans wg pubkey</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>umask 077; wg genkey | tee wgkvm.key | wg pubkey &gt; wgkvm.pub
</code></pre></div></div>
<p><strong>Générer des clés pour chaque “peer”</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>umask 077; wg genkey | tee peer_B.key | wg pubkey &gt; peer_B.pub
umask 077; wg genkey | tee peer_C.key | wg pubkey &gt; peer_C.pub
umask 077; wg genkey | tee peer_D.key | wg pubkey &gt; peer_D.pub
</code></pre></div></div>
<p>On peut également générer une <strong>clé pré-partagée</strong> pour ajouter une couche supplémentaire de cryptographie à clé symétrique qui sera mélangée à la cryptographie à clé publique déjà existante, pour une résistance post-quantique. Une clé pré-partagée doit être générée pour chaque paire de pairs et ne doit pas être réutilisée. Par exemple, trois pairs interconnectés, A, B, C et D, auront besoin de duatre clés pré-partagées distinctes, une pour chaque paire de pairs.</p>
<p>Le pair “wgkvm” écoutera sur le port UDP 51955 et acceptera la connexion des pairs B, C et D.</p>
<p>Générez une clé pré-partagée pour chaque paire de pairs en utilisant la commande suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>umask 077; wg genpsk &gt; wgkvm-peer_B.psk
umask 077; wg genpsk &gt; wgkvm-peer_C.psk
umask 077; wg genpsk &gt; wgkvm-peer_D.psk
</code></pre></div></div>
<p><strong>Fichier de configuration /etc/wireguard/wg0.conf</strong></p>
<p>Récupérer le nom de la carte réseau <code class="language-plaintext highlighter-rouge">ip a</code> , dans notre cas <strong>eth0</strong></p>
<p>La première étape consiste à choisir une plage IPV4 privée, <a href="https://www.fakeaddresstool.com/random-ipv4-private-generator/">Random IPV4 Private Address Generator</a>, qui sera utilisée par le serveur : <strong>10.55.22.0/8</strong></p>
<p>Pour une adresse IPV6 <a href="https://www.ultratools.com/tools/rangeGenerator">Local IPv6 Address Generator</a> : <strong>fd83:d8a9:3fd8:2e9b::/64</strong></p>
<table>
<thead>
<tr>
<th>Prefix/L</th>
<th>fd</th>
</tr>
</thead>
<tbody>
<tr>
<td>Global ID</td>
<td>83d8a93fd8</td>
</tr>
<tr>
<td>Subnet ID</td>
<td>2e9b</td>
</tr>
<tr>
<td>Combine/CID</td>
<td>fd83:d8a9:3fd8:2e9b::/64</td>
</tr>
<tr>
<td>IPv6 addresses</td>
<td>fd83:d8a9:3fd8:2e9b::/64:XXXX:XXXX:XXXX:XXXX</td>
</tr>
<tr>
<td>Start Range</td>
<td>fd83:d8a9:3fd8:2e9b:0:0:0:0</td>
</tr>
<tr>
<td>End Range</td>
<td>fd83:d8a9:3fd8:2e9b:ffff:ffff:ffff:ffff</td>
</tr>
<tr>
<td>No. of hosts</td>
<td>18446744073709551616</td>
</tr>
</tbody>
</table>
<p>Le serveur aura ladresse IP suivante: 10.55.22.1 . Il est également nécessaire de choisir un port, qui sera exposé publiquement, pour que le serveur écoute.Le port de documentation standard est généralement 51820.</p>
<p>Créer le fichier <strong>/etc/wireguard/wg0.conf</strong> serveur wgkvm</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/wireguard/wg0.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Interface]
Address = 10.55.22.1/24, fd83:d8a9:3fd8:2e9b::/64
ListenPort = 51955
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# wgkvm.key
PrivateKey = 5Z........................................mk=
DNS = 10.55.22.1, fd83:d8a9:3fd8:2e9b::1
[Peer]
# peer_B.pub
PublicKey = X8............................................=
# wgkvm-peer_B.psk
PresharedKey = bf.......................................Ug=
AllowedIPs = 10.55.22.2/32, fd83:d8a9:3fd8:2e9b::2/128
[Peer]
# peer_C.pub
PublicKey = Gl..........................................30=
# wgkvm-peer_C.psk
PresharedKey = +I9.......................................A=
AllowedIPs = 10.55.22.3/32, fd83:d8a9:3fd8:2e9b::3/128
[Peer]
# peer_D.pub
PublicKey = if..........................................Q4=
# wgkvm-peer_D.psk
PresharedKey = WG.......................................CE=
AllowedIPs = 10.55.22.4/32, fd83:d8a9:3fd8:2e9b::4/128
</code></pre></div></div>
<p><strong>Address</strong> , fixer ladresse IP privée du serveur à lintérieur du VPN.Les adresses du réseau VPN de 10.55.22.0 à 10.55.22.255 sont fixées par le masque <strong>/24</strong> et fd83:d8a9:3fd8:2e9b::1 à fd83:d8a9:3fd8:2e9b::ffff sont fixées par le masque <strong>/128</strong><br />
<strong>PostUp</strong> , pour la mise en place des règles iptables de translation dadresses à lactivation du VPN (autoriser le routage des paquets réseau venant des clients vers internet)<br />
<strong>PostDown</strong> , pour la suppression des règles iptables de translation dadresses à larrêt du VPN<br />
<strong>PrivateKey</strong> , clé privée du serveur (wgkvm.key)<br />
<strong>DNS =</strong> Pour utiliser un pair comme serveur DNS, définissez DNS = wireguard_internal_ip_address_of_peer dans la section [Interface]. Les domaines de recherche sont également définis avec loption DNS =. Séparez toutes les valeurs dans la liste par des virgules.
<strong>AllowedIPs =</strong> Pour acheminer tout le trafic du tunnel vers un pair spécifique, ajoutez litinéraire par défaut (0.0.0.0/0 pour IPv4 et ::/0 pour IPv6) à AllowedIPs. Par exemple, AllowedIPs = 0.0.0.0/0, ::/0. wg-quick se chargera automatiquement de configurer le routage correct et fwmark [5] pour que le réseau fonctionne toujours.</p>
<p>Les fichiers des pairs (peers)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/wireguard/wg0.conf # peer_B
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Interface]
Address = 10.55.22.2/32, fd83:d8a9:3fd8:2e9b::2/128
PrivateKey = PEER_B_PRIVATE_KEY
DNS = 10.55.22.1, fd83:d8a9:3fd8:2e9b::1
[Peer]
PublicKey = wgkvm_PUBLIC_KEY wgkvm.pub
PresharedKey = wgkvm-PEER_B-PRESHARED_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 51.210.73.163:51955
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/wireguard/wg0.conf # peer_C
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Interface]
Address = 10.55.22.3/32, fd83:d8a9:3fd8:2e9b::3/128
PrivateKey = PEER_B_PRIVATE_KEY
DNS = 10.55.22.1, fd83:d8a9:3fd8:2e9b::1
[Peer]
PublicKey = wgkvm_PUBLIC_KEY
PresharedKey = wgkvm-PEER_B-PRESHARED_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 51.210.73.163:51955
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/wireguard/wg0.conf # peer_D
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Interface]
Address = 10.55.22.4/32, fd83:d8a9:3fd8:2e9b::4/128
PrivateKey = PEER_B_PRIVATE_KEY
DNS = 10.55.22.1, fd83:d8a9:3fd8:2e9b::1
[Peer]
PublicKey = wgkvm_PUBLIC_KEY
PresharedKey = wgkvm-PEER_B-PRESHARED_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 51.210.73.163:51955
</code></pre></div></div>
<p>Modifier les droits des fichiers <strong>wg0.conf</strong> (lecture uniquement par “root”)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 600 /etc/wireguard/wg0.conf
</code></pre></div></div>
<h3 id="-dns-unbound"><img src="/images/unbound-250.png" alt="" width="100" /> DNS Unbound</h3>
<p>Un problème majeur avec beaucoup de configurations VPN est que le DNS nest pas suffisant. Cela finit par une fuite de connexion client et de détails demplacement. Un bon moyen de tester cela est à travers le site <a href="http://dnsleak.com/">http://dnsleak.com/</a></p>
<p>Nous allons sécuriser le trafic DNS avec la solution <strong>unbound</strong> qui offre les caractéristiques suivantes</p>
<ul>
<li>Léger et rapide</li>
<li>Facile à installer et à configurer</li>
<li>Orienté sécurité</li>
<li>Prise en charge DNSSEC</li>
</ul>
<p>Nous allons le configurer de manière à contrer les fuites DNS, les attaques plus sophistiquées comme la fausse configuration de proxy, les routeurs escrocs et toutes sortes dattaques MITM sur HTTPS et autres protocoles.</p>
<p>Nous installons unbound sur le serveur <br />
Passage en mode super utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s # ou su
</code></pre></div></div>
<blockquote>
<p>ATTENTION : Le programme <strong>resolvconf</strong> est en général seulement nécessaire quand un système a plusieurs programmes qui ont besoin de modifier de façon dynamique les informations sur les serveurs de noms de domaine. Sur un système simple où les serveurs de noms de domaine ne changent pas souvent ou bien ne sont modifiés que par un programme, le <u>fichier de configuration **resolv.conf** est suffisant</u>.<br />
Il faut installer <strong>resolvconf</strong>, sinon on a une erreur <strong>unbound-resolvconf</strong><br />
Une fois le paquet « <strong>resolvconf</strong> » installé, <u>il ne faut plus modifier le fichier</u> « <strong>/etc/resolv.conf</strong> », car le contenu de celui-ci sera automatiquement géré et remplacé par « <strong>resolvconf</strong> ».</p>
</blockquote>
<p>Installation des outils dns, des paquets Unbound et resolv :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install unbound unbound-host resolvconf -y
</code></pre></div></div>
<p>Téléchargement de la liste des serveurs DNS racines</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
chown unbound:unbound /var/lib/unbound/root.hints
</code></pre></div></div>
<p>Ajout dun fichier de configuration <strong>dns-KVM-256.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/unbound/unbound.conf.d/dns-KVM-256.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server:
num-threads: 4
# enable logs
verbosity: 0 # no verbosity, only errors
# liste des serveurs DNS racine
root-hints: "/var/lib/unbound/root.hints"
# Répondre aux requêtes DNS sur toutes les interfaces
interface: 0.0.0.0 # 0.0.0.0 unbound sur plusieurs interfaces
interface: ::0
max-udp-size: 3072
# IPs authorised to access the DNS Server
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.55.22.0/16 allow
access-control: ::0/0 refuse
access-control: ::1 allow
access-control: fe80::/10 allow
access-control: fd83:d8a9:3fd8:2e9b::/48 allow
local-zone: "55.10.in-addr.arpa." transparent
#hide DNS Server info
hide-identity: yes
hide-version: yes
# limit DNS fraud and use DNSSEC
harden-glue: yes
harden-dnssec-stripped: yes
harden-referral-path: yes
# add an unwanted reply threshold to clean the cache and avoid, when possible, DNS poisoning
unwanted-reply-threshold: 10000000
# have the validator print validation failures to the log
val-log-level: 1
# minimum lifetime of cache entries in seconds
cache-min-ttl: 1800
# maximum lifetime of cached entries in seconds
cache-max-ttl: 14400
prefetch: yes
prefetch-key: yes
#include: /etc/unbound/unbound.conf.d/adslist.txt
</code></pre></div></div>
<p>Droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R unbound:unbound /var/lib/unbound
</code></pre></div></div>
<p>Pour vérifier si le fichier de configuration est valide</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unbound-checkconf /etc/unbound/unbound.conf.d/dns-KVM-256.conf
</code></pre></div></div>
<p><em>unbound-checkconf: no errors in /etc/unbound/unbound.conf.d/dns-KVM-256.conf</em><br />
Désactiver systemd-resolved (si utilisé)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl stop systemd-resolved
systemctl disable systemd-resolved
</code></pre></div></div>
<p>Activer Unbound (ILS SONT ACTIFS DES LEUR INSTALLATION)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl enable unbound-resolvconf
systemctl enable unbound
</code></pre></div></div>
<blockquote>
<p><strong>Redémarrer le serveur <code class="language-plaintext highlighter-rouge">systemctl reboot</code></strong></p>
</blockquote>
<p>Après redémarrage et connexion au serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl status unbound unbound-resolvconf resolvconf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● unbound.service - Unbound DNS server
Loaded: loaded (/lib/systemd/system/unbound.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2021-01-09 15:28:16 UTC; 6min ago
Docs: man:unbound(8)
Process: 433 ExecStartPre=/usr/lib/unbound/package-helper chroot_setup (code=exited, status=0/SUCCESS)
Process: 439 ExecStartPre=/usr/lib/unbound/package-helper root_trust_anchor_update (code=exited, status=0/SUCCESS)
Main PID: 444 (unbound)
Tasks: 4 (limit: 234)
Memory: 25.0M
CGroup: /system.slice/unbound.service
└─444 /usr/sbin/unbound -d
● unbound-resolvconf.service - Unbound DNS server via resolvconf
Loaded: loaded (/lib/systemd/system/unbound-resolvconf.service; enabled; vendor preset: enabled)
Active: active (exited) since Sat 2021-01-09 15:28:16 UTC; 6min ago
Process: 449 ExecStart=/usr/lib/unbound/package-helper resolvconf_start (code=exited, status=0/SUCCESS)
Main PID: 449 (code=exited, status=0/SUCCESS)
● resolvconf.service - Nameserver information manager
Loaded: loaded (/lib/systemd/system/resolvconf.service; enabled; vendor preset: enabled)
Active: active (exited) since Sat 2021-01-09 15:28:12 UTC; 6min ago
Docs: man:resolvconf(8)
Process: 158 ExecStartPre=/bin/mkdir -p /run/resolvconf/interface (code=exited, status=0/SUCCESS)
Process: 170 ExecStartPre=/bin/touch /run/resolvconf/postponed-update (code=exited, status=0/SUCCESS)
Process: 178 ExecStart=/sbin/resolvconf --enable-updates (code=exited, status=0/SUCCESS)
Main PID: 178 (code=exited, status=0/SUCCESS)
</code></pre></div></div>
<p><strong>Créer un lien</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/resolv.conf
sudo ln -s /etc/resolvconf/run/resolv.conf /etc/resolv.conf
</code></pre></div></div>
<p><strong>Vérifications</strong></p>
<p>Les commandes suivantes ne fonctionneront que si le paquet “dnsutils” est installé sur votre système Debian!</p>
<p>On teste en utilisant les serveurs DNS locaux</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig @127.0.0.1 afnic.fr +short +dnssec
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>192.134.5.37
A 13 2 600 20210205065724 20210106120632 31668 afnic.fr. TaZQ2+Sm2ujp+uTqGyxz2EXMo2/UnZsqVUnsiH5/sXixeqJJ/rczjDlu wrFJ/hRuHFoPowssiGjVhOvzk61SPQ==
</code></pre></div></div>
<p><strong>Mise à jour des serveurs DNS racines</strong></p>
<p>Télécharger le script</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -o /etc/unbound/dnsunbound-update-root-dns.sh https://static.xoyaz.xyz/files/dnsunbound-update-root-dns.sh
</code></pre></div></div>
<p>Droits en exécution pour le bash <strong>dnsunbound-update-root-dns.sh</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x /etc/unbound/dnsunbound-update-root-dns.sh
</code></pre></div></div>
<p>Planification journalière</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
</code></pre></div></div>
<p>Ajouter en fin de fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Mise à jour automatique des serveurs DNS de la racine
10 02 * * * /etc/unbound/dnsunbound-update-root-dns.sh &gt; /dev/null
</code></pre></div></div>
<h3 id="-parefeu"><img src="/images/ufw-logo1.png" alt="ufw" width="50" /> Parefeu</h3>
<p><em>UFW, ou pare - feu simple , est une interface pour gérer les règles de pare-feu dans Arch Linux, Debian ou Ubuntu. UFW est utilisé via la ligne de commande (bien quil dispose dinterfaces graphiques disponibles), et vise à rendre la configuration du pare-feu facile (ou simple).</em></p>
<p>Installation <strong>Debian / Ubuntu</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install ufw
</code></pre></div></div>
<p><em>Par défaut, les jeux de règles dUFW sont vides, de sorte quil napplique aucune règle de pare-feu, même lorsque le démon est en cours dexécution.</em></p>
<p>Les règles</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ufw allow 56777/tcp # port SSH
sudo ufw allow DNS # port 53
sudo ufw allow 51955/udp # wireguard
</code></pre></div></div>
<p>Activer le parefeu</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ufw enable
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
</code></pre></div></div>
<p>Status</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo ufw status verbose
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
56777/tcp ALLOW IN Anywhere
53 (DNS) ALLOW IN Anywhere
51955/udp ALLOW IN Anywhere
56777/tcp (v6) ALLOW IN Anywhere (v6)
53 (DNS (v6)) ALLOW IN Anywhere (v6)
51955/udp (v6) ALLOW IN Anywhere (v6)
</code></pre></div></div>
<h3 id="tester-wireguard">Tester wireguard</h3>
<p>Sur le serveur et le client wireguard (en mode su)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/wireguard
</code></pre></div></div>
<p><strong>Serveur wireguard</strong></p>
<p>Lancement wireguard</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wg-quick up wg0
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.55.22.1/24 dev wg0
[#] ip -6 address add fd83:d8a9:3fd8:2e9b::1/64 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a tun.wg0 -m 0 -x
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</code></pre></div></div>
<p>Vérifications</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wg show
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>interface: wg0
public key: xl4qS/t+XxyvWo/xlsdMvl7OYkcttE/yW+TIx+Wl4ys=
private key: (hidden)
listening port: 51955
peer: jHohx9BNYllm56TvzclhUUsy2RukVvrpB4PB970ddhs=
preshared key: (hidden)
allowed ips: 10.55.22.2/32, fd83:d8a9:3fd8:2e9b::2/128
peer: eLrpg8FmGMsHRMs9l5D0T3TpJsZ2Zwh8hQrDHgVIXig=
preshared key: (hidden)
allowed ips: 10.55.22.3/32, fd83:d8a9:3fd8:2e9b::3/128
peer: 7Z4aeRL7N9neaZMmb88/ZWjE2Q02hm7vJuMsmL7BgwY=
preshared key: (hidden)
allowed ips: 10.55.22.4/32, fd83:d8a9:3fd8:2e9b::4/128
</code></pre></div></div>
<p><strong>Client wireguard</strong></p>
<p>Lancement wireguard</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wg-quick up wg0
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.55.22.2/32 dev wg0
[#] ip -6 address add fd83:d8a9:3fd8:2e9b::2/128 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -6 route add ::/0 dev wg0 table 51820
[#] ip -6 rule add not fwmark 51820 table 51820
[#] ip -6 rule add table main suppress_prefixlength 0
[#] ip6tables-restore -n
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] iptables-restore -n
</code></pre></div></div>
<p>Vérifications</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip a show wg0
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wg0: &lt;POINTOPOINT,NOARP,UP,LOWER_UP&gt; mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.55.22.2/32 scope global wg0
valid_lft forever preferred_lft forever
inet6 fd83:d8a9:3fd8:2e9b::2/128 scope global
valid_lft forever preferred_lft forever
</code></pre></div></div>
<p>DNS V4 V6</p>
<p>Les commandes <code class="language-plaintext highlighter-rouge">dig @10.55.22.1 afnic.fr +short +dnssec</code> et <code class="language-plaintext highlighter-rouge">dig @fd83:d8a9:3fd8:2e9b::1 afnic.fr +short +dnssec</code> donnent le résultat suivant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A 13 2 600 20210120124535 20201221100316 31668 afnic.fr. HZhLWz7CHV/aeLoxBVrqFM1mWQHPBt+OOMEJtJod7r7lKxEbGGT2+WB2 W1FZ3D4jT1K+1dyRpTJXgmo13u8P0Q==
</code></pre></div></div>
<p><strong>Activer wireguard</strong><br />
Pour une activation permanente de wireguard serveur et client</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start wg-quick@wg0.service
sudo systemctl enable wg-quick@wg0.service
</code></pre></div></div>
<h3 id="wireguard-web-manager">Wireguard web manager</h3>
<p>Prérequis :</p>
<ul>
<li><a href="/2021/01/29/Debian_installer_Go+Node.html">Debian installer Go + Node</a></li>
<li>Installer la version compilée de wg-gen-web → <code class="language-plaintext highlighter-rouge">/opt/appwg/</code></li>
</ul>
<p>Arrêter wg-quick : <code class="language-plaintext highlighter-rouge">sudo systemctl stop wg-quick@wg0.service</code><br />
Déplacer le dossier <code class="language-plaintext highlighter-rouge">sudo mv /etc/wireguard ~/wireguard.sav</code></p>
<p>Créer le dossier wireguard et copier le fichier <code class="language-plaintext highlighter-rouge">wg0.conf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /etc/wireguard
sudo cp ~/wireguard.sav/wg0.conf /etc/wireguard/
</code></pre></div></div>
<p>Créer un fichier <code class="language-plaintext highlighter-rouge">/etc/wireguard/server.json</code> à lidentique du fichier wg0.conf</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"address"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"fd18:2941:0ae9:7d96::1/64"</span><span class="p">,</span><span class="w">
</span><span class="s2">"10.14.94.1/24"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"listenPort"</span><span class="p">:</span><span class="w"> </span><span class="mi">51820</span><span class="p">,</span><span class="w">
</span><span class="nl">"mtu"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"privateKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UEQCgh/6a2RQbF9+qqylVjqLCK/mRwqRPc/4vjRsYXg="</span><span class="p">,</span><span class="w">
</span><span class="nl">"publicKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0s1wsNpuU1RlKgj6AmoN0aKUeb+aESByhO3yTSnfTyE="</span><span class="p">,</span><span class="w">
</span><span class="nl">"endpoint"</span><span class="p">:</span><span class="w"> </span><span class="s2">"51.210.73.163:51820"</span><span class="p">,</span><span class="w">
</span><span class="nl">"persistentKeepalive"</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span><span class="w">
</span><span class="nl">"dns"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"fd18:2941:0ae9:7d96::1"</span><span class="p">,</span><span class="w">
</span><span class="s2">"10.14.94.1"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"allowedips"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"0.0.0.0/0"</span><span class="p">,</span><span class="w">
</span><span class="s2">"::/0"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"preUp"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="nl">"postUp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE"</span><span class="p">,</span><span class="w">
</span><span class="nl">"preDown"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="nl">"postDown"</span><span class="p">:</span><span class="w"> </span><span class="s2">"iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE"</span><span class="p">,</span><span class="w">
</span><span class="nl">"updatedBy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Unknown"</span><span class="p">,</span><span class="w">
</span><span class="nl">"created"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-10-21T12:31:50.589913433Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"updated"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-10-21T12:31:50.589913433Z"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Configuration .env</p>
<p>lautorisation à 2 facteurs nest pas utilisée, le fichier /opt/appwg/.env se résume à remplir la zone correspondante SMTP de la messagerie et désactiver lautorisation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/appwg/.env
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># IP address to listen to
SERVER=127.0.0.1
# port to bind
PORT=8080
# Gin framework release mode
GIN_MODE=release
# where to write all generated config files
WG_CONF_DIR=/etc/wireguard
# WireGuard main config file name, generally &lt;interface name&gt;.conf
WG_INTERFACE_NAME=wg0.conf
# SMTP settings to send email to clients
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=account@gmail.com
SMTP_PASSWORD=*************
SMTP_FROM=Wg Gen Web &lt;account@gmail.com&gt;
# set provider name to fake to disable auth, also the default
OAUTH2_PROVIDER_NAME=fake
</code></pre></div></div>
<p>Créer un service systemd wgweb qui lance le serveur avec journalisation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/wgweb.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Wireguard web
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10
WorkingDirectory=/opt/appwg
ExecStart=/opt/appwg/deb-wg-gen-web
[Install]
WantedBy=multi-user.target
</code></pre></div></div>
<p>Recharger systemd puis démarrer le service:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
sudo systemctl start wgweb.service
sudo systemctl status wgweb.service
</code></pre></div></div>
<p>Relancer le service wireguard</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start wg-quick@wg0.service
</code></pre></div></div>
<p><strong>Configurer automatiquement wireguard après création ou modification des clients ou du paramétrage serveur</strong></p>
<p>Utilisation de <strong>systemd.path</strong> monitor pour les changements dans le répertoire, voir <a href="https://www.freedesktop.org/software/systemd/man/systemd.path.html">systemd doc</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/systemd/system/wg-gen-web.path
</code></pre></div></div>
<pre><code class="language-init">[Unit]
Description=Surveiller /etc/wireguard pour les changements
[Path]
PathModified=/etc/wireguard
[Install]
WantedBy=multi-user.target
</code></pre>
<p>Ce <strong>wg-gen-web.path</strong> activera le fichier de lunité avec le même nom, <strong>wg-gen-web.service</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/systemd/system/wg-gen-web.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Relancer WireGuard si changements
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart wg-quick@wg0.service
[Install]
WantedBy=multi-user.target
</code></pre></div></div>
<p>Ce qui permettra de relancer le service WireGuard</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start wg-gen-web.path
sudo systemctl status wg-gen-web.path
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● wg-gen-web.path - Surveiller /etc/wireguard pour les changements
Loaded: loaded (/etc/systemd/system/wg-gen-web.path; disabled; vendor preset: enabled)
Active: active (waiting) since Wed 2020-10-21 11:00:47 CEST; 20ms ago
Oct 21 11:00:47 debian-cx11 systemd[1]: Started Surveiller /etc/wireguard pour les changements.
</code></pre></div></div>
<p>Activation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable wg-gen-web.path
</code></pre></div></div>
<p>Pour suivre dans le journal</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -t wg-quick
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#]
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] ip link add wg0 type wireguard
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] wg setconf wg0 /dev/fd/63
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] ip -6 address add fd5c:ecbe:9c7c:dd5e::1/64 dev wg0
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] ip -4 address add 10.22.1.1/24 dev wg0
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] ip link set mtu 1420 up dev wg0
Jan 30 07:48:24 nsdyanone wg-quick[1825]: [#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</code></pre></div></div>
<h3 id="web-wireguard-via-ssh">Web Wireguard via SSH</h3>
<p>On utilise la redirection port SSH<br />
Vérification,ouvrir un terminal sur le client linux qui dispose des clés ssh et lancer la commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 9000:localhost:8080 wgyan@51.210.73.163 -p 56777 -i /home/yann/.ssh/wgkvm
</code></pre></div></div>
<p>Ouvrir un navigateur sur le client et saisir localhost:9000 pour afficher le gestionnaire web de wireguard
Activer le service si tout fonctionne</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable wgweb.service
</code></pre></div></div>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2021-01-11T00:00:00+01: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="/2021/01/10/Hostnamaste_VPS_KVM-256_debian_10.html">Hostnamaste VPS KVM-256 debian 10 - nsdyanone</a></div><div class="next"><span>SUIVANT</span><a href="/2021/01/18/InfluxDB-Telegraf-Grafana-NEW.html">InfluxDB Telegraf Grafana NEW</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>