yannstatic/static/2019/12/28/VirtualBox(virtualisation-linux)-serveur-xoyize.xyz(ex_PC2)-debian.html

2717 lines
226 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>VirtualBox sur serveur xoyize.xyz (srvxo, ex PC2) + Machine virtuelle yunohost ouestline.net - YannStatic</title>
<meta name="description" content="">
<link rel="canonical" href="https://static.rnmkcy.eu/2019/12/28/VirtualBox(virtualisation-linux)-serveur-xoyize.xyz(ex_PC2)-debian.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;">VirtualBox sur serveur xoyize.xyz (srvxo, ex PC2) + Machine virtuelle yunohost ouestline.net</h1></header></div><meta itemprop="headline" content="VirtualBox sur serveur xoyize.xyz (srvxo, ex PC2) + Machine virtuelle yunohost ouestline.net"><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=virtuel">virtuel</a>
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">28&nbsp;déc.&nbsp;&nbsp;2019</span>
<span title="Modification" style="color:#00FF7F">20&nbsp;févr.&nbsp;2020</span></li></ul></div><meta itemprop="datePublished" content="2020-02-20T00:00:00+01:00">
<meta itemprop="keywords" content="virtuel"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><p><img src="/images/virtualbox6-logo.png" alt="image" width="200px" /></p>
<h2 id="virtualbox-on-headless-server">VirtualBox on Headless Server</h2>
<p><em>Installer virtualBox sur un serveur sans carte graphique</em></p>
<ul>
<li><a href="https://www.ostechnix.com/install-oracle-virtualbox-ubuntu-16-04-headless-server/">How to Install Oracle VirtualBox On Ubuntu 18.04.2 LTS Headless Server</a></li>
<li><a href="https://www.tecmint.com/install-virtualbox-on-debian-10/">How to Install VirtualBox 6 on Debian 10</a></li>
<li><a href="https://vorkbaard.nl/how-to-set-up-a-virtualbox-server-in-debian-9-web-interface-autostart-backup/">How to set up a VirtualBox server in Debian 9: web interface, autostart, backup</a></li>
<li><a href="https://www.howtoforge.com/managing-a-headless-virtualbox-installation-with-phpvirtualbox-on-nginx-ubuntu-12.04">Managing A Headless VirtualBox Installation With phpvirtualbox On nginx (Ubuntu 12.04)</a></li>
<li><a href="https://vorkbaard.nl/how-to-set-up-a-virtualbox-server-in-debian-9-web-interface-autostart-backup/">How to set up a VirtualBox server in Debian 9: web interface, autostart, backup</a></li>
</ul>
<p>VirtualBox 6.0 est la dernière version majeure publiée par léquipe Oracle. Cette version est publiée avec diverses améliorations de performances par rapport aux versions majeures précédentes. Cet article vous aide à installer VirtualBox sur le système Debian 10 Buster Linux.</p>
<h3 id="prérequis">Prérequis</h3>
<p>Connectez-vous à votre système de bureau Debian 10 Buster Linux avec les privilèges sudo utilisateur. Mettez ensuite à jour les packages actuellement installés sur votre système. Pour ce faire, exécutez simplement les commandes suivantes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
sudo apt upgrade
sudo apt install build-essential dkms unzip wget
</code></pre></div></div>
<blockquote>
<p>Un redémarrage de la machine est nécessaire <code class="language-plaintext highlighter-rouge">sudo systemctl reboot</code></p>
</blockquote>
<h3 id="configuration-du-référentiel-apt">Configuration du référentiel Apt</h3>
<p>Maintenant, importez la clé publique Oracle sur votre système, qui a signé les paquets Debian. Vous pouvez ajouter ces clés à laide des commandes suivantes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget --no-check-certificate -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
wget --no-check-certificate -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
</code></pre></div></div>
<blockquote>
<p>Loption <code class="language-plaintext highlighter-rouge">--no-check-certificate</code> est obligatoire sinon erreur <strong>gpg: aucune donnée OpenPGP valable na été trouvée.</strong></p>
</blockquote>
<p>Configurez ensuite le référentiel apt sur votre système Debian 10 Buster. Cette commande ajoutera une entrée au fichier /etc/apt/sources.list à la fin du fichier.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo add-apt-repository "deb http://download.virtualbox.org/virtualbox/debian buster contrib"
</code></pre></div></div>
<h3 id="installer-virtualbox-sur-debian-10">Installer VirtualBox sur Debian 10</h3>
<p>Après avoir terminé les étapes ci-dessus, installons VirtualBox à laide des commandes suivantes. Si vous avez déjà installé une ancienne version de VirtualBox, la commande ci-dessous la mettra à jour automatiquement.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
sudo apt install virtualbox-6.0
</code></pre></div></div>
<p>Ajout dutilisateurs au groupe VirtualBox</p>
<p>Nous devons créer et ajouter notre utilisateur système au groupe <strong>vboxusers</strong> . Vous pouvez soit créer un utilisateur distinct et laffecter au groupe vboxusers, soit utiliser lutilisateur existant.</p>
<p><u>Créer un utilisateur *vbox*</u> <br />
Configurer un compte pour VirtualBox afin quil ne fonctionne pas en tant que root.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd -d /home/vbox -m -g vboxusers -s /bin/bash vbox
sudo passwd vbox
</code></pre></div></div>
<p><u>Utilisateur existant</u><br />
Exécuter la commande suivante pour lajouter au groupe vboxusers.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -aG vboxusers $USER
</code></pre></div></div>
<blockquote>
<p>Veuillez noter que si vous utilisez un utilisateur distinct pour virtualbox, vous devez vous déconnecter et vous connecter à cet utilisateur particulier et effectuer les autres étapes.</p>
</blockquote>
<p>Maintenant, exécutez la commande suivante pour vérifier si les modules du noyau de virtualbox sont chargés ou non.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl status vboxdrv
</code></pre></div></div>
<p>Comme vous pouvez le voir dans la capture décran ci-dessus, le module vboxdrv est chargé et fonctionne!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● vboxdrv.service - VirtualBox Linux kernel module
Loaded: loaded (/usr/lib/virtualbox/vboxdrv.sh; enabled; vendor preset: enabled)
Active: active (exited) since Fri 2019-12-20 08:19:49 CET; 3min 1s ago
Tasks: 0 (limit: 4915)
Memory: 0B
CGroup: /system.slice/vboxdrv.service
déc. 20 08:19:49 xoyize.xyz systemd[1]: Starting VirtualBox Linux kernel module...
déc. 20 08:19:49 xoyize.xyz vboxdrv.sh[13280]: vboxdrv.sh: Starting VirtualBox services.
déc. 20 08:19:49 xoyize.xyz systemd[1]: Started VirtualBox Linux kernel module.
</code></pre></div></div>
<h3 id="installer-le-pack-dextension-virtualbox">Installer le pack dextension VirtualBox</h3>
<ul>
<li><a href="https://kifarunix.com/install-virtualbox-extension-pack-on-virtualbox-6-0/">Install VirtualBox Extension Pack on VirtualBox 6.0</a></li>
</ul>
<p>Le pack dextension VirtualBox fournit les fonctionnalités suivantes aux invités VirtualBox.</p>
<ul>
<li>Le périphérique USB 2.0 virtuel (EHCI)</li>
<li>Prise en charge de VirtualBox Remote Desktop Protocol (VRDP)</li>
<li>Passthrough webcam hôte</li>
<li>ROM de démarrage Intel PXE</li>
<li>Prise en charge expérimentale du passthrough PCI sur les hôtes Linux</li>
</ul>
<p>Vérifier la version</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vboxmanage --version
# 6.0.14r133895
</code></pre></div></div>
<p>Téléchargez ici le dernier pack dextension pour VirtualBox 6.0.x.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://download.virtualbox.org/virtualbox/6.0.14/Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack
</code></pre></div></div>
<p>Installez le pack dextension à laide de la commande:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack
</code></pre></div></div>
<p>Successfully installed “Oracle VM VirtualBox Extension Pack”.</p>
<p>Nous avons installé avec succès Oracle VirtualBox avec pack dextension dans le serveur Ubuntu 18.04 LTS. Il est temps de déployer des machines virtuelles. Reportez-vous au <a href="http://www.virtualbox.org/manual/ch08.html">guide officiel de virtualbox</a> pour commencer à créer et gérer des machines virtuelles en ligne de commande.</p>
<h3 id="créerdémarrer-une-machine-virtuelle-en-ligne-de-commande">Créer/démarrer une machine virtuelle en ligne de commande</h3>
<blockquote>
<p>Lutilisateur “vbox” est seul autorisé à gérer virtualbox , il faut précéder les commandes de <code class="language-plaintext highlighter-rouge">sudo -u vbox</code></p>
</blockquote>
<ul>
<li><a href="/files/html/How to Manage Oracle VirtualBox Virtual Machines from Command Line.htm">How to Manage Oracle VirtualBox Virtual Machines from Command Line-Lien HS</a></li>
<li><a href="https://docs.oracle.com/cd/E97728_01/E97727/html/vboxmanage.html">VBoxManage (User Manual for Release 6.0)</a></li>
</ul>
<p>On se connecte sur le serveur qui héberge VirtualBox via SSH</p>
<p>Liste des machines virtuelles sur le serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u vbox VBoxManage list vms
</code></pre></div></div>
<p>“debian9” {bbe16841-97ac-4ff8-85e3-d6c9dc0ce470}</p>
<p>Si lextension daffichage à distance VirtualBox na pas été activée, la procédure peut être répétée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u vbox VBoxManage modifyvm "debian9" --vrde on
</code></pre></div></div>
<p>Il y a une machine virtuelle nommée “debian9”.<br />
Le mode Headless peut être activé par la suite de deux manières :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u vbox VBoxHeadless -s debian9
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Oracle VM VirtualBox Headless Interface 4.1.8
(C) 2008-2019 Oracle Corporation
Tous droits réservés.
Le serveur VRDE est à l'écoute sur le port 3389.
</code></pre></div></div>
<p>ou :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage startvm ubuntu-server --type headless
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Attendre que la VM "ubuntu-server" s'allume...
La VM "ubuntu-server" a été démarrée avec succès.
</code></pre></div></div>
<p>La machine virtuelle est maintenant en cours dexécution sans affichage<br />
A la place, on se connecte à la machine par RDP ou SSH (en supposant que les configurations réseau et SSH correspondantes existent).</p>
<h2 id="phpvirtualbox-virtualbox-web-vmxoyizexyz">phpVirtualBox (VirtualBox web vm.xoyize.xyz)</h2>
<ul>
<li>Créer et gérer des machines virtuelles graphiquement avec <a href="https://github.com/phpvirtualbox/phpvirtualbox">phpVirtualBox</a></li>
<li><a href="https://github.com/phpvirtualbox/phpvirtualbox/wiki/vboxweb-service-Configuration-in-Linux">vboxweb service Configuration in Linux</a></li>
</ul>
<p><em>PhpVirtualBox est un frontal gratuit basé sur le Web pour Oracle VirtualBox. Il est écrit en langage PHP. En utilisant phpVirtualBox, nous pouvons facilement créer, supprimer, gérer et administrer des machines virtuelles via un navigateur Web à partir de nimporte quel système distant sur le réseau.</em></p>
<p>Nous utilisons un logiciel libre de serveur Web (ou HTTP) <strong>nginx</strong></p>
<h3 id="installer">Installer</h3>
<p>Installer phpVirtualBox</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/phpvirtualbox/phpvirtualbox.git
sudo mv phpvirtualbox /var/www/phpvirtualbox
</code></pre></div></div>
<p>Configurer phpVirtualBox.</p>
<p>Copiez lexemple de fichier de configuration comme indiqué ci-dessous.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cp /var/www/phpvirtualbox/config.php-example /var/www/phpvirtualbox/config.php
</code></pre></div></div>
<p>Editez le fichier config.php de phpVirtualBox:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /var/www/phpvirtualbox/config.php
</code></pre></div></div>
<p>Recherchez les lignes suivantes et remplacez le nom dutilisateur et le mot de passe</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* Username / Password for system user that runs VirtualBox */
var $username = 'vbox';
var $password = 'pass';
/* Default language. See languages folder for more language options.
* Can also be changed in File -&gt; Preferences -&gt; Language in
* phpVirtualBox.
*/
var $language = 'fr';
</code></pre></div></div>
<blockquote>
<p>Remplacer pass par le mot de passe</p>
</blockquote>
<p>Créer un nouveau fichier appelé <strong>/etc/default/virtualbox</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/default/virtualbox
</code></pre></div></div>
<p>Ajoutez la ligne suivante.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBOXWEB_USER = vbox
VBOXWEB_HOST=127.0.0.1
</code></pre></div></div>
<h3 id="vhost-vmxoyizexyz-authentification-par-certificat-client">Vhost vm.xoyize.xyz (authentification par certificat client)</h3>
<p>Créer le vhost nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/vm.xoyize.xyz.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/nginx/conf.d/vm.xoyize.xyz.conf
##
# Virtual Host vm.xoyize.xyz (phpVirtualbox)
##
server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name vm.xoyize.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name vm.xoyize.xyz;
include ssl_dh_headers_ocsp;
# Authentification par certificat client
include auth_certificat_client;
root /var/www/phpvirtualbox;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
access_log /var/log/nginx/phpvirtualbox-access.log;
error_log /var/log/nginx/phpvirtualbox-error.log;
}
</code></pre></div></div>
<p>Il faut installer le module PHP SOAP extension</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install php7.3-soap
</code></pre></div></div>
<p>Redémarrer les services PHP et nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart php7.3-fpm
sudo systemctl restart nginx
</code></pre></div></div>
<p>Enfin, redémarrez votre système ou redémarrez simplement les services suivants pour terminer la configuration.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart vboxweb-service
sudo systemctl restart vboxdrv
</code></pre></div></div>
<p>Accéder à la console Web phpVirtualBox https://vm.xoyize.xyz</p>
<p><img src="/images/vm001.png" alt="" width="600" /><br />
Entrez les informations didentification de lutilisateur administratif phpVirtualBox.<br />
Le nom dutilisateur par défaut et phpVirtualBox est admin / admin .</p>
<h3 id="récupération-du-mot-de-passe">Récupération du mot de passe</h3>
<p>Vous pouvez réinitialiser le mot de passe admin en renommant le fichier <strong>recovery.php-disabled</strong> dans le dossier de phpVirtualBox en <strong>recovery.php</strong> et en y accédant dans votre navigateur Web. Par exemple <em>http://HOST-OR-IP/phpvirtualbox/recovery.php</em></p>
<p>Cette page vous présente un formulaire simple. Cliquez sur le bouton Récupérer pour réinitialiser le mot de passe de lutilisateur <em>admin</em> à la valeur par défaut de <em>admin</em>. Si vous avez supprimé le compte administrateur, il sera recréé.</p>
<p>Une fois cela fait, renommez <strong>recovery.php</strong> en <strong>recovery.php-disabled</strong>. phpVirtualBox refusera de fonctionner tant que recovery.php existera. Vous pouvez alors vous connecter avec les identifiants par défaut de admin / admin.</p>
<h3 id="désactivation-de-lauthentification-par-mot-de-passe">Désactivation de lauthentification par mot de passe</h3>
<blockquote>
<p>Désactivation de lauthentification par mot de passe car on utilise une authentification par <strong>certificat client</strong></p>
</blockquote>
<p>Si vous voulez désactiver lauthentification dans <em>phpVirtualBox</em>, ajoutez la ligne suivante dans le fichier <strong>config.php</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var $noAuth = true ;
</code></pre></div></div>
<p>Une fois que cela est fait, aucun nom dutilisateur / mot de passe ne sera nécessaire pour accéder à phpVirtualBox. De plus, les sections de phpVirtualBox relatives à lauthentification (changement de mot de passe, utilisateurs, etc.) ne seront pas visibles.</p>
<h3 id="créerdémarrer-une-machine-virtuelle-via-phpvirtualbox">Créer/démarrer une machine virtuelle via phpvirtualbox</h3>
<p>Après avoir créé une machine , activé “le bureau à distance” port 3389 puis démarré</p>
<p><img src="/images/phpvbox001.png" alt="" width="500" /></p>
<h3 id="accès-aux-machines-virtuelles-en-mode-console-rdp">Accès aux machines virtuelles en mode console (RDP)</h3>
<ul>
<li><a href="http://www.virtualbox.org/manual/ch07.html#idp8971072">Remote virtual machines: Remote display (VRDP support)</a> (Oracle VM VirtualBox User Manual, Chapter 7)</li>
<li>Pour pouvoir utiliser VRPDP, le <a href="#installer-le-pack-dextension-virtualbox">package dextension pour VirtualBox</a> doit avoir été installé.</li>
<li>Installer un client RDP : <code class="language-plaintext highlighter-rouge">sudo pacman -S rdesktop</code></li>
</ul>
<p>Laffichage dune machine virtuelle démarrée en mode sans affichage (headless) peut être réalisé via VRDP.</p>
<p>La connexion à une machine virtuelle via RDP ne fonctionnera que si VRDE a été activé pour la machine virtuelle. Après cela, nimporte quel client RDP peut être utilisé pour se connecter à lhôte local ou utiliser ladresse IP de lhôte sur la machine virtuelle <br />
Le serveur VRDE est à lécoute sur le port 3389.</p>
<p>VirtualBox est hébergé sur un serveur (xoyize.xyz) avec un pare-feu , la seule entrée possible est le port SSH .<br />
On va utiliser le port SSH (55035) du serveur pour rediriger tout le traffic du port 3389 de la machine virtuelle vers un port local (15000) de la machine appelante.</p>
<p>Exécuter la commande suivante sur un premier terminal</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 15000:localhost:3389 admbust@xoyize.xyz -p 55035 -i /home/yannick/.ssh/vbox-srvbust-ed25519
</code></pre></div></div>
<p>Exécuter la commande suivante sur un second terminal (<a href="https://linux.die.net/man/1/rdesktop">man rdesktop</a>)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rdesktop -g 100% -P -z -k fr localhost:15000 # Automatic scaling of geometry
</code></pre></div></div>
<p>Et vous obtenez une fenêtre console de la machine virtuelle</p>
<p><img src="/images/phpvbox002.png" alt="" width="200" /></p>
<h2 id="service-pour-startstop-machine-virtuelle">Service pour start/stop machine virtuelle</h2>
<p><em>Créer un service systemd qui lancera automatiquement un serveur virtuel au démarrage</em></p>
<p>Le serveur à lancer est identifié par son uuid<br />
Exemple pour un serveur avec des “instantanés” (snapshots) <br />
Liste des machines</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u vbox VBoxManage list vms # liste des machines virtuelles
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"ynh" {beec9cd5-8afb-4906-861d-f4c18f1545e3}
</code></pre></div></div>
<p>On veut démarrer automatiquement ynh</p>
<p>Création dun service <strong>vmdebian.service</strong> sous systemd</p>
<blockquote>
<p><strong>ATTENTION!!!</strong><br />
Utilisation de systemd pour démarrer et arrêter la coexistence de <strong>vm</strong> et <strong>phpvirtualbox</strong> <br />
Si vous utilisez un script systemd pour démarrer et arrêter <strong>vm</strong>, dans votre <strong>vmdebian.service</strong> vous devez utiliser<br />
<code class="language-plaintext highlighter-rouge">sudo -u vboxuser /usr/bin/VBoxHeadless ...</code><br />
et NE PAS SPECIFIER utilisateur et groupe comme suit<br />
[Service]
User=vboxuser<br />
Group=vboxuser<br />
Ajoutez également <code class="language-plaintext highlighter-rouge">httpd.service</code> au paramètre <code class="language-plaintext highlighter-rouge">After</code> dans <strong>vmdebian.service</strong>.<br />
Vous devez également démarrer et arrêter vm UNIQUEMENT à partir de systemd, sinon vous risquez de recevoir une erreur de connexion</p>
</blockquote>
<p>Le fichier <strong>vmdebian.service</strong> sous systemd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/vmdebian.service
</code></pre></div></div>
<p>Contenu du fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Vbox Yunohost Service
After=network.target vboxdrv.service httpd.service
[Service]
Type=simple
ExecStart=sudo -u vbox /usr/bin/vboxheadless -s 'ynh'
ExecStop=sudo -u vbox /usr/bin/vboxmanage controlvm 'ynh' poweroff
[Install]
WantedBy=multi-user.target
</code></pre></div></div>
<p>Lancer le service vmdebian après avoir créé ynh et installé yunohost:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
sudo systemctl start vmdebian
#Vérifier:
sudo systemctl status vmdebian
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● vmdebian.service - Vbox Yunohost Service
Loaded: loaded (/etc/systemd/system/vmdebian.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2020-02-20 11:44:26 CET; 12s ago
Main PID: 24618 (sudo)
Tasks: 27 (limit: 4915)
Memory: 33.4M
CGroup: /system.slice/vmdebian.service
├─24618 /usr/bin/sudo -u vbox /usr/bin/vboxheadless -s ynh
└─24619 /usr/lib/virtualbox/VBoxHeadless -s ynh
févr. 20 11:44:26 xoyize.xyz systemd[1]: Started Vbox Yunohost Service.
févr. 20 11:44:26 xoyize.xyz sudo[24618]: root : TTY=unknown ; PWD=/ ; USER=vbox ; COMMAND=/usr/bin/vboxheadless -s ynh
févr. 20 11:44:26 xoyize.xyz sudo[24618]: pam_unix(sudo:session): session opened for user vbox by (uid=0)
</code></pre></div></div>
<p>Activer le service pour le redémarrage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable vmdebian
</code></pre></div></div>
<h1 id="machine-virtuelle-virtualbox---ynh-ouestlinenet">Machine virtuelle Virtualbox - ynh (ouestline.net)</h1>
<p><em>VirtualBox est installé sur le serveur xoyize.xyz , à ladresse 192.168.0.45 dans le réseau local. On va utliser <strong><a href="https://vm.xoyize.xyz/">phpvirtualbox</a></strong> pour créer/gérer les machines virtuelles.</em></p>
<h2 id="création-et-configuration---ynh">Création et configuration - ynh</h2>
<h3 id="télécharger-une-image-iso-yunohost-virtualbox">Télécharger une image “iso” yunohost virtualbox</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir ~/yunohost # créer un dossier
cd ~/yunohost
# Télécharger la dernière image stable
wget https://build.yunohost.org/yunohost-stretch-3.6.4.6-amd64-stable.iso
</code></pre></div></div>
<h3 id="créer-ynh">Créer “ynh”</h3>
<p>Création “ynh” avec disque dur ynh.vmdk de 10 Go via phpvirtualbox et le lancer</p>
<p><img src="/images/phpvbox001.png" alt="" width="500" /></p>
<p>Activer la liaison sécurisée SSH/RDP pour installer yunohost</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 15000:localhost:3389 admbust@xoyize.xyz -p 55035 -i /home/yannick/.ssh/vbox-srvbust-ed25519
</code></pre></div></div>
<p>Exécuter la commande suivante sur un second terminal pour accès en mode console</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rdesktop -g 1024x768 -P -z -k fr localhost:15000 # Automatic scaling of geometry
</code></pre></div></div>
<p><img src="/images/phpvbox002.png" alt="" width="200" /></p>
<h3 id="yunohost">Yunohost</h3>
<p>Lancer linstallation de yunohost… <br />
puis la post installation domaine : cinay.eu<br />
<img src="/images/ynhvb001.png" alt="" width="400" /></p>
<p>Se connecter en <em>admin</em><br />
Lancer une mise à jour</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update &amp;&amp; sudo apt -y upgrade
</code></pre></div></div>
<p>Relever adresse ip : 192.168.0.36 et adresse mac : 08:00:27:3c:82:f2 <br />
inet6 fe80::a00:27ff:fe3c:82f2/64
connexion via SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh admin@192.168.0.36
</code></pre></div></div>
<h3 id="locales">Locales</h3>
<p>Pour avoir linterface en français</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
nano /etc/locale.gen
</code></pre></div></div>
<p>Supprimer le <code class="language-plaintext highlighter-rouge">#</code> de la ligne fr_FR.UTF-8<br />
Générer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>locale-gen
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Generating locales (this might take a while)...
fr_FR.UTF-8... done
</code></pre></div></div>
<h3 id="freebox">Freebox</h3>
<p><strong>DMZ</strong><br />
<img src="/images/freebox-dmz.png" alt="Texte alternatif" width="600" /></p>
<p>A partir des éléments fournis par <code class="language-plaintext highlighter-rouge">ip a</code>, définir un <strong>Next Hop ipv6</strong> (2a01:e34:eebf:df2::/64) sur la freebox <br />
<img src="/images/freebox-ipv6-ouestline.png" alt="Texte alternatif" width="600" /></p>
<p>Créer le <strong>Reverse DNS</strong> <ouestline.net> dans l'espace abonné Free (MA FREEBOX &rarr; Reverse DNS)</ouestline.net></p>
<h3 id="adressage-ipv6">adressage IPV6</h3>
<p>Modifier linterface réseau <strong>/etc/network/interfaces</strong> pour un adressage IPV6</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug enp0s3
iface enp0s3 inet dhcp
# This is an autoconfigured IPv6 interface
#iface enp0s3 inet6 auto
iface enp0s3 inet6 static
address 2a01:e34:eebf:df2::1
netmask 64
post-up ip -6 route add default via fe80::224:d4ff:fea6:aa20 dev enp0s3
</code></pre></div></div>
<p>Et redémarrer <code class="language-plaintext highlighter-rouge">sudo systemctl reboot</code></p>
<p>Vérification adressage IPV6</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 1
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: enp0s3: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:3c:82:f2 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.36/24 brd 192.168.0.255 scope global enp0s3
valid_lft forever preferred_lft forever
inet6 2a01:e34:eebf:df2::1/64 scope global
valid_lft forever preferred_lft forever
inet6 2a01:e34:eebf:df0:a00:27ff:fe3c:82f2/64 scope global mngtmpaddr dynamic
valid_lft 85869sec preferred_lft 85869sec
inet6 fe80::a00:27ff:fe3c:82f2/64 scope link
valid_lft forever preferred_lft forever
</code></pre></div></div>
<h3 id="ovh---configuration-dns-ouestlinenet">OVH - Configuration DNS ouestline.net</h3>
<font color="green"><b>On fait le choix de définir le domaine ouestline.net en IPV6 uniquement</b></font>
<p>Informations yunohost sur le domaine ouestline.net</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Basic ipv4/ipv6 records
@ 3600 IN A 78.235.240.223
* 3600 IN A 78.235.240.223
@ 3600 IN AAAA 2a01:e34:eebf:df2::1
* 3600 IN AAAA 2a01:e34:eebf:df2::1
; XMPP
_xmpp-client._tcp 3600 IN SRV 0 5 5222 ouestline.net.
_xmpp-server._tcp 3600 IN SRV 0 5 5269 ouestline.net.
muc 3600 IN CNAME @
pubsub 3600 IN CNAME @
vjud 3600 IN CNAME @
; Mail
@ 3600 IN MX 10 ouestline.net.
@ 3600 IN TXT "v=spf1 a mx ip4:78.235.240.223 ip6:2a01:e34:eebf:df2::1 -all"
mail._domainkey 3600 IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOT4EhluaTJNwVu668Wn6+OVhuQQUn94KcAOAXi+xKpjH+LA4g/5p6WUUV1Qo4Vgp9Il90dZKM/vAjilchXB+vePT2XZwqWIvjxTYD6s97E/YBYbEVUJdoCoZlxaQPS+T90ikJJje8vK9SO4AMuQKGxzHeTzM4dHIVDMQCXmQUfQIDAQAB"
_dmarc 3600 IN TXT "v=DMARC1; p=none"
; Extra
@ 3600 IN CAA 128 issue "letsencrypt.org"
</code></pre></div></div>
<p>Paramétrage de la zone DNS OVH ouestline.net</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 3600
@ IN SOA dns111.ovh.net. tech.ovh.net. (2020012301 86400 3600 3600000 300)
IN NS dns111.ovh.net.
IN NS ns111.ovh.net.
IN MX 10 ouestline.net.
IN A 78.235.240.223
IN AAAA 2a01:e34:eebf:df2::1
IN CAA 128 issue "letsencrypt.org"
600 IN TXT "v=spf1 mx ip4:78.235.240.223 ip6:2a01:e34:eebf:df2::1 -all"
* IN CNAME ouestline.net.
_dmarc IN TXT "v=DMARC1;p=none;"
mail._domainkey IN TXT ( "v=DKIM1;h=sha256;k=rsa;s=*;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOT4EhluaTJNwVu668Wn6+OVhuQQUn94KcAOAXi+xKpjH+LA4g/5p6WUUV1Qo4Vgp9Il90dZKM/vAjilchXB+vePT2XZwqWIvjxTYD6s97E/YBYbEVUJdoCoZlxaQPS+T90ikJJje8vK9SO4AMuQKGxzHeTzM4dHIVDMQCXmQUfQIDAQAB;" )
</code></pre></div></div>
<h3 id="dnsmasq">Dnsmasq</h3>
<p>Modifier ladresse IPV6 , dernière ligne du fichier suivant <strong>/etc/dnsmasq.d/ouestline.net</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>address=/ouestline.net/78.235.240.223
txt-record=ouestline.net,"v=spf1 mx a -all"
mx-host=ouestline.net,ouestline.net,5
srv-host=_xmpp-client._tcp.ouestline.net,ouestline.net,5222,0,5
srv-host=_xmpp-server._tcp.ouestline.net,ouestline.net,5269,0,5
address=/ouestline.net/2a01:e34:eebf:df2::1
</code></pre></div></div>
<p>Relancer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart dnsmasq
</code></pre></div></div>
<h3 id="acme---certificats-letsencrypt">Acme - Certificats letsencrypt</h3>
<blockquote>
<font color="red"><b>On ne peut pas utiliser la création des certificats proposé par yunohost car elle utilise l'adressage ipv4</b></font>
</blockquote>
<p><a href="https://yann.cinay.eu/2017/08/31/Acme-Certficats-Serveurs.html#g%C3%A9n%C3%A9ration-des-certificats-avec-le-client-acmesh">Génération des certificats avec le client acme.sh</a></p>
<p>La ligne de commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --dns dns_ovh --ocsp --issue --keylength ec-384 -d 'ouestline.net' -d '*.ouestline.net'
</code></pre></div></div>
<p>Les certificats sont sous <strong>/home/admin/.acme.sh/ouestline.net_ecc/</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[lundi 13 janvier 2020, 16:39:58 (UTC+0100)] Your cert is in /home/admin/.acme.sh/ouestline.net_ecc/ouestline.net.cer
[lundi 13 janvier 2020, 16:39:58 (UTC+0100)] Your cert key is in /home/admin/.acme.sh/ouestline.net_ecc/ouestline.net.key
[lundi 13 janvier 2020, 16:39:58 (UTC+0100)] The intermediate CA cert is in /home/admin/.acme.sh/ouestline.net_ecc/ca.cer
[lundi 13 janvier 2020, 16:39:58 (UTC+0100)] And the full chain certs is there: /home/admin/.acme.sh/ouestline.net_ecc/fullchain.cer
</code></pre></div></div>
<p>Remplacer les certificats actuels</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mv /etc/yunohost/certs/ouestline.net/crt.pem /etc/yunohost/certs/ouestline.net/crt.pem.sav
sudo mv /etc/yunohost/certs/ouestline.net/key.pem /etc/yunohost/certs/ouestline.net/key.pem.sav
sudo ln -s /home/admin/.acme.sh/ouestline.net_ecc/fullchain.cer /etc/yunohost/certs/ouestline.net/crt.pem
sudo ln -s /home/admin/.acme.sh/ouestline.net_ecc/ouestline.net.key /etc/yunohost/certs/ouestline.net/key.pem
sudo systemctl restart nginx
</code></pre></div></div>
<p>Vérifier par le lien <a href="https://ouestline.net">https://ouestline.net</a> que la connexion est sécurisée<br />
<img src="/images/ouestline.net-letsencrypt.png" alt="" width="300" /></p>
<p>Le renouvellement est fait automatiquement avec le “scheduler” admin</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -l
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>25 0 * * * "/home/admin/.acme.sh"/acme.sh --cron --home "/home/admin/.acme.sh" &gt; /dev/null
</code></pre></div></div>
<p>Vérifier le fonctionnement du script</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"/home/admin/.acme.sh"/acme.sh --cron --ocsp --home "/home/admin/.acme.sh"
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] ===Starting cron===
[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] Renew: 'ouestline.net'
[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] Skip, Next renewal time is: vendredi 13 mars 2020, 15:39:58 (UTC+0000)
[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] Add '--force' to force to renew.
[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] Skipped ouestline.net_ecc
[lundi 13 janvier 2020, 16:42:31 (UTC+0100)] ===End cron===
</code></pre></div></div>
<h3 id="ouestlinenet---dhocsp">ouestline.net - dh+ocsp</h3>
<blockquote>
<p>Les commandes se font en mode su ou sudo</p>
</blockquote>
<p><em><a href="https://fr.wikipedia.org/wiki/%C3%89change_de_cl%C3%A9s_Diffie-Hellman">Wikipédia : Échange de clés Diffie-Hellman</a><br />
En cryptographie, léchange de clés Diffie-Hellman, du nom de ses auteurs Whitfield Diffie et Martin Hellman, est une méthode1, publiée en 1976, par laquelle deux agents, nommés par convention Alice et Bob, peuvent se mettre daccord sur un nombre (quils peuvent utiliser comme clé pour chiffrer la conversation suivante) sans quun troisième agent appelé Ève puisse découvrir le nombre, même en ayant écouté tous leurs échanges.</em><br />
<img src="/images/Diffie-Hellman_Key_Exchange_(fr).svg" alt="Texte alternatif" width="300" /><br />
<em>Illustration conceptuelle dun échange de clés Diffie-Hellman</em></p>
<p>Générer la clé dh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
</code></pre></div></div>
<p><em><a href="https://fr.wikipedia.org/wiki/Online_Certificate_Status_Protocol">Wikipédia : Online Certificate Status Protocol</a> (OCSP, en français « protocole de vérification de certificat en ligne ») est un protocole Internet utilisé pour valider un certificat numérique X.509. OCSP est standardisé par lIETF dans la RFC 69601.</em></p>
<table>
<thead>
<tr>
<th>comment la requête OCSP est formée et envoyée<br /> vers le serveur OCSP.</th>
<th>comment la réponse OCSP est formée<br /> et envoyée vers le client OCSP.<br />Cette réponse peut être : GOOD, REVOKED ou UNKNOWN.</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="/images/Ocsp-request.png" alt="Texte alternatif" width="300" /></td>
<td><img src="/images/Ocsp-request.png" alt="Texte alternatif" width="300" /></td>
</tr>
</tbody>
</table>
<p>Modifier le fichier de configuration <strong>/etc/nginx/conf.d/ouestline.net.conf</strong> pour activer dh et ocsp <br />
Supprimer le <code class="language-plaintext highlighter-rouge">#</code> qui précède la commande <code class="language-plaintext highlighter-rouge">ssl_dhparam /etc/ssl/private/dh2048.pem;</code><br />
Ajouter ce qui suit la ligne suivante</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/yunohost/certs/ouestline.net/crt.pem;
resolver 127.0.0.1;
</code></pre></div></div>
<p>Vérifier et relancer nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
systemctl restart nginx
</code></pre></div></div>
<p>Tester la réponse OCSP</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -connect ouestline.net:443 -status &lt; /dev/null
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
OCSP response:
======================================
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
Produced At: Jan 11 07:58:00 2020 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 7729AB3FCF8A22064A12DEE66AE76071085D6C16
Issuer Key Hash: ADDDBAE6D139B74565EFF384A6A63047A8ECA1A6
Serial Number: 60B5D00F31795538F9C2C9A60354993266A5
Cert Status: good
[...]
</code></pre></div></div>
<h3 id="openssl-version-111x-non-implante">Openssl version 1.1.1x (NON IMPLANTE)</h3>
<p>Pour installer une version openssl plus récente et PHP7.x</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Nouvelle source pour installer Openssl , PHP7
apt-get -y install apt-transport-https lsb-release ca-certificates
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" &gt; /etc/apt/sources.list.d/php.list'
apt update &amp;&amp; apt upgrade -y
</code></pre></div></div>
<h3 id="additions-invité-nécessaire-pour-le-partage">Additions invité (nécessaire pour le partage)</h3>
<p>Ouvrir <strong>phpvirtualbox</strong> et sélectionner <em>stockage</em> de la machine virtuelle ynh<br />
Insérer le cdrom contenant limage <strong>VBoxGuestAdditions.iso</strong> (située généralement sous <strong>/usr/share/virtualbox</strong>)</p>
<p><img src="/images/virtualbox-additions-clients.png" alt="" width="600" /><br />
<img src="/images/virtualbox-additions-clients-1.png" alt="" width="300" /></p>
<p>Ajouter un partage qui sera pris en compte au prochain démarrage<br />
<img src="/images/virtualbox-additions-clients-2.png" alt="" width="200" /></p>
<p>Connexion sur la machine virtuelle ynh : <code class="language-plaintext highlighter-rouge">ssh admin@192.168.0.36</code><br />
Installer les additions client dans un Debian en cours dexécution dans une machine virtuelle.</p>
<ul>
<li>Installez gcc ,make et kernel headers (installateur a besoin deux pour construire le module du noyau):<code class="language-plaintext highlighter-rouge">sudo apt install gcc make linux-headers-$(uname -r)</code></li>
<li>Monter le cd dans la machine virtuelle : <code class="language-plaintext highlighter-rouge">sudo mount /dev/cdrom /media/cdrom</code></li>
<li>Allez dans le dossier monté : <code class="language-plaintext highlighter-rouge">cd /media/cdrom</code></li>
<li>Exécutez : <code class="language-plaintext highlighter-rouge">sudo ./VBoxLinuxAdditions.run</code> , patienter quelques minutes…</li>
</ul>
<blockquote>
<p>Redémarrer la machine virtuelle : <code class="language-plaintext highlighter-rouge">sudo systemctl reboot</code></p>
</blockquote>
<h2 id="sécurité">Sécurité</h2>
<h3 id="authentification-ssh-par-clé">Authentification SSH par clé</h3>
<p>Sur le <u>poste appelant</u>, générer un jeu de clés</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ouestline
</code></pre></div></div>
<p>Copier la clé publique sur le serveur ynh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id -i ouestline.pub admin@192.168.0.36
</code></pre></div></div>
<p>Sur le <u>serveur ynh</u>, éditez le fichier de configuration SSH, pour désactiver lauthentification par mot de passe et changer de port</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/ssh/sshd_config
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>port 55032
PasswordAuthentication no
</code></pre></div></div>
<p>Sauvegardez et relancez le démon SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart ssh
</code></pre></div></div>
<p>Activer et désactiver les ports dans le pare feu</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yunohost firewall allow TCP 55032 # activation port 55032
sudo yunohost firewall disallow TCP 22 # désactivation port 22
</code></pre></div></div>
<h3 id="désactivation-de-lapi-yunohost">Désactivation de lAPI YunoHost</h3>
<p>YunoHost est administrable via une API HTTP, servie sur le port 6787 par défaut (seulement sur localhost). Elle permet dadministrer une grande partie de votre serveur, et peut donc être utilisée à des fins malveillantes. La meilleure chose à faire si vous êtes habitués aux lignes de commande est de désactiver le service yunohost-api, et utiliser la ligne de commande en SSH.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl disable yunohost-api
sudo systemctl stop yunohost-api
</code></pre></div></div>
<h3 id="modifications-des-mots-de-passe">Modifications des mots de passe</h3>
<p>En ligne de commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh admin@192.168.0.36 -p 55032 -i /home/yannick/.ssh/ouestline # connexion SSH
sudo -s
yunohost tools adminpw -n Nouveau_mot_de_passe # modifier mot de passe administrateur
yunohost user update ouest -p Nouveau_mot_de_passe # modifier mot de passe utilisateur
</code></pre></div></div>
<h3 id="vérifications">Vérifications</h3>
<p>Accès ipv4 ipv6</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ping4 -c3 ouestline.net
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PING ouestline.net (78.235.240.223) 56(84) bytes of data.
64 bytes from smm49-1-78-235-240-223.fbx.proxad.net (78.235.240.223): icmp_seq=1 ttl=49 time=16.2 ms
64 bytes from smm49-1-78-235-240-223.fbx.proxad.net (78.235.240.223): icmp_seq=2 ttl=49 time=15.9 ms
64 bytes from smm49-1-78-235-240-223.fbx.proxad.net (78.235.240.223): icmp_seq=3 ttl=49 time=17.5 ms
--- ouestline.net ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 15.959/16.592/17.556/0.708 ms
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ping6 -c3 ouestline.net
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PING ouestline.net(2a01:e34:eebf:df2::1 (2a01:e34:eebf:df2::1)) 56 data bytes
64 bytes from 2a01:e34:eebf:df2::1 (2a01:e34:eebf:df2::1): icmp_seq=1 ttl=51 time=16.8 ms
64 bytes from 2a01:e34:eebf:df2::1 (2a01:e34:eebf:df2::1): icmp_seq=2 ttl=51 time=16.7 ms
64 bytes from 2a01:e34:eebf:df2::1 (2a01:e34:eebf:df2::1): icmp_seq=3 ttl=51 time=32.2 ms
</code></pre></div></div>
<p>Reverse DNS</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig A ouestline.net +noall +answer
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; &lt;&lt;&gt;&gt; DiG 9.11.5-P4-5.1-Debian &lt;&lt;&gt;&gt; A ouestline.net +noall +answer
;; global options: +cmd
ouestline.net. 3600 IN A 78.235.240.223
</code></pre></div></div>
<p><a href="https://whatismyipaddress.com/blacklist-check">Blacklist Check</a> (vérifier si ladresse IP 78.235.240.223 nest pas dans une liste noire)</p>
<h2 id="applications---ynh">Applications - ynh</h2>
<h3 id="rainloop">RainLoop</h3>
<p><em>RainLoop est un client de messagerie web libre pour le protocole IMAP</em><br />
Installation via yunohost admin</p>
<h3 id="transmission">Transmission</h3>
<p><em>Transmission est un client BitTorrent intuitif, fonctionnel et très léger. Il dispose de fonctionnalités comme le chiffrement des échanges de données, léchange de pairs, le support des blocklists, la limitation des débits en émission et en réception, etc…</em><br />
Installation via yunohost admin</p>
<h3 id="firefox-sync-server">Firefox Sync Server</h3>
<p><em>Le serveur de synchronisation de Mozilla, pour héberger vos données Firefox</em><br />
Installation en ligne de commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
yunohost app install https://github.com/YunoHost-Apps/ffsync_ynh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [Y/N] : Y
Domaines disponibles :
- ouestline.net
Choisissez un domaine pour Firefox-Sync (default: ouestline.net) :
Choisissez un chemin pour Firefox-Sync (default: /ffsync) :
Info : Installation de l'application ffsync …
Info : [....................] &gt; Validating installation parameters...
Info : [++++++..............] &gt; Installing dependencies...
Info : [######+.............] &gt; Configuring MySQL database...
Info : [#######++++++++.....] &gt; Installing sources files...
Attention : DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
[...]
Info : [###############+....] &gt; Configuring nginx
Info : [################....] &gt; Configuring system user...
Info : [################+...] &gt; Configuring application...
Attention : Created symlink /etc/systemd/system/multi-user.target.wants/uwsgi-app@ffsync.service → /etc/systemd/system/uwsgi-app@.service.
Info : [#################+..] &gt; Protecting directory
Info : [##################+.] &gt; Configuring permissions
Info : [####################] &gt; Installation of ffsync completed
Succès ! La configuration de SSOwat a été générée
Succès ! Installation terminée
</code></pre></div></div>
<p>Lancer lapplication FFsync depuis le tableau de bord yunohost</p>
<p><img src="/images/ffouest001.png" alt="" width="600" /></p>
<p>Procéder à la modification (comme indiqué)<br />
Pour configurer Firefox pour quil parle à votre nouveau serveur Sync, allez dans “<code class="language-plaintext highlighter-rouge">about:config</code>”, cherchez “<code class="language-plaintext highlighter-rouge">identity.sync.tokenserver.uri</code>” et changez sa valeur en URL de votre serveur avec un chemin daccès de “token/1.0/sync/1.5” :<br />
<code class="language-plaintext highlighter-rouge">identity.sync.tokenserver.uri</code> → https://ouestline.net/ffsync/token/1.0/sync/1.5 <br />
<img src="/images/ffouest003.png" alt="" width="400" /></p>
<p>Puis se rendre dans “Préférences → Sync”<br />
<img src="/images/ffouest002.png" alt="" width="400" /></p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2019-12-28T00: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="/2019/12/28/Archlinux-Debian-Node.js-Nvm-Npm-Yarn.html">Archlinux Debian , installation des paquets node npm nvm yarn</a></div><div class="next"><span>SUIVANT</span><a href="/2019/12/30/Archlinux-yay-un-yaourt-AUR-Helper-en-Go.html">Archlinux "yay" un autre "yaourt" - Un AUR Helper écrit en Go</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>