yannstatic/static/2023/12/22/Alpine-Linux.html

2891 lines
230 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>Alpine Linux dans un environnement virtuel KVM Lenovo - YannStatic</title>
<meta name="description" content="Alpine Linux est une distribution Linux ultra-légère, orientée sécurité et basée sur Musl (en) et BusyBox, principalement conçue pour un « utilisateur intens...">
<link rel="canonical" href="https://static.rnmkcy.eu/2023/12/22/Alpine-Linux.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;">Alpine Linux dans un environnement virtuel KVM Lenovo</h1></header></div><meta itemprop="headline" content="Alpine Linux dans un environnement virtuel KVM Lenovo"><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">22&nbsp;déc.&nbsp;&nbsp;2023</span>
<span title="Modification" style="color:#00FF7F">20&nbsp;mai&nbsp;&nbsp;&nbsp;2024</span></li></ul></div><meta itemprop="datePublished" content="2024-05-20T00:00:00+02: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><em>Alpine Linux est une distribution Linux ultra-légère, orientée sécurité et basée sur Musl (en) et BusyBox, principalement conçue pour un « utilisateur intensif qui apprécie la sécurité, la simplicité et lefficacité des ressources ». Elle utilise les patches PaX et Grsecurity du noyau par défaut et compile tous les binaires de lespace utilisateur et exécutables indépendants de la position avec protection de destruction de la pile (<a href="https://fr.wikipedia.org/wiki/Alpine_Linux">Alpine Linux (wikipédia)</a>)</em></p>
<p><img src="/images/alpine-linux-logo.png" alt="" width="300" /></p>
<h2 id="alpine-linux">Alpine Linux</h2>
<p><em>Création machine virtuelle Alpine de type KVM avec 2 Go de RAM, 1 cœur de processeur et 8 Go de disque dur.</em></p>
<ul>
<li><a href="/2023/12/17/Installer_KVM_Kernel_Virtual_Machine_sur_un_serveur.html#création-machines-virtuelles-kvm-avec-la-commande-virsh">Création machines virtuelles KVM avec la commande virsh</a></li>
<li><a href="/2023/12/17/Installer_KVM_Kernel_Virtual_Machine_sur_un_serveur.html#accéder-aux-machines-virtuelles-kvm-via-le-client-vnc">Accéder aux machines virtuelles KVM via le client VNC</a></li>
<li><a href="https://wiki.alpinelinux.org/wiki/">Wiki Alpine Linux</a></li>
</ul>
<h3 id="créer-machine-virtuelle-alpineouest">Créer machine virtuelle AlpineOuest</h3>
<p>Création dune image virtuelle AlpineOuest sous le serveur Lenovo rnmkcy.eu<br />
On se connecte sur le serveur Lenovo en SSH, puis on exécute la commande suivante pour créer une machine virtuelle Alpine avec 2 Go de RAM, 1 cœur de processeur et 8 Go de disque dur</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>virt-install <span class="nt">--os-variant</span><span class="o">=</span><span class="s2">"alpinelinux3.17"</span> <span class="se">\</span>
<span class="nt">--name</span> AlpineOuest <span class="se">\</span>
<span class="nt">--ram</span><span class="o">=</span>2048 <span class="se">\</span>
<span class="nt">--vcpus</span><span class="o">=</span>1 <span class="se">\</span>
<span class="nt">--cpu</span> host <span class="se">\</span>
<span class="nt">--hvm</span> <span class="nt">--disk</span> <span class="nv">path</span><span class="o">=</span>/srv/kvm/libvirt/images/alpine-ouest,size<span class="o">=</span>8 <span class="se">\</span>
<span class="nt">--cdrom</span> /srv/kvm/libvirt/boot/alpine-standard-3.19.0-x86_64.iso <span class="se">\</span>
<span class="nt">--network</span> <span class="nv">bridge</span><span class="o">=</span>br0 <span class="se">\</span>
<span class="nt">--graphics</span> vnc
</code></pre></div></div>
<p>Le serveur Lenovo na pas daffichage, il faut créer un tunnel ssh depuis un poste local</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 5900:127.0.0.1:5900 leno@192.168.0.215 -p 55215 -i /home/yann/.ssh/lenovo-ed25519
</code></pre></div></div>
<p>Puis lancer de ce même poste un client VNC : <code class="language-plaintext highlighter-rouge">localhost:9500</code> , la console saffiche <br />
<img src="/images/alpine-ouest01.png" alt="" /></p>
<h3 id="installer-et-configurer-alpineouest">Installer et configurer AlpineOuest</h3>
<ul>
<li><a href="https://www.librebyte.net/en/tag/alpine/">Alpine tutos</a></li>
</ul>
<p>Une fois limage ISO lancée, on arrive à un invite de connexion. <br />
Indiquez <code class="language-plaintext highlighter-rouge">root</code> comme nom dutilisateur, aucun mot de passe ne vous sera demandé à cette étape. <br />
Le système est utilisable, mais on veut linstaller, ce qui passe par la commande suivante (clavier qwerty)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>setup-alpine
</code></pre></div></div>
<p>Une suite de questions :</p>
<ul>
<li>la langue du clavier (fr) keyboard layout (fr)</li>
<li>le nom que vous voulez donner à la machine sur le réseau (ouestline.xyz)</li>
<li>interface (eth0) et réseau</li>
<li>mot de passe root (toor)</li>
<li>votre fuseau horaire (Europe/paris)</li>
<li>proxy none</li>
<li>APK mirror (f)</li>
<li>User à créer (aluser) et son mot de passe (aluser49)</li>
<li>ssh key (none)</li>
<li>ssh server (openssh)</li>
<li>Disk &amp; Install (vda)</li>
<li>Utiliser (sys)</li>
<li>Erase the disk vda (y)</li>
</ul>
<p>Normalement, vous navez rien à faire, les paramètres par défaut doivent convenir. Mais si vous le désirez, vous pouvez les modifier pour utiliser une interface particulière, une IP fixe, un serveur proxy, etc.</p>
<p>Une soixantaine de serveurs mirroir vous seront proposés pour télécharger les paquets. Choisissez un numéro dans la liste ou demandez au système de les tester et de sélectionner le plus rapide. Vous pouvez aussi modifier le fichier des sources. Il vous faudra ensuite choisir votre serveur SSH : OpenSSH, Dropbear ou aucun.</p>
<p>On termine par la méthode dinstallation. Il en existe quatre :</p>
<ul>
<li>none : le système et ses données sont placés en RAM et seront perdus après le redémarrage</li>
<li>sys : le système et ses données sont placés sur un HDD/SSD</li>
<li>data : le système est placé en RAM, les données sur un HDD/SSD</li>
<li>lvm : utilisation de Logical Volume Manager, les deux choix précédents seront proposés (lvmsys, lvmdata)</li>
</ul>
<p>Si vous stockez le système en mémoire, il faudra trouver un moyen de sauvegarder la configuration. Vous pourrez le faire uniquement depuis un lecteur de disquettes (!) ou une clé USB. Une fois le système installé, vous pourrez lutiliser directement sil est placé en mémoire ou redémarrer si vous avez opté pour un stockage classique.</p>
<p>Il nest pas conseillé dutiliser directement le compte root pour les actions du quotidien.<br />
Si utilisateur non créé dans la procédure dinstallation, le créer avec son propre espace dans /home/</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adduser aluser
</code></pre></div></div>
<p>Vous pouvez utiliser lutilisateur pour vous connecter via SSH (impossible avec le compte root)<br />
Relever ladresse ip allouée : <code class="language-plaintext highlighter-rouge">ip a</code> &gt; 192.168.0.5</p>
<p>Sur un poste linux du réseau</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh aluser@192.168.0.5
</code></pre></div></div>
<p>Une fois connecté ,vous pouvez accéder au “root” de manière classique avec la commande :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su -
</code></pre></div></div>
<p>Mise à jour</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk update
apk upgrade
<span class="c"># Vous pouvez fusionner les deux lignes avec </span>
apk <span class="nt">-U</span> upgrade
</code></pre></div></div>
<p>Editeur nano (Vous pouvez aussi opter pour vi qui est nativement présent sur le système)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add nano
</code></pre></div></div>
<h3 id="réseau">Réseau</h3>
<p><a href="https://www.cyberciti.biz/faq/how-to-configure-static-ip-address-on-alpine-linux/">How to configure static IP address on Alpine Linux</a></p>
<h4 id="activer-ipv6">Activer IPv6</h4>
<p>Si vous utilisez IPv6, faites ce qui suit pour activer IPv6 maintenant et à chaque démarrage :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>modprobe ipv6
echo "ipv6" &gt;&gt; /etc/modules
</code></pre></div></div>
<h4 id="configurer-interface">Configurer interface</h4>
<p>Configuration de loopback (obligatoire)</p>
<p class="info">Remarque : La configuration loopback doit apparaître en premier dans /etc/network/interfaces pour éviter les problèmes de réseau.</p>
<p>Pour configurer loopback, ajoutez ce qui suit au fichier <code class="language-plaintext highlighter-rouge">/etc/network/interfaces</code></p>
<p>Contenu de <code class="language-plaintext highlighter-rouge">/etc/network/interfaces</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
auto lo
iface lo inet loopback
</code></pre></div></div>
<p class="info">Ce qui précède fonctionne pour configurer ladresse IPv4 loopback (127.0.0.1) et ladresse IPv6 loopback (::1) — si vous avez activé IPv6.</p>
<p>Le fichier finale de configuration <code class="language-plaintext highlighter-rouge">/etc/network/interfaces</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/network/interfaces
</code></pre></div></div>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.216/24
gateway 192.168.0.254
<span class="nb">hostname </span>linux-alpine
iface eth0 inet static
address 2a01:e0a:9c8:2083::1/64
gateway fe80::8e97:eaff:fe39:66d6
pre-up <span class="nb">echo </span>0 <span class="o">&gt;</span> /proc/sys/net/ipv6/conf/eth0/accept_ra
</code></pre></div></div>
<p>Fichier de résolution dns</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/resolv.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nameserver 1.1.1.1
nameserver 192.168.0.254
</code></pre></div></div>
<p class="warning">ATTENTION , pour ladresse ipv6 statique il faut renseigner le NextHop de la box free avec ladresse inet6 <code class="language-plaintext highlighter-rouge">fe80::5054:ff:fe7c:b46c</code> de linterface réseau eth0<br />
<img src="/images/alpine-ouest02.png" alt="" /></p>
<p>Les modifications apportées à /etc/network/interfaces peuvent être activées en exécutant</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service networking restart <span class="c"># par défaut</span>
/etc/init.d/networking restart <span class="c"># alternative</span>
service networking restart <span class="c"># autre alternative</span>
</code></pre></div></div>
<h3 id="hostname">hostname</h3>
<p>Vérifier hostname</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostname
</code></pre></div></div>
<p>Renvoie <code class="language-plaintext highlighter-rouge">ouestline.xyz</code></p>
<p>Si lon veut changer de hostname</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"linux-alpine"</span> <span class="o">&gt;</span> /etc/hostname
</code></pre></div></div>
<p>Activez immédiatement la modification en exécutant la commande suivante.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">hostname</span> <span class="nt">-F</span> /etc/hostname
</code></pre></div></div>
<h3 id="php">PHP</h3>
<p><a href="https://www.librebyte.net/en/systems-deployment/how-to-install-php-php-fpm-in-alpine-linux/">How to install PHP, PHP-FPM in Alpine Linux?</a></p>
<h4 id="installer-php81">Installer php81</h4>
<p>Vérifier les dépôts de mon installation <code class="language-plaintext highlighter-rouge">cat /etc/apk/repositories</code>
Vérifiez que le dépôt communautaire est actif.</p>
<p>Mise à jour</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk update &amp;&amp; apk upgrade
</code></pre></div></div>
<p>Liste des paquets php</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk search ph8 | more
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
php81-8.1.27-r0
php81-fpm-8.1.27-r0
[...]
</code></pre></div></div>
<p>PHP-FPM introduit le concept de pools, chaque pool peut recevoir des connexions sur une socket PTC/IP (IP:Port) ou UNIX, et peut fonctionner sous un utilisateur et un groupe différents. Chaque pool a son fichier de configuration.</p>
<p>Installation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add php81 php81-fpm
</code></pre></div></div>
<p>Résultat</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(1/5) Installing php81-common (8.1.27-r0)
(2/5) Installing pcre2 (10.42-r2)
(3/5) Installing libxml2 (2.11.6-r0)
(4/5) Installing php81 (8.1.27-r0)
(5/5) Installing php81-fpm (8.1.27-r0)
Executing busybox-1.36.1-r15.trigger
OK: 438 MiB in 118 packages
</code></pre></div></div>
<p>Une fois le processus terminé, vous pouvez explorer les paramètres par défaut, voici un exemple de la structure du répertoire:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tree /etc/php81/
</code></pre></div></div>
<p><img src="/images/alpine-ouest16.png" alt="" width="400" /></p>
<p>Vous pouvez découvrir la valeur de la directive écoute en exécutant la commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grep 'listen =' -R /etc/php81/
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/php81/php-fpm.d/www.conf:listen = 127.0.0.1:9000
/etc/php81/php-fpm.d/www.conf:;pm.status_listen = 127.0.0.1:9001
</code></pre></div></div>
<p>La seconde ligne est commentée, lécoute se fait sur le port 9000</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>listen = 127.0.0.1:9000
</code></pre></div></div>
<p>Créer un lien symbolique vers la version correspondante</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ln -s /usr/bin/php81 /usr/bin/php
</code></pre></div></div>
<p>Afficher les versions installées de php</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>php -v
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PHP 8.1.27 (cli) (built: Dec 22 2023 21:16:31) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.27, Copyright (c) Zend Technologies
</code></pre></div></div>
<h4 id="gérer-le-service-php-fpm81">Gérer le service php-fpm81</h4>
<p>Démarrer, arrêter ou redémarrer le service php-fpm8, en utilisant le système dinitialisation OpenRC qui est le système init par défaut dans les distributions comme Gentoo et Alpine Linux.</p>
<p>Vérifier létat : <code class="language-plaintext highlighter-rouge">rc-service php-fpm81 status</code><code class="language-plaintext highlighter-rouge">* status: stopped</code><br />
Démarrer le service : <code class="language-plaintext highlighter-rouge">rc-service php-fpm81 start</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> * Caching service dependencies ... [ ok ]
* Checking /etc/php81/php-fpm.conf ...
* /run/php-fpm81: creating directory
* Starting PHP FastCGI Process Manager ... [ ok ]
</code></pre></div></div>
<p>Maintenant, vous pouvez vérifier si le service a démarré avec succès: <code class="language-plaintext highlighter-rouge">rc-service php-fpm81 status</code><code class="language-plaintext highlighter-rouge">* status: started</code></p>
<p>Lancement automatiquement après un redémarrage du système</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add php-fpm81 default
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">* service php-fpm81 added to runlevel default</code></p>
<h4 id="vérifier-et-recharger-php-fpm81">Vérifier et Recharger php-fpm81</h4>
<p>Chaque fois que vous modifiez les fichiers de configuration, vérifiez dabord les modifications avec:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>php-fpm81 -t
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">[02-Jan-2024 14:33:00] NOTICE: configuration file /etc/php81/php-fpm.conf test is successful</code><br />
puis rechargez les configurations:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service php-fpm81 reload
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">* Reloading PHP FastCGI Process Manager ... [ ok ]</code></p>
<p>redémarrer et arrêter</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service php-fpm81 restart
rc-service php-fpm81 stop
</code></pre></div></div>
<h3 id="caddy-server">Caddy server</h3>
<h4 id="installer-et-configurer">Installer et configurer</h4>
<p>Installer caddy</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk update
apk add caddy
</code></pre></div></div>
<p>Jai une erreur , il ne trouve pas le paquet caddy</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERROR: unable to select packages:
caddy (no such package):
required by: world[caddy]
</code></pre></div></div>
<p>Voir le site : Alpine Linux packages https://pkgs.alpinelinux.org/packages<br />
<img src="/images/alpine-ouest03.png" alt="" /><br />
caddy est dans le dépôt community</p>
<p>Vérifier les dépôts de mon installation <code class="language-plaintext highlighter-rouge">cat /etc/apk/repositories</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#/media/cdrom/apks
http://mirrors.ircam.fr/pub/alpine/v3.19/main
#http://mirrors.ircam.fr/pub/alpine/v3.19/community
</code></pre></div></div>
<p>Il faut décommenter le dépôt community, exécuter <code class="language-plaintext highlighter-rouge">apk update</code> puis installer caddy <code class="language-plaintext highlighter-rouge">apk add caddy</code></p>
<p><strong>DNS OVH</strong> du domaine et sous-domaines ouestline.xyz pointent sur ladresse ipv6 <code class="language-plaintext highlighter-rouge">2a01:e0a:9c8:2083::1/64</code> de la machine alpine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 3600
@ IN SOA dns111.ovh.net. tech.ovh.net. (2024020607 86400 3600 3600000 300)
IN NS ns111.ovh.net.
IN NS dns111.ovh.net.
IN AAAA 2a01:e0a:9c8:2083::1
dev IN AAAA 2a01:e0a:9c8:2083::1
dice IN AAAA 2a01:e0a:9c8:2083::1
osm IN AAAA 2a01:e0a:9c8:2083::1
static IN AAAA 2a01:e0a:9c8:2083::1
tst IN AAAA 2a01:e0a:9c8:2083::1
</code></pre></div></div>
<p>Créer une configuration de test dans le fichier <code class="language-plaintext highlighter-rouge">/etc/caddy/Caddyfile</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Caddy's configuration file
# see: https://caddyserver.com/docs/caddyfile
ouestline.xyz
respond "Hello, privacy!"
</code></pre></div></div>
<p>Lancer le service caddy</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service caddy start
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> * Caching service dependencies ... [ ok ]
* Starting Caddy web server ... [ ok ]
</code></pre></div></div>
<p>Puis tester sur le lien https://ouestline.xyz<br />
<img src="/images/alpine-ouest04.png" alt="" /></p>
<p>Tester une autre configuration<br />
On va créer un fichier <code class="language-plaintext highlighter-rouge">/var/lib/caddy/index.html</code></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;title&gt;</span>Hello from Caddy!<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;h1</span> <span class="na">style=</span><span class="s">"font-family: sans-serif"</span><span class="nt">&gt;</span>This page is being served via Caddy<span class="nt">&lt;/h1&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>
<p>Modifier le fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/caddy/Caddyfile</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ouestline.xyz {
root * /var/lib/caddy
file_server
}
</code></pre></div></div>
<p>Il sagit dune configuration de base de Caddy, qui déclare que le domaine ouestline.xyz de votre serveur doit être servi avec des fichiers provenant de <code class="language-plaintext highlighter-rouge">/var/lib/caddy</code></p>
<p>On lance le service : <code class="language-plaintext highlighter-rouge">service caddy start</code> puis ouvre le lien https://ouestline.xyz<br />
<img src="/images/alpine-ouest05.png" alt="" width="400" /></p>
<p>Pour un lancement au démarrage de la machine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add caddy
</code></pre></div></div>
<h4 id="prise-en-charge-php">Prise en charge PHP</h4>
<p><em>Prérequis, PHP est installé avec php-fpm</em></p>
<p>Installer gzip et zstd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add gzip zstd
</code></pre></div></div>
<p>fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/caddy/Caddyfile</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>domain.tld {
root * /chemin/racine
encode gzip zstd
php_fastcgi 127.0.0.1:9000
file_server {
index index.html index.php;
}
}
</code></pre></div></div>
<p>Recharger</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>caddy fmt --overwrite /etc/caddy/Caddyfile
service caddy reload
</code></pre></div></div>
<h4 id="sites-https">Sites HTTPS</h4>
<p><strong>Sites : ouestline.xyz et sous-domaines static, osm, dice, tst et dev</strong></p>
<p>Modifier le fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/caddy/Caddyfile</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ouestline.xyz {
root * /mnt/nfs-share/alpine/default
php_fastcgi 127.0.0.1:9000
file_server {
index index.html index.php
}
}
static.ouestline.xyz {
root * /mnt/nfs-share/multimedia/Divers/static
file_server
}
osm.ouestline.xyz {
root * /mnt/nfs-share/multimedia/Divers/osm-new
file_server
}
dice.ouestline.xyz {
root * /mnt/nfs-share/multimedia/Divers/diceware
file_server
}
tst.ouestline.xyz {
root * /mnt/nfs-share/alpine/tst
file_server
}
dev.ouestline.xyz {
root * /mnt/nfs-share/alpine/dev
encode gzip zstd
php_fastcgi 127.0.0.1:9000
file_server
}
</code></pre></div></div>
<p>Reformater le fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>caddy fmt --overwrite /etc/caddy/Caddyfile
</code></pre></div></div>
<p>Recharger le service caddy</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service caddy reload
</code></pre></div></div>
<h3 id="samba-client-inactif">Samba client (INACTIF)</h3>
<p>Installer samba client</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add samba-client cifs-utils
</code></pre></div></div>
<p>Créer le dossier de montage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /mnt/nfs-share/
</code></pre></div></div>
<p>Le fichier dautorisation <code class="language-plaintext highlighter-rouge">/root/.smb-credentials</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>username=aluser
password=xxxxxxxxxxxxxxx
</code></pre></div></div>
<p>Tester le montage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mount -t cifs //192.168.0.215/thinkshare /mnt/nfs-share -o rw,credentials=/root/.smb-credentials,uid=aluser,gid=aluser
</code></pre></div></div>
<p>On a bien les droits utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/aluser # ls -la /mnt/nfs-share
total 4
drwxr-xr-x 2 aluser aluser 0 Dec 19 20:57 .
drwxr-xr-x 3 aluser aluser 4096 Dec 19 20:56 ..
-rwxr-xr-x 1 aluser aluser 0 Dec 19 20:57 test.txt
</code></pre></div></div>
<p>Le fichier /etc/fstab</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//192.168.0.215/thinkshare /mnt/sambashare cifs rw,credentials=/root/.smb-credentials,uid=aluser,gid=aluser
</code></pre></div></div>
<p>Activer le montage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add netmount boot
</code></pre></div></div>
<p><strong>Désinstaller samba client</strong><br />
Supprimer la ligne dans fstab<br />
Supprimer les paquets : <code class="language-plaintext highlighter-rouge">sudo apk del samba-client cifs-utils</code></p>
<p>Désinstaller le mount au boot : <code class="language-plaintext highlighter-rouge">sudo rc-update del netmount boot</code></p>
<h3 id="nfs">NFS</h3>
<p>Installer le paquet nfs</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apk add nfs-utils
</code></pre></div></div>
<p>Démarrage automatique</p>
<p>Exporter les répertoires dans /etc/exports, puis</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add nfs
</code></pre></div></div>
<p>Si vous avez besoin de monter un partage nfs à partir du fichier fstab au démarrage du système</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add nfsmount
</code></pre></div></div>
<p>ou</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add netmount
</code></pre></div></div>
<p>Vous pouvez vérifier les services de démarrage :</p>
<p>rc-status</p>
<p>Démarrez maintenant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service nfs start
</code></pre></div></div>
<p>ou si vous avez besoin de monter un partage nfs à partir du fichier fstab maintenant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service nfsmount start
</code></pre></div></div>
<p>ou</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service netmount start
</code></pre></div></div>
<p><strong>Montage du partage NFS disponible sur le réseau</strong></p>
<p>Création point de montage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /mnt/nfs-share
</code></pre></div></div>
<p>Ajout du partage réseau à fstab</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/fstab
</code></pre></div></div>
<p>Ligne à ajouter</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>192.168.0.215:/ /mnt/nfs-share nfs4 soft,intr,rsize=8192,wsize=8192
</code></pre></div></div>
<p>Lancer le service et vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rc-service nfsmount start
ls /mnt/nfs-share/
</code></pre></div></div>
<p>partage nfs à partir du fichier fstab au démarrage du système</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add nfsmount
</code></pre></div></div>
<h3 id="parefeu-nftables">Parefeu nftables</h3>
<p><em>Parmi les avantages de nftables sur iptables, il y a moins de duplication de code et plus de débit. nftables est configuré via lutilitaire espace utilisateur nft, tandis que netfilter est configuré via les utilitaires iptables, ip6tables, arptables et ebtables.</em></p>
<p>On installe le paquet nftables</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add nftables
</code></pre></div></div>
<p>Par défaut les régles <strong>Basic IPv4/IPv6 stateful firewall for server/workstation.</strong> présentes dans le fichier <code class="language-plaintext highlighter-rouge">/etc/nftables.nft</code> sont chargés</p>
<p>Modifier le fichier</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/sbin/nft -f</span>
<span class="c"># vim: set ts=4 sw=4:</span>
<span class="c"># You can find examples in /usr/share/nftables/.</span>
<span class="c"># Clear all prior state</span>
flush ruleset
<span class="c"># Basic IPv4/IPv6 stateful firewall for server/workstation.</span>
table inet filter <span class="o">{</span>
chain input <span class="o">{</span>
<span class="nb">type </span>filter hook input priority 0<span class="p">;</span> policy drop<span class="p">;</span>
iifname lo accept <span class="se">\</span>
comment <span class="s2">"Accept any localhost traffic"</span>
ct state <span class="o">{</span> established, related <span class="o">}</span> accept <span class="se">\</span>
comment <span class="s2">"Accept traffic originated from us"</span>
tcp dport http
tcp dport https
tcp dport 55216 accept <span class="se">\</span>
comment <span class="s2">"Port SSH 55216"</span>
ct state invalid drop <span class="se">\</span>
comment <span class="s2">"Drop invalid connections"</span>
tcp dport 113 reject with icmpx <span class="nb">type </span>port-unreachable <span class="se">\</span>
comment <span class="s2">"Reject AUTH to make it fail fast"</span>
<span class="c"># ICMPv4</span>
ip protocol icmp icmp <span class="nb">type</span> <span class="o">{</span>
echo-reply, <span class="c"># type 0</span>
destination-unreachable, <span class="c"># type 3</span>
echo-request, <span class="c"># type 8</span>
time-exceeded, <span class="c"># type 11</span>
parameter-problem, <span class="c"># type 12</span>
<span class="o">}</span> accept <span class="se">\</span>
comment <span class="s2">"Accept ICMP"</span>
<span class="c"># ICMPv6</span>
ip6 nexthdr icmpv6 icmpv6 <span class="nb">type</span> <span class="o">{</span>
destination-unreachable, <span class="c"># type 1</span>
packet-too-big, <span class="c"># type 2</span>
time-exceeded, <span class="c"># type 3</span>
parameter-problem, <span class="c"># type 4</span>
echo-request, <span class="c"># type 128</span>
echo-reply, <span class="c"># type 129</span>
<span class="o">}</span> accept <span class="se">\</span>
comment <span class="s2">"Accept basic IPv6 functionality"</span>
ip6 nexthdr icmpv6 icmpv6 <span class="nb">type</span> <span class="o">{</span>
nd-router-solicit, <span class="c"># type 133</span>
nd-router-advert, <span class="c"># type 134</span>
nd-neighbor-solicit, <span class="c"># type 135</span>
nd-neighbor-advert, <span class="c"># type 136</span>
<span class="o">}</span> ip6 hoplimit 255 accept <span class="se">\</span>
comment <span class="s2">"Allow IPv6 SLAAC"</span>
ip6 nexthdr icmpv6 icmpv6 <span class="nb">type</span> <span class="o">{</span>
mld-listener-query, <span class="c"># type 130</span>
mld-listener-report, <span class="c"># type 131</span>
mld-listener-reduction, <span class="c"># type 132</span>
mld2-listener-report, <span class="c"># type 143</span>
<span class="o">}</span> ip6 saddr fe80::/10 accept <span class="se">\</span>
comment <span class="s2">"Allow IPv6 multicast listener discovery on link-local"</span>
ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept <span class="se">\</span>
comment <span class="s2">"Accept DHCPv6 replies from IPv6 link-local addresses"</span>
<span class="o">}</span>
chain forward <span class="o">{</span>
<span class="nb">type </span>filter hook forward priority 0<span class="p">;</span> policy drop<span class="p">;</span>
<span class="o">}</span>
chain output <span class="o">{</span>
<span class="nb">type </span>filter hook output priority 0<span class="p">;</span> policy accept<span class="p">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c"># The state of stateful objects saved on the nftables service stop.</span>
include <span class="s2">"/var/lib/nftables/*.nft"</span>
<span class="c"># Rules</span>
include <span class="s2">"/etc/nftables.d/*.nft"</span>
</code></pre></div></div>
<p>Relancer nftables</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-service nftables restart
</code></pre></div></div>
<p>Vérifier les configurations : <code class="language-plaintext highlighter-rouge">nft list ruleset</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept comment "Accept any localhost traffic"
ct state { established, related } accept comment "Accept traffic originated from us"
tcp dport { 80, 443 } accept
tcp dport 55216 accept comment "Port SSH 55216"
ct state invalid drop comment "Drop invalid connections"
tcp dport 113 reject comment "Reject AUTH to make it fail fast"
ip protocol icmp icmp type { echo-reply, destination-unreachable, echo-request, time-exceeded, parameter-problem } accept comment "Accept ICMP"
ip6 nexthdr ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } accept comment "Accept basic IPv6 functionality"
ip6 nexthdr ipv6-icmp ip6 hoplimit 255 icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept comment "Allow IPv6 SLAAC"
ip6 nexthdr ipv6-icmp icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, mld2-listener-report } ip6 saddr fe80::/10 accept comment "Allow IPv6 multicast listener discovery on link-local"
ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept comment "Accept DHCPv6 replies from IPv6 link-local addresses"
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
</code></pre></div></div>
<p>nftables exécution et chargement des configurations lorsque le système démarre.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rc-update add nftables
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">* service nftables added to runlevel default</code></p>
<h3 id="accès-administration-via-sudo">Accès administration via sudo</h3>
<p>Installer sudo</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk update
apk add <span class="nb">sudo</span>
</code></pre></div></div>
<p>Ensuite, créons un nouvel utilisateur dans Alpine Linux et accordons des privilèges de sudo à lutilisateur nouvellement créé.</p>
<p><strong>Créer un utilisateur de sudo</strong></p>
<p>Pour créer un nouvel utilisateur dans Alpine Linux, nous utilisons la commande adduser</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adduser admi
</code></pre></div></div>
<p>Création du nouvel utilisateur nommé “admi”.</p>
<p>Saisissez le mot de passe deux fois pour le nouvel utilisateur et remplissez la création de lutilisateur.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Changing password for admi
New password:
Retype password:
passwd: password for admi changed by root
</code></pre></div></div>
<p>Nous venons de créer un nouvel utilisateur normal. Lutilisateur na pas encore de droits administratifs.</p>
<p>Vous pouvez vérifier si un utilisateur a des privilèges de sudo ou non dans Alpine Linux en utilisant la commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -lU admi
</code></pre></div></div>
<p>Sortie :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User admi is not allowed to run sudo on ouestline.
</code></pre></div></div>
<p>Ajoutons le nouvel utilisateur à la liste des sudoers, afin quil puisse effectuer des opérations administratives</p>
<p><strong>Accorder des privilèges de sudo aux utilisateurs</strong></p>
<p>Nous pouvons le faire de deux façons.</p>
<p><u>Méthode 1</u></p>
<p>Pour attribuer des permissions de sudo à un utilisateur dans Alpine Linux, il suffit de lajouter au groupe <strong>wheel</strong> qui est un groupe spécial dans certains systèmes dexploitation comme Unix. Tous les membres du groupe <strong>wheel</strong> peuvent effectuer des tâches administratives. Le groupe <strong>wheel</strong> est similaire au groupe de sudo dans les systèmes basés sur Debian.</p>
<p>Exécutez la commande suivante pour permettre aux membres du groupe <strong>wheel</strong> dexécuter nimporte quelle commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo '%wheel ALL=(ALL) ALL' &gt; /etc/sudoers.d/wheel
</code></pre></div></div>
<p>Puis ajouter lutilisateur “admi” au groupe wheel</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adduser admi wheel
</code></pre></div></div>
<p>Nous avons ajouté lutilisateur admi à la liste des sudoers.
Vérifiez si lutilisateur a accès au sudo</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -lU admi
</code></pre></div></div>
<p><u>Méthode 2</u></p>
<p>Une autre façon dattribuer les permissions de sudo à un utilisateur est de lajouter directement dans le fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/sudoers</code></p>
<p>Pour donner des permissions de sudo à lutilisateur “admi”, modifier le fichier “/etc/sudoers” :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>visudo
</code></pre></div></div>
<p>Ajouter la ligne suivante:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>admi ALL=(ALL) ALL
</code></pre></div></div>
<p><img src="/images/alpine-ouest14.png" alt="" /><br />
Editeur vi → ESC puis <code class="language-plaintext highlighter-rouge">:wq</code></p>
<p>Pour donner des permissions de sudo à lutilisateur “admi”, sans saisie mot de passe</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>admi ALL=(ALL) NOPASSWD: ALL
</code></pre></div></div>
<p><strong>Vérifiez si un utilisateur a accès au sudo</strong></p>
<p>Pour vérifier si un utilisateur a des droits sudo dans Alpine Linux, exécutez cette commande :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -lU admi
</code></pre></div></div>
<p>Sortie :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User admi may run the following commands on ouestline:
(ALL) ALL
</code></pre></div></div>
<p>Comme vous pouvez le voir, lutilisateur “admi” peut exécuter toutes les commandes</p>
<p>Passons au nouvel utilisateur de sudo et vérifions sil peut exécuter des tâches de sudo.<br />
Pour passer au nouvel utilisateur, cest-à-dire admi dans notre cas, exécutez :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su - admi
</code></pre></div></div>
<p>Exécutez toute opération de sudo pour vérifier si lutilisateur a vraiment des permissions de sudo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apk update
</code></pre></div></div>
<p><img src="/images/alpine-ouest15.png" alt="" /></p>
<p>Oui, lutilisateur fait partie du groupe des utilisateurs administratifs.</p>
<p><strong>Supprimer les privilèges sudo à un utilisateur</strong></p>
<p>Pour révoquer les autorisations de sudo dun utilisateur dans Alpine Linux, il suffit de le supprimer du groupe wheel en utilisant la commande <code class="language-plaintext highlighter-rouge">gpasswd</code>. La commande <code class="language-plaintext highlighter-rouge">gpasswd</code> nest pas disponible dans limage de base alpine. Vous devez installer le paquet <code class="language-plaintext highlighter-rouge">shadow</code> afin dobtenir la commande <code class="language-plaintext highlighter-rouge">gpasswd</code>.</p>
<p>Pour installer le paquet shadow dans Alpine Linux, exécutez la commande suivante en tant quutilisateur root :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk add shadow
</code></pre></div></div>
<p>Maintenant, vous pouvez supprimer les privilèges de sudo dun utilisateur, par exemple ostechnix, en utilisant la commande:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpasswd -d admi wheel
</code></pre></div></div>
<p>Sortie :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Removing user admi from group wheel
</code></pre></div></div>
<p>Lutilisateur admi a été retiré du groupe de roues. Vous pouvez le vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -lU admi
</code></pre></div></div>
<p>Lutilisateur admi est maintenant devenu un utilisateur régulier. Il ne peut plus effectuer dopérations de sudo.</p>
<p>Si vous ne voulez plus de cet utilisateur, retirez-le entièrement du système en utilisant cette commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>userdel -r admi
</code></pre></div></div>
<p>Ici, le drapeau <code class="language-plaintext highlighter-rouge">-r</code> est utilisé pour supprimer le répertoire <code class="language-plaintext highlighter-rouge">$HOME</code> de lutilisateur.</p>
<h3 id="openssh-avec-clés">OpenSSH avec clés</h3>
<p><em>Connexion ssh sur un autre port avec un jeu de clés</em></p>
<p>Générer une paire de clé sur lordinateur de bureau PC1<br />
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) pour une liaison SSH avec le serveur.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/alpine-vm
</code></pre></div></div>
<p>Copier la clé publique <code class="language-plaintext highlighter-rouge">alpine-vm.pub</code> dans le presse-papier</p>
<p>On se connecte sur la machine virtuelle alpine linux</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh aluser@192.168.0.216
</code></pre></div></div>
<p>Créer le répertoire et ouvrir nouveau fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p $HOME/.ssh/
nano $HOME/.ssh/authorized_keys
</code></pre></div></div>
<p>Coller le contenu du presse-papier , sauver le fichier et sortir</p>
<p>Passer en mode su</p>
<p>Modifier la configuration serveur SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/ssh/sshd_config
</code></pre></div></div>
<p>Modifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Port = 55216
PasswordAuthentication no
</code></pre></div></div>
<p>Relancer le serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service sshd restart
</code></pre></div></div>
<p>Modifier /etc/motd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> _ _ _ ___ _
/_\ | | _ __ (_) _ _ ___ / _ \ _ _ ___ ___| |_
/ _ \ | || '_ \| || ' \ / -_)| (_) || || |/ -_)(_-&lt;| _|
/_/ \_\|_|| .__/|_||_||_|\___| \___/ \_,_|\___|/__/ \__|
|_| _ _ _
___ _ _ ___ ___| |_ | |(_) _ _ ___ __ __ _ _ ___
/ _ \| || |/ -_)(_-&lt;| _|| || || ' \ / -_) _ \ \ /| || ||_ /
\___/ \_,_|\___|/__/ \__||_||_||_||_|\___|(_)/_\_\ \_, |/__|
_ ___ ___ _ __ ___ __ ___ _ __|__/
/ |/ _ \|_ ) / | / / ( _ ) / \ |_ )/ | / /
| |\_, / / / _ | |/ _ \/ _ \ _| () |_ / / | |/ _ \
|_| /_/ /___|(_)|_|\___/\___/(_)\__/(_)/___||_|\___/
</code></pre></div></div>
<p>Test connexion</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -p 55216 -i ~/.ssh/alpine-vm aluser@192.168.0.216
</code></pre></div></div>
<h2 id="utilitaires">Utilitaires</h2>
<h3 id="iproute2">iproute2</h3>
<p>Vous pouvez souhaiter installer le paquet iproute2 (à noter que cela installera également iptables si ce nest pas encore installé)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apk ajouter iproute2
</code></pre></div></div>
<p>Cela fournit la commande ss qui est IMHO une version meilleure de netstat.</p>
<p>Afficher les ports tcp découte</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss -tl
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 0 0.0.0.0:55216 0.0.0.0:*
LISTEN 0 0 127.0.0.1:2019 0.0.0.0:*
LISTEN 0 0 127.0.0.1:9000 0.0.0.0:*
LISTEN 0 0 *:55216 *:*
LISTEN 0 0 *:https *:*
LISTEN 0 0 *:http *:*
</code></pre></div></div>
<p>Afficher les ports découte tcp et les processus associés:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss -ptl
</code></pre></div></div>
<p>Afficher lécoute et les connexions tcp établies :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss -ta
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 0 0.0.0.0:55216 0.0.0.0:*
LISTEN 0 0 127.0.0.1:2019 0.0.0.0:*
LISTEN 0 0 127.0.0.1:9000 0.0.0.0:*
ESTAB 0 0 192.168.0.216:55216 192.168.0.39:60300
ESTAB 0 0 192.168.0.216:56326 192.168.0.215:microsoft-ds
LISTEN 0 0 *:55216 *:*
LISTEN 0 0 *:https *:*
LISTEN 0 0 *:http *:*
</code></pre></div></div>
<p>Afficher le résumé dutilisation de la socket :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss -s
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Total: 17
TCP: 8 (estab 2, closed 0, orphaned 0, timewait 0)
Transport Total IP IPv6
RAW 0 0 0
UDP 1 0 1
TCP 8 5 3
INET 9 5 4
FRAG 0 0 0
</code></pre></div></div>
<p>Afficher plus doptions :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss -h
</code></pre></div></div>
<h3 id="drill">drill</h3>
<p>Vous pouvez également vouloir installer drill (il installera également le paquet ldns) qui est un remplacement supérieur (IMHO) pour nslookup et dig etc</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apk add drill
</code></pre></div></div>
<p>Alors utilisez-le comme vous le feriez avec dig</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drill @8.8.8.8 alpinlinux.org
</code></pre></div></div>
<p>Pour effectuer une recherche inversée (obtenir un nom depuis une IP) utilisez la syntaxe suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drill @208.67.222.222 -x 8.8.8.8
</code></pre></div></div>
<h3 id="postfix">postfix</h3>
<p><em>Envoyer des messages en ligne de commande depuis le serveur alpine linux</em></p>
<p>Installation postfix et mailx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apk add postfix
sudo apk add mailx
</code></pre></div></div>
<p>Ajouter les lignes suivantes au fichier de configuration <code class="language-plaintext highlighter-rouge">/etc/postfix/main.cf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>myhostname = ouestline.xyz
mydomain = ouestline.xyz
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
inet_interfaces = loopback-only
</code></pre></div></div>
<p>Recharger postfix</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo service postfix restart
</code></pre></div></div>
<p>Envoyer un message</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "Test envoi via postfix smtp" | mail -s "serveur alpine linux" yack@cinay.eu
</code></pre></div></div>
<p>Sur la boîte de réception<br />
<img src="/images/alpine-ouest17.png" alt="" /></p>
<h3 id="chroot">chroot</h3>
<p><em>On veut modifier linterface réseau de la Machine virtuelle AlpineOuest</em></p>
<p>Il faut arrêter la machine virtuelle AlpineOuest pour la faire redémarrer sur une image ISO<br />
<img src="/images/alpine-chroot01.png" alt="" /></p>
<p>Booter sur une image ISO Alpine Linux</p>
<p>Passer le clavier en fr (qwerty de base)<br />
<img src="/images/alpine-chroot03.png" alt="" /><br />
<img src="/images/alpine-chroot04.png" alt="" /></p>
<p>Montage de la partion à chrooter /dev/vda3</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mount /dev/vda3 /mnt
</code></pre></div></div>
<p>Passage en chroot</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chroot</span> /mnt /bin/ash
</code></pre></div></div>
<p><img src="/images/alpine-chroot02.png" alt="" /></p>
<p>Modifier ladresse<br />
<img src="/images/alpine-chroot05.png" alt="" /></p>
<p>Sortie chroot et arrêt</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">exit
</span>poweroff
</code></pre></div></div>
<p>Modifier lordre de démarrage et désactiver le cd-rom<br />
<img src="/images/alpine-chroot06.png" alt="" /></p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2023-12-22T00: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="/2023/12/17/Installer_KVM_Kernel_Virtual_Machine_sur_un_serveur.html">Installer KVM (Kernel Virtual Machine) sur un serveur</a></div><div class="next"><span>SUIVANT</span><a href="/2023/12/22/Caddy_serveur.html">Caddy serveur</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>