yannstatic/static/2019/07/10/OVH-vps626865-SSD1-KVM-OpenStack(yanspm.com).html

3710 lines
267 KiB
HTML
Raw Permalink Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>OVH VPS SSD 1 KVM OpenStack (1 vCore/2GoRam/20GoSSD) domaine yanspm.com - YannStatic</title>
<meta name="description" content="Debian Stretch yanspm.com">
<link rel="canonical" href="https://static.rnmkcy.eu/2019/07/10/OVH-vps626865-SSD1-KVM-OpenStack(yanspm.com).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;">OVH VPS SSD 1 KVM OpenStack (1 vCore/2GoRam/20GoSSD) domaine yanspm.com</h1></header></div><meta itemprop="headline" content="OVH VPS SSD 1 KVM OpenStack (1 vCore/2GoRam/20GoSSD) domaine yanspm.com"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=serveur">serveur</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">10&nbsp;juil.&nbsp;2019</span>
<span title="Modification" style="color:#00FF7F">&nbsp;2&nbsp;oct.&nbsp;&nbsp;2019</span></li></ul></div><meta itemprop="datePublished" content="2019-10-02T00:00:00+02:00">
<meta itemprop="keywords" content="serveur"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h1 id="debian-stretch-yanspmcom">Debian Stretch yanspm.com</h1>
<h2 id="kvm-openstack-ovh-2-gb-mémoire-1-cpu-20-gb-ssd-100-mbps">KVM OpenStack OVH (2 GB Mémoire, 1 CPU, 20 GB SSD, 100 Mbps)</h2>
<p><img src="/images/debian9a.png" alt="Debian 9" width="100" /></p>
<p>Package: 2 GB Mémoire, 1 CPU, 20 GB SSD, 100 Mbps<br />
Selected Location: Strasbourg<br />
Debian Stretch 64<br />
Livraison : vps626865</p>
<ul>
<li>IPv4 du serveur : 51.77.192.45</li>
<li>IPv6 du serveur : 2001:41d0:0404:0200:0000:0000:0000:0c11</li>
<li>IPV6 gateway : 2001:41d0:0404:0200:0000:0000:0000:0001</li>
</ul>
<h3 id="vps-ovh--activation-ipv6">VPS OVH , activation IPV6</h3>
<p>Connexion sur “OVH8 VPS SSD 3 KVM 2 vCore(s) Ram 8Go SSD 40Go Debian Stretch”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh root@51.77.192.45
</code></pre></div></div>
<p>Sur le VPS OVH il faut désactiver linitialisation réseau par le cloud</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
</code></pre></div></div>
<p>Création du fichier <strong>/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg</strong> en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "network: {config: disabled}" &gt; /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
</code></pre></div></div>
<p>Le fichier <strong>/etc/network/interfaces</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>auto lo
iface lo inet loopback
auto ens3
iface ens3 inet dhcp
iface ens3 inet6 static
address 2001:41d0:0404:0200:0000:0000:0000:0c11
netmask 128
post-up /sbin/ip -6 route add 2001:41d0:0404:0200:0000:0000:0000:0001 dev ens3
post-up /sbin/ip -6 route add default via 2001:41d0:0404:0200:0000:0000:0000:0001 dev ens3
pre-down /sbin/ip -6 route del default via 2001:41d0:0404:0200:0000:0000:0000:0001 dev ens3
pre-down /sbin/ip -6 route del 2001:41d0:0404:0200:0000:0000:0000:0001 dev ens3
</code></pre></div></div>
<blockquote>
<p>Redémarrer la machine <code class="language-plaintext highlighter-rouge">systemctl reboot</code> pour la prise en compte des modifications du réseau</p>
</blockquote>
<p>Vérifier le réseau <code class="language-plaintext highlighter-rouge">ip addr</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens3: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether fa:16:3e:27:b7:ff brd ff:ff:ff:ff:ff:ff
inet 51.77.192.45/32 brd 51.77.192.45 scope global ens3
valid_lft forever preferred_lft forever
inet6 2001:41d0:404:200::c11/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fe27:b7ff/64 scope link
valid_lft forever preferred_lft forever
</code></pre></div></div>
<h3 id="mise-à-jour-debian-et-installation-des-utilitaires">Mise à jour Debian et installation des utilitaires</h3>
<p>Màj</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update &amp;&amp; apt upgrade
</code></pre></div></div>
<p>Installer utilitaires</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install rsync curl tmux jq figlet git mailutils dnsutils -y
</code></pre></div></div>
<h3 id="configurer-locales-fr-et-en">Configurer Locales (fr et en)</h3>
<p>Locales : <strong>fr_FR.UTF-8</strong> et <strong>en_US.UTF-8</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dpkg-reconfigure locales
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Generating locales <span class="o">(</span>this might take a <span class="k">while</span><span class="o">)</span>...
fr_FR.UTF-8... <span class="k">done
</span>en_US.UTF-8... <span class="k">done
</span>Generation complete.
</code></pre></div></div>
<h3 id="europeparis-timezone-tzdata">Europe/Paris (TimeZone tzdata)</h3>
<p>Europe/Paris</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dpkg-reconfigure tzdata
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Current default time zone: 'Europe/Paris'
Local time is now: Sun Mar 18 19:49:55 CET 2018.
Universal Time is now: Sun Mar 18 18:49:55 UTC 2018.
</code></pre></div></div>
<h3 id="création-utilisateur">Création utilisateur</h3>
<p>Utilisateur <strong>yanspm</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /home/yanspm/ -s /bin/bash yanspm
</code></pre></div></div>
<p>Mot de passe <strong>yanspm</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd yanspm
</code></pre></div></div>
<p>Visudo pour les accès root via utilisateur <strong>yanspm</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install sudo</span> <span class="c"># installé par défaut</span>
<span class="nb">echo</span> <span class="s2">"yanspm ALL=(ALL) NOPASSWD: ALL"</span> <span class="o">&gt;&gt;</span> /etc/sudoers
</code></pre></div></div>
<p>Changer le mot de passe root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd root
</code></pre></div></div>
<p>Déconnexion puis connexion ssh en mode utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh yanspm@51.77.192.45
</code></pre></div></div>
<h3 id="hostname">Hostname</h3>
<p>Exécuter les instructions suivantes en mode su<br />
Configuration OVH à modifier <strong>/etc/cloud/cloud.cfg</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>preserve_hostname: true
manage_etc_hosts: false
</code></pre></div></div>
<p>Modifier <strong>hostname</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostnamectl set-hostname --static yanspm.com
</code></pre></div></div>
<p>Modifier <strong>/etc/hosts</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/hosts
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>127.0.1.1 yanspm.com vps626865
127.0.0.1 localhost
</code></pre></div></div>
<p>Vérifications</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostnamectl
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Static hostname: yanspm.com
Icon name: computer-vm
Chassis: vm
Machine ID: ae99d55cea1e4ccabe7432b2fa05d502
Boot ID: 99269b96a32745bd868938d0f717bb89
Virtualization: kvm
Operating System: Debian GNU/Linux 9 (stretch)
Kernel: Linux 4.9.0-8-amd64
Architecture: x86-64
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostname --fqdn
yanspm.com
</code></pre></div></div>
<h3 id="ovh-dns-fournisseur-domaine">OVH DNS fournisseur domaine</h3>
<p>Domaine <strong>yanspm.com</strong> distribué par OVH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 86400
@ IN SOA dns101.ovh.net. tech.ovh.net. (2018121601 86400 3600 3600000 300)
3600 IN NS dns101.ovh.net.
3600 IN NS ns101.ovh.net.
3600 IN A 51.77.192.45
3600 IN AAAA 2001:41d0:404:200::c11
* 3600 IN CNAME yanspm.com.
</code></pre></div></div>
<h3 id="openssh-clé-et-script">OpenSSH, clé et script</h3>
<p><img src="/images/ssh_logo1.png" alt="OpenSSH" width="100" /></p>
<p><strong>connexion avec clé</strong><br />
<u>sur l'ordinateur de bureau</u>
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) nommé <strong>kvm-cinay</strong> pour une liaison SSH avec le serveur KVM.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/kvm-vps626865
</code></pre></div></div>
<p>Envoyer la clé publique sur le serveur KVM</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scp ~/.ssh/kvm-vps626865.pub yanspm@51.77.192.45:/home/yanspm/
</code></pre></div></div>
<p><u>sur le serveur KVM</u>
On se connecte</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh yanspm@51.77.192.45
</code></pre></div></div>
<p>Copier le contenu de la clé publique dans /home/$USER/.ssh/authorized_keys</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
</code></pre></div></div>
<p>Sur le KVM ,créer un dossier .ssh</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> .ssh
<span class="nb">cat</span> <span class="nv">$HOME</span>/kvm-vps626865.pub <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.ssh/authorized_keys
</code></pre></div></div>
<p>et donner les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 600 $HOME/.ssh/authorized_keys
</code></pre></div></div>
<p>effacer le fichier de la clé</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm $HOME/kvm-vps626865.pub
</code></pre></div></div>
<p>Modifier la configuration serveur SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/ssh/sshd_config
</code></pre></div></div>
<p>Modifier</p>
<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Port</span> = <span class="m">55031</span>
<span class="n">PermitRootLogin</span> <span class="n">no</span>
<span class="n">PasswordAuthentication</span> <span class="n">no</span>
</code></pre></div></div>
<p><u>session SSH ne se termine pas correctement lors d'un "reboot" à distance</u><br />
Si vous tentez de <strong>redémarrer/éteindre</strong> une machine distance par <strong>ssh</strong>, vous pourriez constater que votre session ne se termine pas correctement, vous laissant avec un terminal inactif jusquà lexpiration dun long délai dinactivité. Il existe un bogue 751636 à ce sujet. Pour linstant, la solution de contournement à ce problème est dinstaller :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install libpam-systemd
</code></pre></div></div>
<p>cela terminera la session ssh avant que le réseau ne tombe.<br />
Veuillez noter quil est nécessaire que PAM soit activé dans sshd.</p>
<p>Relancer openSSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart sshd
</code></pre></div></div>
<p>Accès depuis le poste distant avec la clé privée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -p 55031 -i ~/.ssh/kvm-vps626865 yanspm@yanspm.com
</code></pre></div></div>
<p><strong>Exécution script sur connexion</strong><br />
Exécuter un fichier <em>utilisateur</em> nommé <strong>$HOME/.ssh/rc</strong> si <em>présent</em><br />
Pour <em>tous les utilisateurs</em> exécuter un fichier nommé <strong>/etc/ssh/sshrc</strong> si <em>présent</em><br />
Installer les utilitaires <em>curl jq figlet</em></p>
<p>Le batch</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/.ssh/rc
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c">#clear</span>
<span class="nv">PROCCOUNT</span><span class="o">=</span><span class="sb">`</span>ps <span class="nt">-Afl</span> | <span class="nb">wc</span> <span class="nt">-l</span><span class="sb">`</span> <span class="c"># nombre de lignes</span>
<span class="nv">PROCCOUNT</span><span class="o">=</span><span class="sb">`</span><span class="nb">expr</span> <span class="nv">$PROCCOUNT</span> - 5<span class="sb">`</span> <span class="c"># on ote les non concernées</span>
<span class="nv">GROUPZ</span><span class="o">=</span><span class="sb">`</span><span class="nb">users</span><span class="sb">`</span>
<span class="nv">ipinfo</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-s</span> ipinfo.io<span class="si">)</span> <span class="c"># info localisation format json</span>
<span class="nv">publicip</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$ipinfo</span> | jq <span class="nt">-r</span> <span class="s1">'.ip'</span><span class="si">)</span> <span class="c"># extraction des données , installer préalablement "jq"</span>
<span class="nv">ville</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$ipinfo</span> | jq <span class="nt">-r</span> <span class="s1">'.city'</span><span class="si">)</span>
<span class="nv">pays</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$ipinfo</span> | jq <span class="nt">-r</span> <span class="s1">'.country'</span><span class="si">)</span>
<span class="nv">cpuname</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat</span> /proc/cpuinfo |grep <span class="s1">'model name'</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f2</span> | <span class="nb">sed</span> <span class="nt">-n</span> 1p<span class="sb">`</span>
<span class="nv">iplink</span><span class="o">=</span><span class="sb">`</span>ip <span class="nb">link </span>show |grep <span class="nt">-m</span> 1 <span class="s2">"2:"</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span><span class="sb">`</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[0m</span><span class="se">\0</span><span class="s2">33[1;31m"</span>
figlet <span class="s2">"</span><span class="sb">`</span><span class="nb">hostname</span> <span class="nt">--fqdn</span><span class="sb">`</span><span class="s2">"</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[0m
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mHostname </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">hostname</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mWired IpV4 </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span>ip addr show <span class="nv">$iplink</span> | <span class="nb">grep</span> <span class="s1">'inet\b'</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>/ <span class="nt">-f1</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mWired IpV6 </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span>ip addr show <span class="nv">$iplink</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'inet6'</span> |grep <span class="nt">-E</span> <span class="s1">'scope link'</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>/ <span class="nt">-f1</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mKernel </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">uname</span> <span class="nt">-r</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mDebian </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">cat</span> /etc/debian_version<span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mUptime </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">uptime</span> | <span class="nb">sed</span> <span class="s1">'s/.*up ([^,]*), .*/1/'</span> | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s1">'s/^[ \t]*//'</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mCPU </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">echo</span> <span class="nv">$cpuname</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mMemory Use </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span>free <span class="nt">-m</span> | <span class="nb">awk</span> <span class="s1">'NR==2{printf "%s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mUsername </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">whoami</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mSessions </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">who</span> | <span class="nb">grep</span> <span class="nv">$USER</span> | <span class="nb">wc</span> <span class="nt">-l</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mPublic IpV4 </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span><span class="nb">echo</span> <span class="nv">$publicip</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[1;35m </span><span class="se">\0</span><span class="s2">33[1;37mPublic IpV6 </span><span class="se">\0</span><span class="s2">33[1;35m= </span><span class="se">\0</span><span class="s2">33[1;32m</span><span class="sb">`</span>ip addr show <span class="nv">$iplink</span> | <span class="nb">grep</span> <span class="nt">-m</span> 1 <span class="s1">'inet6\b'</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>/ <span class="nt">-f1</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[0m"</span>
<span class="nb">df</span> <span class="nt">-h</span> /
<span class="c">#curl fr.wttr.in/$ville?0</span>
</code></pre></div></div>
<p>Effacer motd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/motd
</code></pre></div></div>
<p>Déconnexion puis connexion</p>
<h3 id="systemdjournal">systemd/journal</h3>
<p>Ajout de lutilisateur courant au groupe systemd-journal</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a $USER systemd-journal
</code></pre></div></div>
<p>Accès utilisateur aux fichiers log</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a $USER adm
</code></pre></div></div>
<p>Après déconnexion puis reconnexion , lutilisateur a accès au journal:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl
</code></pre></div></div>
<p>Pour avoir les lignes NON TRONQUEES</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export SYSTEMD_LESS=FRXMK journalctl
</code></pre></div></div>
<p>Pour un mode permanent ,modifier <strong>~/.bashrc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "export SYSTEMD_LESS=FRXMK journalctl" &gt;&gt; ~/.bashrc
</code></pre></div></div>
<h3 id="nginx-php7-mariadb">Nginx PHP7 MariaDb</h3>
<p><img src="/images/nginx-php7-mariadb1.png" alt="lemp" title="lemp" width="100" /></p>
<ul>
<li><a href="https://websiteforstudents.com/install-php-7-3-php-7-3-fpm-with-apache2-nginx-on-ubuntu-16-04-18-04-18-10/">PHP 7.3 for Nginx</a></li>
<li><a href="http://jc.etiemble.free.fr/abc/index.php/trucs-astuces/lamp/deb9php73">Debian 9.x + PHP 7.3.x</a></li>
</ul>
<p>Script nommé <strong>debian9-compilation-nginx-tls1.3-php7.3-MariaDB.sh.txt</strong> pour compiler et installer nginx, openssl + tlsv1.3, php7.3 et MariaDB sur debian stretch <a href="https://static.rnmkcy.eu/files/debian9-compilation-nginx-tls1.3-php7.3-MariaDB.sh.txt">Téléchargement script</a></p>
<p>Définition des chemins et fichiers de configuration nginx<br />
<strong>/etc/nginx/conf.d/yanspm.com.conf</strong> configuration de base du domaine<br />
Création dossier <strong>/etc/nginx/conf.d/yanspm.com.d/</strong> pour les fichiers de configuration supplémentaires</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /etc/nginx/conf.d/yanspm.com.d
</code></pre></div></div>
<p>Déplacer et renommer le fichier de configuration par défaut</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/yanspm.com.conf
</code></pre></div></div>
<p>Modifier le fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/yanspm.com.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
root /var/www/ ;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
</code></pre></div></div>
<p>Recharger</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl reload nginx
</code></pre></div></div>
<p>Activer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable nginx
</code></pre></div></div>
<p><strong>MariaDb</strong></p>
<p>Installer MariaDb :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install mariadb-server -y
</code></pre></div></div>
<p>Initialiser le mot de passe root ( ) + sécurisation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mysql_secure_installation
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter current password for root (enter for none):
Set root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
</code></pre></div></div>
<p><strong>MariaDB mot de passe pour root</strong><br />
Même après avoir exécuté <em>mysql_secure_installation</em>, lutilisateur <strong>root</strong> na toujours pas besoin de mot de passe.<br />
Voici la solution</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
mysql -u root
MariaDB [(none)]&gt; use mysql;
MariaDB [mysql]&gt; update user set plugin='' where User='root';
MariaDB [mysql]&gt; flush privileges;
</code></pre></div></div>
<blockquote>
<p>ATTENTION!!! Lutilisation dun mot de passe “root” entraîne une erreur de rotation des logs sur mysql</p>
</blockquote>
<p>Message derreur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/cron.daily/logrotate:
mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'root'@'localhost' (using password: NO)'
error: error running shared postrotate script for '/var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log /var/log/mysql/mariadb-slow.log /var/log/mysql/error.log '
run-parts: /etc/cron.daily/logrotate exited with return code 1
</code></pre></div></div>
<p>Il faut un mot de passe pour se connecter en “root” à la base mysql qui nest pas fourni dans la commande du fichier de configuration logrotate <strong>/etc/logrotate.d/mysql-server</strong>, modifier le fichier<br />
Remplacer les lignes</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mysqladmin --defaults-file=/etc/mysql/debian.cnf --local flush-error-log \
flush-engine-log flush-general-log flush-slow-log
</code></pre></div></div>
<p>Par les lignes suivantes</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mysqladmin --defaults-file=/etc/mysql/debian.cnf --local flush-error-log \
flush-engine-log flush-general-log flush-slow-log \
-uroot -p$(cat /etc/mysql/mdp )
</code></pre></div></div>
<p>Lancer manuellement “logrotate” pour vérification</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/sbin/logrotate /etc/logrotate.conf
</code></pre></div></div>
<p><strong>MariaDb installer la version 10.3 (janvier 2019)</strong></p>
<p>Ajouter la clé et le dépôt</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install software-properties-common dirmngr
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://ftp.igh.cnrs.fr/pub/mariadb/repo/10.3/debian stretch main'
</code></pre></div></div>
<p>Installer mariadb 10.3</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get update
sudo apt-get install mariadb-server
</code></pre></div></div>
<h3 id="unbound-résolveur-dns">Unbound (résolveur DNS)</h3>
<p><img src="/images/unbound-250.png" alt="DNS Unbound" width="100" /></p>
<p><em>Les serveurs DNS sont des machines discutant entre elles afin de se communiquer les correspondances entre nom de domaine et adresses IP. Voir le lien <a href="/2018/04/27/unbound-resolveur-DNS.html">DNS Unbound</a></em></p>
<p>Adresse mail dans la variable <code class="language-plaintext highlighter-rouge">REPORT_EMAIL="admin@desti.tld"</code> du fichier <strong>/etc/unbound/dnsunbound-update-root-dns.sh</strong></p>
<h3 id="quad9-résolveur-dns-sécurisé">Quad9 (résolveur DNS sécurisé)</h3>
<p><img src="/images/quad9-logo.png" alt="quad9" width="100" /><br />
A utiliser avec unbound<br />
Voir le lien <a href="/2019/01/07/quad9-dns-resolver-secure.html">Quad9 résolveur DNS public accessible de manière sécurisée (DNS sur TLS)</a></p>
<h3 id="certificats-ssl-letsencrypt-acme">Certificats SSL letsencrypt (acme)</h3>
<p><img src="/images/letsencrypt-logo1.png" alt="SSL Letsencrypt" width="100" /><br />
<a href="https://yann.cinay.eu/2017/08/31/Acme-Certficats-Serveurs.html">installer et renouveler les certificats SSL Lets encrypt </a></p>
<p>Installer acme</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
sudo -s # en mode super utilisateur
apt install netcat -y # prérequis
git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh
./acme.sh --install # --nocron
cd ..
rm -rf acme.sh/
</code></pre></div></div>
<p>Ajouter les variables pour laccès api OVH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export OVH_AK="Lj45UFRTDESDnnh5"
export OVH_AS="J582RTDESDnnh5rhDE89ZFSxng58aKL"
</code></pre></div></div>
<p>Génération des certificats (le wildcard est autorisé)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/root/.acme.sh/acme.sh --dns dns_ovh --issue --keylength ec-384 -d 'yanspm.com' -d '*.yanspm.com'
</code></pre></div></div>
<p>Il faut sidentifier chez OVH , un lien est fourni dans le résultat <code class="language-plaintext highlighter-rouge">Please open this link to do authentication: https://eu.api.ovh.com/auth/?credentialToken=kdfyjvuioiogg265bhbgdfbghh</code><br />
Sélectionner <code class="language-plaintext highlighter-rouge">validity : unlimited</code> et <strong>login</strong> , vous obtiendrez le message suivant <code class="language-plaintext highlighter-rouge">OVH authentication Success !</code> .<br />
Il faut relancer la commande et patienter quelques minutes…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/root/.acme.sh/acme.sh --dns dns_ovh --issue --keylength ec-384 -d 'yanspm.com' -d '*.yanspm.com'
</code></pre></div></div>
<p>Certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
[jeudi 23 mai 2019, 10:40:08 (UTC+0200)] Your cert is in /root/.acme.sh/yanspm.com_ecc/yanspm.com.cer
[jeudi 23 mai 2019, 10:40:08 (UTC+0200)] Your cert key is in /root/.acme.sh/yanspm.com_ecc/yanspm.com.key
[jeudi 23 mai 2019, 10:40:09 (UTC+0200)] The intermediate CA cert is in /root/.acme.sh/yanspm.com_ecc/ca.cer
[jeudi 23 mai 2019, 10:40:09 (UTC+0200)] And the full chain certs is there: /root/.acme.sh/yanspm.com_ecc/fullchain.cer
</code></pre></div></div>
<p>Création des liens sur <strong>/etc/ssl/private</strong> pour nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ln -s /root/.acme.sh/yanspm.com_ecc/fullchain.cer /etc/ssl/private/yanspm.com-fullchain.pem # full chain certs
ln -s /root/.acme.sh/yanspm.com_ecc/yanspm.com.key /etc/ssl/private/yanspm.com-key.pem # cert key
ln -s /root/.acme.sh/yanspm.com_ecc/yanspm.com.cer /etc/ssl/private/yanspm.com-chain.pem # cert
ln -s /root/.acme.sh/yanspm.com_ecc/ca.cer /etc/ssl/private/yanspm.com-ca.pem # intermediate CA cert
</code></pre></div></div>
<p>Vérification de la mise à jour automatique</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
9 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" &gt; /dev/null
</code></pre></div></div>
<blockquote>
<p>NOTE: Sous-domaines <strong>nc.yanspm.com -&gt; Nextcloud , imap smtp et mail</strong></p>
</blockquote>
<h3 id="nginx--ssl--diffie-hellmann--entêtes">Nginx + SSL + Diffie-Hellmann + Entêtes</h3>
<p><strong>ssl</strong><br />
Il faut préalablement demander des certificats (ca+key) SSL pour le domaine auprès dune autorité de certification (lets encrypt ou autre)<br />
Le fichier de configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/ssl_params
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssl_certificate /etc/ssl/private/yanspm.com-fullchain.pem;
ssl_certificate_key /etc/ssl/private/yanspm.com-key.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_prefer_server_ciphers on;
# Ciphers with modern compatibility
# New protocol TLSv1.3
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
</code></pre></div></div>
<p><strong>Diffie-Hellmann</strong><br />
Générer une clé Diffie-Hellmann<br />
<em>Lalgorithme Diffie-Hellman est un algorithme déchange de clés, utilisé notamment lors de louverture dune connexion à un site sécurisé via le protocole SSL/TLS.</em></p>
<p>Générer une clé Diffie Hellman (patienter quelques minutes)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
</code></pre></div></div>
<p>Ajouter la ligne suivante au fichier <strong>ssl_params</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl_dhparam /etc/ssl/private/dh2048.pem;
</code></pre></div></div>
<p><strong>Entêtes</strong><br />
Le fichier de configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/header_params
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
# https://observatory.mozilla.org/
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header Content-Security-Policy "upgrade-insecure-requests";
add_header Content-Security-Policy-Report-Only "default-src https: data: 'unsafe-inline' 'unsafe-eval'";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options "SAMEORIGIN";
</code></pre></div></div>
<p>On change le dossier racine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /var/www/default-www
sudo mv /var/www/index.html /var/www/default-www/
</code></pre></div></div>
<p>Configuration de base avec SSL et sécurité + letsencrypt (renouvellement)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/yanspm.com.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yanspm.com;
#### Locations
# On cache les fichiers statiques
location ~* \.(html|css|js|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires max; }
# On interdit les dotfiles
location ~ /\. { deny all; }
include ssl_params;
include header_params;
root /var/www/default-www ;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# if folder yanspm.com.d , uncomment the following directive
#include conf.d/yanspm.com.d/*.conf;
access_log /var/log/nginx/yanspm.com-access.log;
error_log /var/log/nginx/yanspm.com-error.log;
}
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
</code></pre></div></div>
<p>Relancer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl reload nginx
</code></pre></div></div>
<p>Test redirection http/https avec curl depuis un poste distant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -I yanspm.com
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Server: nginx/1.15.5
Date: Sat, 22 Dec 2018 16:13:31 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://yanspm.com/
</code></pre></div></div>
<p>Tester le lien <a href="https://yanspm.com">https://yanspm.com</a></p>
<p>Vérifier les entêtes depuis un autre poste</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -I https://yanspm.com
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/2 200
server: nginx/1.15.5
content-type: text/html
content-length: 867
last-modified: Wed, 19 Dec 2018 16:41:58 GMT
etag: "5c1a74d6-363"
expires: Thu, 31 Dec 2037 23:55:55 GMT
cache-control: max-age=315360000
strict-transport-security: max-age=63072000; includeSubDomains; preload
content-security-policy: upgrade-insecure-requests
content-security-policy-report-only: default-src https: data: 'unsafe-inline' 'unsafe-eval'
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-download-options: noopen
x-permitted-cross-domain-policies: none
x-frame-options: SAMEORIGIN
accept-ranges: bytes
</code></pre></div></div>
<h3 id="parefeu-iptables-v4-v6">parefeu (iptables V4 V6)</h3>
<p><img src="/images/iptables1.png" alt="parefeu Iptables" width="100" /><br />
<a href="https://yann.cinay.eu/2018/10/08/Pare-feu-iptables-IPv4-IPv6-versions-bureau-et-serveur.html">installer un parefeu serveur</a></p>
<h2 id="applications">Applications</h2>
<h3 id="rainloop-webmail">Rainloop webmail</h3>
<p><img src="/images/rainloop.png" alt="Rainloop" width="50" /></p>
<ul>
<li><a href="http://rainloop.net/">Rainloop</a></li>
<li><a href="https://www.howtoforge.com/installation-and-configuratio-of-rainloop-webmail-client-with-nginx-on-ubuntu-14.04">Installation And Configuration Of RainLoop Webmail Client With Nginx</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/installing-the-rainloop-email-client-on-ajenti-v">Installing the RainLoop Email Client on Ajenti V </a></li>
</ul>
<p>On va utiliser le domaine <strong>webmail.yanspm.com</strong></p>
<p><strong>MariaDB</strong><br />
Créer dans Mariadb une base de données <em>rainloopdb</em>, utilisateur <em>rainloopuser</em> et un mot de passe situé sous <em>/etc/mysql/rainlooppassword</em> <br />
Pour info le mot de passe root de la base mysql est situé sous <em>/etc/mysql/mdp</em></p>
<p>Génération du mot de passe de la base <em>rainloopdb</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
echo $(date +%s | sha256sum | base64 | head -c 20 ;) &gt; /etc/mysql/rainlooppassword
</code></pre></div></div>
<p>Création de la base mysql <em>rainloopdb</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql -u root -p$(cat /etc/mysql/mdp) &lt;&lt;EOF
create database rainloopdb;
GRANT ALL PRIVILEGES ON rainloopdb.* TO 'rainloopuser'@'localhost' IDENTIFIED BY 'rainlooppassword';
flush privileges;
exit;
EOF
</code></pre></div></div>
<blockquote>
<p>REMPLACER <em>rainlooppassword</em> par le contenu du fichier <em>/etc/mysql/rainlooppassword</em></p>
</blockquote>
<p><strong>Dépendances PHP7.3</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install php7.3-fpm php7.3-mysql php7.3-cli php7.3-curl php7.3-sqlite
</code></pre></div></div>
<p>Ce serveur utilise PHP7.3 , lextension <strong>mcrypt</strong> na pas été reconduite , il faut installer la dernière version connue php7.1-mcrypt</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install php7.1-mcrypt
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Creating config file /etc/php/7.1/mods-available/calendar.ini with new version
Creating config file /etc/php/7.1/mods-available/ctype.ini with new version
Creating config file /etc/php/7.1/mods-available/exif.ini with new version
Creating config file /etc/php/7.1/mods-available/fileinfo.ini with new version
Creating config file /etc/php/7.1/mods-available/ftp.ini with new version
Creating config file /etc/php/7.1/mods-available/gettext.ini with new version
Creating config file /etc/php/7.1/mods-available/iconv.ini with new version
Creating config file /etc/php/7.1/mods-available/pdo.ini with new version
Creating config file /etc/php/7.1/mods-available/phar.ini with new version
Creating config file /etc/php/7.1/mods-available/posix.ini with new version
Creating config file /etc/php/7.1/mods-available/shmop.ini with new version
Creating config file /etc/php/7.1/mods-available/sockets.ini with new version
Creating config file /etc/php/7.1/mods-available/sysvmsg.ini with new version
Creating config file /etc/php/7.1/mods-available/sysvsem.ini with new version
Creating config file /etc/php/7.1/mods-available/sysvshm.ini with new version
Creating config file /etc/php/7.1/mods-available/tokenizer.ini with new version
Paramétrage de libmcrypt4 (2.5.8-3.3) ...
Paramétrage de php7.1-mcrypt (7.1.25-1+0~20181207224650.11+stretch~1.gbpf65b84) ...
Creating config file /etc/php/7.1/mods-available/mcrypt.ini with new version
</code></pre></div></div>
<p><strong>Installer rainloop</strong></p>
<p>Créer le dossier du site web (en mode su)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /var/www/rainloop/{public_html,logs}
cd /var/www/rainloop/public_html/
curl -s http://repository.rainloop.net/installer.php | php
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env php
[RainLoop Webmail Installer]
* Connecting to repository ...
* Downloading package ...
* Complete downloading!
* Installing package ...
* Complete installing!
* [Success] Installation is finished!
</code></pre></div></div>
<p>Création du fichier de configuration nginx pour rainloop</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/nginx/conf.d/rainloop.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name webmail.yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name webmail.yanspm.com;
root /var/www/rainloop/public_html;
index index.php;
include ssl_params;
include header_params;
# Diffie-Hellmann
# Uncomment the following directive after DH generation
# &gt; openssl dhparam -out /etc/ssl/private/dh4096.pem -outform PEM -2 4096
# ssl_dhparam /etc/ssl/private/dh4096.pem;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
location ~ /\.ht {
deny all;
}
location ^~ /data {
deny all;
}
# if folder yanspm.com.d , uncomment the following directive
#include conf.d/yanspm.com.d/*.conf;
access_log /var/www/rainloop/logs/access.log;
error_log /var/www/rainloop/logs/error.log;
}
</code></pre></div></div>
<p>Vérification et rechargement nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
systemctl reload nginx
</code></pre></div></div>
<p>Les permissions du dossier web rainloop</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R www-data: /var/www/rainloop/public_html/
</code></pre></div></div>
<p><strong>Configurer rainloop (mode administration)</strong><br />
Accèder au panneau dadministration avec la configuration par défaut <a href="https://webmail.yanspm.com/?admin">https://webmail.yanspm.com/?admin</a> utilisateur <em>admin</em> et mot de passe <em>12345</em></p>
<p><img src="/images/rainloop-a.png" alt="" /><br />
Cliquer sur change et modifier le mot de passe admin, se reconnecter <br />
<img src="/images/rainloop-admin.png" alt="" width="300" /></p>
<p><strong>Général</strong><br />
<img src="/images/rainloop-b.png" alt="" width="400" /></p>
<p><strong>Domaines</strong><br />
<img src="/images/rainloop-c.png" alt="" width="400" /></p>
<p><strong>Contacts</strong><br />
<img src="/images/rainloop-d.png" alt="" width="400" /></p>
<p><strong>Sécurité ,authentification en deux étapes</strong><br />
<img src="/images/rainloop-e.png" alt="" width="400" /><br />
Se déconnecter du mode administration, puis se connecter en utilisateur sur lun des domaines <a href="https://webmail.yanspm.com">https://webmail.yanspm.com</a> <br />
Aller dans les paramètres et sécurité<br />
<img src="/images/rainloop2fa-1.png" alt="" width="300" /><br />
Cliquer sur le lien ,”Configurer lauthentification en deux étapes”</p>
<p><img src="/images/rainloop2fa-01.png" alt="" width="300" /><br />
Cliquer sur <strong>Activer</strong></p>
<p><img src="/images/rainloop2fa-02.png" alt="" width="400" /><br />
scanner le code QR avec lapplication “And OTP” android, faire le test du code et ensuite activer (copier la clé secrète pour une utilisation sur un autre périphérique) puis cliquer sur <strong>Fait</strong> pour terminer lopération.</p>
<blockquote>
<p><strong>Lopération “authentification en deux étapes” doit être effectuée pour chaque domaine ayant un utilisateur</strong></p>
</blockquote>
<h3 id="shaarli">Shaarli</h3>
<p><img src="/images/shaarli_logo.png" alt="image" width="50px" /><br />
<em>Voulez-vous partager les liens que vous découvrez ? Shaarli est un gestionnaire de signets minimaliste et un service de partage de liens que vous pouvez installer sur votre propre serveur. Il est conçu pour être personnel (monoposte), rapide et pratique.</em></p>
<p>Utlisation domaine shaarli.yanspm.com</p>
<p><strong>Installation shaarli</strong><br />
Dans la plupart des cas, vous devriez télécharger la dernière version de Shaarli depuis la <a href="https://github.com/shaarli/Shaarli/releases">page des versions</a>. Téléchargez notre archive shaarli-full pour inclure les dépendances.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://github.com/shaarli/Shaarli/releases/download/v0.10.2/shaarli-v0.10.2-full.zip
unzip shaarli-v0.10.2-full.zip
sudo mv Shaarli /var/www/
sudo mkdir -p /var/log/shaarli # stockage des logs
</code></pre></div></div>
<p>Création du fichier de configuration nginx pour shaarli</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
nano /etc/nginx/conf.d/shaarli.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name shaarli.yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name shaarli.yanspm.com;
root /var/www/Shaarli;
index index.php;
include ssl_params;
include header_params;
# Diffie-Hellmann
# Uncomment the following directive after DH generation
# &gt; openssl dhparam -out /etc/ssl/private/dh4096.pem -outform PEM -2 4096
# ssl_dhparam /etc/ssl/private/dh4096.pem;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# if folder yanspm.com.d , uncomment the following directive
#include conf.d/yanspm.com.d/*.conf;
access_log /var/log/shaarli/shaarli_access.log;
error_log /var/log/shaarli/shaarli_error.log;
}
</code></pre></div></div>
<p>Vérification et rechargement nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
systemctl reload nginx
</code></pre></div></div>
<p>Les permissions du dossier web shaarli</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R www-data: /var/www/Shaarli/
</code></pre></div></div>
<p>Ouvrir le lien <a href="https://shaarli.yanspm.com">https://shaarli.yanspm.com</a> pour poursuivre linstallation</p>
<p><img src="/images/shaarli01.png" alt="" width="500" /> <br />
Après linstallation, se connecter en utilisateur/mot de passe <br />
Paramétrer <em>Français</em>, <strong>Tools</strong><strong>Configure your Shaarli</strong></p>
<h3 id="netdata">NetData</h3>
<p><img src="/images/netdata-logomark.png" alt="" width="50" /><br />
<a href="/2018/03/05/Netdata-Performance-Monitoring-Tool.html">NetData</a></p>
<p>Après installation de base<br />
Modifier la configuration par défaut <strong>/etc/nginx/conf.d/yanspm.com.conf</strong> et ajouter avant le } de fin</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> location /stub_status {
stub_status;
# Security: Only allow access from the IP below.
allow 127.0.0.1;
# Deny anyone else
deny all;
}
</code></pre></div></div>
<p>Vérifier la configuration de nginx et redémarrer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
systemctl restart nginx
</code></pre></div></div>
<p>Le module stub_statusde Nginx a été activé, vérifier avec la commande curl</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl https://yanspm.com/stub_status
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Active connections: 1
server accepts handled requests
3 3 2
Reading: 0 Writing: 1 Waiting: 1
</code></pre></div></div>
<p>Pour surveiller Nginx à laide de Netdata, nous avons besoin du modulestub_statusde Nginx qui est activé.<br />
Créer le fichier python.d/nginx.conf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/netdata/python.d/nginx.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>localhost:
name : 'local'
url : 'https://yanspm.com/stub_status'
</code></pre></div></div>
<p>Redémarrez maintenant Netdata en utilisant systemctl.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart netdata
</code></pre></div></div>
<p>La configuration de Netdata pour la surveillance de Nginx est terminée.</p>
<p>Créer un proxy nginx pour accès à netdata <strong>/etc/nginx/conf.d/netdata.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upstream backend {
# the netdata server
server 127.0.0.1:19999;
keepalive 64;
}
server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name netdata.yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name netdata.yanspm.com;
include ssl_params;
include header_params;
# Diffie-Hellmann
# Uncomment the following directive after DH generation
# &gt; openssl dhparam -out /etc/ssl/private/dh4096.pem -outform PEM -2 4096
# ssl_dhparam /etc/ssl/private/dh4096.pem;
# include conf.d/netdata.yanspm.com.d/*.conf;
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection "keep-alive";
proxy_store off;
}
access_log /var/log/nginx/netdata-access.log;
error_log /var/log/nginx/netdata-error.log;
}
</code></pre></div></div>
<p>Vérification et rechargement nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
systemctl reload nginx
</code></pre></div></div>
<p>Accès <a href="https://netdata.yanspm.com">https://netdata.yanspm.com</a></p>
<p><img src="/images/netdata01.png" alt="" width="600" /></p>
<h3 id="gitea">Gitea</h3>
<p><img src="/images/gitea-logo.png" alt="gitea" /></p>
<p><em>Gitea est une interface web permettant de visualiser les branches, les commits, les tags, etc. de ses projets git. Il a une utilisation proche de celle de GitHub, tout en restant très léger.</em></p>
<ul>
<li><a href="/2019/01/04/Systemd-service-pour-lancer-application.html">Systemd,lancer une application au démarrage</a></li>
</ul>
<p><strong>Installation</strong><br />
On installe le binaire gitea dans le “home” utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir $HOME/.gitea
cd ~/.gitea
# Télécharger le binaire Gitea
wget https://dl.gitea.io/gitea/1.6.2/gitea-1.6.2-linux-amd64 -O gitea
chmod +x gitea
</code></pre></div></div>
<p>Lancer lapplication au démarrage<br />
<strong>Créer le service systemd “gitea.service”</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/gitea.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Gitea gestion web des projets git
[Service]
Type=simple
ExecStart=/home/yanspm/.gitea/gitea web
User=yanspm
Group=yanspm
[Install]
WantedBy=multi-user.target
</code></pre></div></div>
<p>Lancement du service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
sudo systemctl start gitea.service
</code></pre></div></div>
<p>Vérifier status</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl status gitea.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● gitea.service - Affiche l'heure sur un YoctoDisplay
Loaded: loaded (/etc/systemd/system/gitea.service; disabled; vendor preset: enabled)
Active: active (running) since Fri 2019-01-04 14:21:28 CET; 1min 8s ago
Main PID: 32138 (gitea)
Tasks: 7 (limit: 4915)
CGroup: /system.slice/gitea.service
└─32138 /home/yanspm/.gitea/gitea web
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [T] Log path: /home/yanspm/.gitea/
log
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Gitea v1.6.2 built with: binda
ta, sqlite
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Log Mode: Console(Info)
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] XORM Log Mode: Console(Info)
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Cache Service Enabled
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Session Service Enabled
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] SQLite3 Supported
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Run Mode: Development
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 Serving [::]:3000 with pid 32138
janv. 04 14:21:28 yanspm.com gitea[32138]: 2019/01/04 14:21:28 [I] Listen: http://0.0.0.0:3000
</code></pre></div></div>
<p>Activer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable gitea.service
</code></pre></div></div>
<p><strong>Créer proxy nginx pour laccès à gitea</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/gitea.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name gitea.yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name gitea.yanspm.com;
include ssl_params;
include header_params;
location / {
proxy_pass http://127.0.0.1:3000;
}
access_log /var/log/nginx/gitea-access.log;
error_log /var/log/nginx/gitea-error.log;
}
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
</code></pre></div></div>
<p>Relancer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl reload nginx
</code></pre></div></div>
<p>Accès au site par le lien <a href="https://gitea.yanspm.com">https://gitea.yanspm.com</a></p>
<p><strong>MariaDB/MySQL base gitea</strong><br />
Version MariadDB/MySQL</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql --version
mysql Ver 15.1 Distrib 10.3.11-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
</code></pre></div></div>
<blockquote>
<p>ATTENTION MariaDB version &gt; 10.1 sinon erreur…</p>
</blockquote>
<p>Créer dans Mariadb une base de données <em>gitea</em>, utilisateur <em>gitea</em> et un mot de passe situé sous <em>/etc/mysql/gitea</em> <br />
Pour info le mot de passe root de la base mysql est situé sous <em>/etc/mysql/mdp</em></p>
<p>Génération du mot de passe de la base <em>gitea</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
echo $(date +%s | sha256sum | base64 | head -c 12 ;) &gt; /etc/mysql/gitea
</code></pre></div></div>
<p>Création de la base mysql <em>gitea</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql -u root -p$(cat /etc/mysql/mdp)
create database gitea;
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost' IDENTIFIED BY 'giteapassword';
flush privileges;
exit;
</code></pre></div></div>
<blockquote>
<p>REMPLACER <em>giteapassword</em> par le contenu du fichier <em>/etc/mysql/gitea</em></p>
</blockquote>
<p><strong>Utiliser “gitea”</strong><br />
La première connexion au site <a href="https://gitea.yanspm.com">https://gitea.yanspm.com</a> , cliquer sur <strong>sinscrire</strong><br />
<strong>Configuration initiale</strong> ,saisir le mot de passe de la base mysql<br />
<strong>Configuration générale</strong> ,modifier le titre du site, désactiver le port du serveur SSH<br />
Cliquer sur <strong>“Installer Gitea”</strong></p>
<p>Se connecter de nouveau, créer un compte puis créer un dépôt , par exemple “wikistatic”</p>
<p><strong>Poste contenant les sources des dépôts</strong><br />
Du poste qui contient les sources de notre application “wikistatic”<br />
Renseigner le fichier <strong>~/.git-credential</strong> , https://yannick:mot-de-passe@gitea.yanspm.com
Renseigner le fichier <strong>~/.gitconfigl</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[user]
name = Gitea Yanspm
email = yannick@cinay.xyz
[credential]
helper = store
[core]
editor = nano
[http]
postBuffer = 524288000
</code></pre></div></div>
<p>Première initialisation du dépôt après sa création sous gitea.yanspm.com</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~/media/gitea/wikistatic # se rendre dans le dossier contenant les sources
git init # initialisation
git add . # on prend le conteu du dossier
git commit -m "Initialisation"
git remote add origin https://gitea.yanspm.com/yannick/wikistatic.git
git push -u origin master
</code></pre></div></div>
<h3 id="msmtp--envoyer-des-messages">msmtp , envoyer des messages</h3>
<p>Avec lutilitaite ssmtp , on utilise un serveur smtp existant pour envoyer des messages<br />
Voir le <a href="/2016/12/17/Debian-ssmtp-msmtp-Mise-A-jour-automatique-avec-Cron-APT.html">lien</a> paragraphe “Méthode 3 : msmtp”<br />
Les opérations suivantes se font en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt --purge remove exim4* # suppression exim
apt install mailutils msmtp msmtp-mta # installation msmtp et utilitaire
</code></pre></div></div>
<p>Le fichier de configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/.msmtprc
</code></pre></div></div>
<p>Le contenu</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>account default
tls on
host messagerie.xyz # smtp.messagerie.xyz
port 587
from user@messagerie.xyz
auth on
user user@messagerie.xyz # user
password &lt;mot de passe&gt;
tls_starttls on
tls_certcheck on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
</code></pre></div></div>
<h4 id="vérifications-et-tests">Vérifications et tests</h4>
<p>On peut tout simplement vérifier que tout est correctement configuré en senvoyant un email avec cette commande :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>printf "Subject:Test expéditeur\nCeci est un test" | msmtp destinataire@desti.tld
</code></pre></div></div>
<p>Pour que la commande <strong>mail</strong> fonctionne, vous devrez mettre ce qui suit dans <em>/etc/mail.rc</em><br />
Veuillez noter que pour avoir lutilitaire mail, vous devrez installer le paquet <strong>mailutils</strong>.<br />
Fichier : <strong>/etc/mail.rc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set sendmail="/usr/bin/msmtp -t"
</code></pre></div></div>
<p>Vous pouvez tester que le courrier fonctionne avec la commande suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "Ceci est un corps de message" | mail -s "Hello there from mail command line" desti@destinataire.tld
</code></pre></div></div>
<p><strong>Crontab</strong> offre une façon denvoyer des courriels. Au début du fichier crontab, vous pouvez léditer avec <code class="language-plaintext highlighter-rouge">sudo crontab -e</code> et déclarer la variable <strong>MAILTO</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MAILTO="xand@xand.es"
* * * * * /tmp/aaa.sh
</code></pre></div></div>
<h3 id="sauvegarde-via-borg">Sauvegarde via Borg</h3>
<p><img src="/images/borg-logo.png" alt="" /></p>
<p>On utilise BorgBackup<br />
Le script <strong>/root/.borg/borg-backup</strong> est lancé chaque jour à 3h00 ,compte rendu dans le fichier <strong>/var/log/borg-backup.log</strong></p>
<h3 id="localisation-ip">Localisation IP</h3>
<p><u>Adresse IPv4</u><br />
Elle est constituée dune série de 4 nombres compris entre 0 et 255 séparés par des points “.“.<br />
Elle est limitée par le nombre dappareils connectés en simultanée (4 294 967 296) sur internet.<br />
Exemple dadresse IPv4 : 88.232.28.174</p>
<p><u>Adresse IPv6</u><br />
Elle est constitué de 8 blocs hexadécimaux de 8 octets séparés par des deux points “:“.<br />
Lintérêt de cette norme est quelle permet davoir beaucoup plus dadresses IP disponibles (340 282 366 920 938 463 463 374 607 431 768 211 456 combinaisons possibles). Cette augmentation du nombre dadresses est devenue nécessaire avec le développement dinternet et le nombre de périphériques connectés (ordinateurs, smartphones, tablettes, objets connectés).<br />
Exemple dadresse IPv6 : 3bec:c504:3127: 5800:10c3:30bf:cb2f:1eee</p>
<p><em>Pour plus dinformations sur les adresses IP, consultez larticle complet dédié au sujet sur <a href="https://fr.wikipedia.org/wiki/Adresse_IP">Wikipedia : https://fr.wikipedia.org/wiki/Adresse_IP</a></em></p>
<p>Se connecter sur le serveur, passer en mode super utilisateur et se rendre dans la racine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/www/default-www
</code></pre></div></div>
<p>Cloner le dépôt dans la “racine” du site web <strong>/var/www/default-www/</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://gitea.yanspm.com/yannick/localisation-IP-V4-V6.git
</code></pre></div></div>
<p>Le lien <a href="https://yanspm.com/localisation-IP-V4-V6/localisation-serveur-vpn-ipv4-ipv6.html">https://yanspm.com/localisation-IP-V4-V6/localisation-serveur-vpn-ipv4-ipv6.html</a></p>
<h3 id="calibre-web">Calibre-web</h3>
<ul>
<li><a href="/2019/04/03/calibre-web.html">Calibre-web</a></li>
</ul>
<h2 id="système">Système</h2>
<h3 id="liste-des-tâches-crontab">Liste des tâches (crontab)</h3>
<p>Tâches exécutées automatiquement</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo crontab -e
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Mise à jour des certificats
9 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" &gt; /dev/null
# Mise à jour automatique des serveurs DNS de la racine
50 02 * * * /etc/unbound/dnsunbound-update-root-dns.sh &gt; /dev/null
# Générer une liste des domaines à bloquer
40 02 * * * /etc/unbound/unbound.conf.d/liste-domaines-bloques.sh &gt; /dev/null
# Sauvegarde sur distant avec BorgBackup
00 03 * * * /root/.borg/borg-backup &gt; /dev/null
</code></pre></div></div>
<h2 id="annuaire-ldap">Annuaire LDAP</h2>
<ul>
<li><a href="/2019/10/05/OpenLDAP-installation-configuration-annuaire.html">OpenLDAP installation et configuration annuaire</a></li>
</ul>
<h3 id="installation--configuration-et-tests-openldap">Installation , configuration et tests openLDAP</h3>
<p><strong>Installation et configuration</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DEBIAN_FRONTEND=noninteractive apt-get -yq install slapd ldap-utils
dpkg-reconfigure slapd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Voulez-vous omettre la configuration dOpenLDAP ? Non
Nom de domaine : ldap.yanspm.com
Nom dentité (« organization ») : ldap.yanspm.com
Mot de passe de ladministrateur : *******
Module de base de données à utiliser : MDB
Faut-il supprimer la base de données lors de la purge du paquet ? Non
Faut-il déplacer lancienne base de données ? Oui
</code></pre></div></div>
<p><strong>Tests</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl enable slapd # activation
systemctl start slapd # exécution
</code></pre></div></div>
<p>Ecoute</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netstat -laputn | grep slapd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tcp 0 0 0.0.0.0:389 0.0.0.0:* LISTEN 28128/slapd
tcp6 0 0 :::389 :::* LISTEN 28128/slapd
</code></pre></div></div>
<p>Avec quels arguments sexécute le service.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /var/run/slapd/slapd.args
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/sbin/slapd -h ldap:/// ldapi:/// -g openldap -u openldap -F /etc/ldap/slapd.d
</code></pre></div></div>
<p><strong>-h</strong> → les modalités daccès à slapd : ldap et ldapi (ldap via TCP 389 et ldapi via socket unix)<br />
<strong>-g</strong> et <strong>-u</strong> → identité groupe et utilisateur sur lequel “tourne” le processus slapd<br />
<strong>-F</strong> → emplacement du ficher de configuration de slapd</p>
<p>Afficher les données de lannuaire</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ldapsearch -x -H ldap://ldap.yanspm.com -b 'dc=ldap,dc=yanspm,dc=com'
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># extended LDIF
#
# LDAPv3
# base &lt;dc=ldap,dc=yanspm,dc=com&gt; with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# ldap.yanspm.com
dn: dc=ldap,dc=yanspm,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: ldap.yanspm.com
dc: ldap
# admin, ldap.yanspm.com
dn: cn=admin,dc=ldap,dc=yanspm,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
</code></pre></div></div>
<h3 id="peuplement-de-lannuaire">Peuplement de lannuaire</h3>
<p>Peupler lannuaire en créant les deux <strong>OU</strong> puis un compte système avec son groupe primaire.<br />
Créer un fichier au format LDIF (LDAP Data Interchange Format)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat &gt; ou.ldif &lt;&lt; EOF
dn: ou=posixaccounts,dc=ldap,dc=yanspm,dc=com
objectclass: OrganizationalUnit
dn: ou=posixgroups,dc=ldap,dc=yanspm,dc=com
objectclass: OrganizationalUnit
EOF
</code></pre></div></div>
<p>Ajouter à lannuaire (mot de passe admin)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ldapadd -x -H ldap://ldap.yanspm.com -D 'cn=admin,dc=ldap,dc=yanspm,dc=com' -f ou.ldif -W
</code></pre></div></div>
<p>Ajouter le compte (utilisateur mot de passe) avec le groupe primaire<br />
Pour créer lempreinte du mot de passe ,utiliser <code class="language-plaintext highlighter-rouge">slappasswd</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat &gt; userandupg.ldif &lt;&lt; EOF
dn: uid=yannick, ou=posixaccounts,dc=ldap,dc=yanspm,dc=com
uid: yannick
sn: yannick
homeDirectory: /home/yannick
cn: yannick
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
loginShell: /bin/bash
uidNumber: 6001
gidNumber: 6001
gecos: yan
mail: yannick@cinay.xyz
userPassword: {SSHA}NGdnkYoutO+bSUVDV1X+H6WvBBi4Cv17
dn: cn=yannick,ou=posixgroups,dc=ldap,dc=yanspm,dc=com
objectClass: posixGroup
objectClass: top
gidNumber: 6001
cn: yannick
EOF
</code></pre></div></div>
<p>Ajout des 2 objets</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ldapadd -x -H ldap://ldap.yanspm.com -D 'cn=admin,dc=ldap,dc=yanspm,dc=com' -f userandupg.ldif -W
</code></pre></div></div>
<p>Supprimer les .ldif</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm *.ldif
</code></pre></div></div>
<h3 id="sécurisation-ssl">Sécurisation SSL</h3>
<p>SSL, couche additionnelle à TCP qui chiffre les échanges.<br />
On va activer ldaps et modifier les paramètres de lancement du service et générer un certificat.</p>
<p><strong>Création des certificats</strong><br />
Création du répertoire ssl et génération certificat autosigné (validité 10ans)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /etc/ldap/ssl &amp;&amp; cd /etc/ldap/ssl
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes
</code></pre></div></div>
<p>Le champ <strong>Common Name</strong> est le plus important</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Common Name (e.g. server FQDN or YOUR name) []:ldap.yanspm.com
</code></pre></div></div>
<p>Changer les permissions sur les 2 fichiers (utilisateur <em>openldap</em>) , clé privée accessible par root uniquement</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown openldap:openldap /etc/ldap/ssl/key.pem
chown openldap:openldap /etc/ldap/ssl/cert.pem
chmod 400 /etc/ldap/ssl/key.pem
</code></pre></div></div>
<p><strong>Configuration de slapd</strong><br />
Ajout de 2 directives pour trouver le couple clé/certificat</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat &gt; cert.ldif &lt;&lt; EOF
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/ssl/cert.pem
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/cert.pem
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/key.pem
EOF
</code></pre></div></div>
<p>Pour appliquer les modifications ,nous allons passer par le mode ldapi car il ny a pas de compte administrateur associé à la racine cn=config</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ldapmodify -Y EXTERNAL -H ldapi:/// -f cert.ldif # pas de mot de passe
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
create: 2019-07-10
modifying entry "cn=config"
</code></pre></div></div>
<p>create: 2019-07-10
modifier le fichier <strong>/etc/default/slapd</strong> pour lui indiquer quil doit gérer la méthode daccès ldaps</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/default/slapd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
</code></pre></div></div>
<p>Relancer slapd et vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart slapd &amp;&amp; netstat -laputn | grep slapd
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tcp 0 0 0.0.0.0:389 0.0.0.0:* LISTEN 28651/slapd
tcp 0 0 0.0.0.0:636 0.0.0.0:* LISTEN 28651/slapd
tcp6 0 0 :::389 :::* LISTEN 28651/slapd
tcp6 0 0 :::636 :::* LISTEN 28651/slapd
</code></pre></div></div>
<p>Le service slapd est en écoute SSL sur le port 636</p>
<h3 id="openldap-php-sur-serveur">OpenLDAP PHP sur serveur</h3>
<p>Installer le module</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install php7.3-ldap
</code></pre></div></div>
<p>Fichiers de test <strong>/var/www/default-www/test.php</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /var/www/default-www/test.php
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;?php
$baseDN = "dc=ldap,dc=yanspm,dc=com";
$ldapServer = "ldap.yanspm.com";
$ldapServerPort = 389;
$dn = 'cn=admin,dc=ldap,dc=yanspm,dc=com';
echo "Connexion au serveur &lt;br /&gt;";
$conn=ldap_connect($ldapServer);
// on teste : le serveur LDAP est-il trouvé ?
if ($conn) {
echo "Le résultat de connexion est ".$conn ."&lt;br /&gt;";
} else {
die("connexion impossible au serveur LDAP");
}
// 2ème étape : on effectue une liaison au serveur, ici de type "anonyme"
// pour une recherche permise par un accès en lecture seule
// On dit qu'on utilise LDAP V3, sinon la V2 par défaut est utilisé
// et le bind ne passe pas.
if (ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3)) {
echo "Utilisation de LDAPv3 &lt;br /&gt;";
} else {
echo "Impossible d'utiliser LDAP V3&lt;br /&gt;";
exit;
}
// Instruction de liaison.
// Connexion anonyme
print ("Connexion anonyme...&lt;br /&gt;");
$bindServerLDAP=ldap_bind($conn);
echo "Liaison au serveur : ". ldap_error($conn)."&lt;br /&gt;";
// en cas de succès de la liaison, renvoie Vrai
if ($bindServerLDAP)
echo "Le résultat de connexion est $bindServerLDAP &lt;br /&gt;";
else
die("Liaison impossible au serveur ldap ...");
/* 3ème étape : on effectue une recherche anonyme, avec le dn de base,
* par exemple, sur tous les noms commençant par B
*/
echo "Recherche suivant le filtre (sn=y*) &lt;br /&gt;";
$query = "sn=y*";
$result=ldap_search($conn, $baseDN, $query);
echo "Le résultat de la recherche est $result &lt;br /&gt;";
echo "Le nombre d'entrées retournées est ".ldap_count_entries($conn,$result)."&lt;p /&gt;";
echo "Lecture de ces entrées ....&lt;p /&gt;";
$info = ldap_get_entries($conn, $result);
echo "Données pour ".$info["count"]." entrées:&lt;p /&gt;";
for ($i=0; $i &lt; $info["count"]; $i++) {
echo "dn est : ". $info[$i]["cn"] ."&lt;br /&gt;";
echo "premiere entree cn : ". $info[$i]["cn"][0] ."&lt;br /&gt;";
echo "premier email : ". $info[$i]["mail"][0] ."&lt;p /&gt;";
}
// Test utilisateur mot de passe
if($bindServerLDAP = @ldap_bind($conn, "uid=yannick,ou=posixaccounts,dc=ldap,dc=yanspm,dc=com", "Jkhgtrdef45")) {
echo "OK Test utilisateur mot de passe &lt;br /&gt;";
} else {
echo "ERROR Test utilisateur mot de passe &lt;br /&gt;";
}
echo "Fermeture de la connexion";
ldap_close($conn);
?&gt;
</code></pre></div></div>
<p>Attribut fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown $USER:www-data /var/www/default-www/test.php
chmod +x /var/www/default-www/test.php
</code></pre></div></div>
<p>Test sur le lien https://yanspm.com/test.php</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connexion au serveur
Le résultat de connexion est Resource id #2
Utilisation de LDAPv3
Connexion anonyme...
Liaison au serveur : Success
Le résultat de connexion est 1
Recherche suivant le filtre (sn=y*)
Le résultat de la recherche est Resource id #3
Le nombre d'entrées retournées est 1
Lecture de ces entrées ....
Données pour 1 entrées:
dn est : Array
premiere entree cn : yannick
premier email : yannick@cinay.xyz
OK Test utilisateur mot de passe
Fermeture de la connexion
</code></pre></div></div>
<p>Une fois la vérification effectuée , supprimer le fichier <strong>test.php</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /var/www/default-www/test.php
</code></pre></div></div>
<h2 id="authentification-jwt--ldap">Authentification JWT + LDAP</h2>
<ul>
<li>Gestion des pages web sur yanspm.com avec autorisation (utilisateur et mot de passe) + jeton (token jwt)</li>
<li>Toutes les pages du site sont en php et ont OBLIGATOIREMENT un début de page avec ce qui suit :</li>
</ul>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nb">session_start</span><span class="p">();</span> <span class="c1">// On démarre la session AVANT toute chose</span>
<span class="k">include_once</span> <span class="s2">"veriftoken.php"</span><span class="p">;</span>
<span class="c1">// si token non valide , retour page login</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">veriftoken</span><span class="p">())</span> <span class="p">{</span>
<span class="c1">// accés non autorisé</span>
<span class="nb">header</span><span class="p">(</span><span class="s1">'Location: login.php'</span><span class="p">);</span>
<span class="p">}</span>
<span class="cp">?&gt;</span>
</code></pre></div></div>
<ul>
<li>En cas dexpiration du token ou mauvaise identification , retour sur la page <strong>login.php</strong></li>
</ul>
<h3 id="privyanspmcom">priv.yanspm.com</h3>
<p>Création dossier private</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /var/www/private
sudo chown $USER:$USER /var/www/private
</code></pre></div></div>
<p>Créer un fichier index.php</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "&lt;?php echo 'Dossier /var/www/private'; ?&gt;" &gt; /var/www/private/index.php
</code></pre></div></div>
<p>Créer un fichier de configuration nginx domaine priv.yanspm.com</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/priv.yanspm.com.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name priv.yanspm.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name priv.yanspm.com;
include ssl_params;
include header_params;
# include dh_param;
root /var/www/private/ ;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
location /stub_status {
stub_status;
# Security: Only allow access from the IP below.
allow 127.0.0.1;
# Deny anyone else
deny all;
}
access_log /var/log/nginx/priv.yanspm.com-access.log;
error_log /var/log/nginx/priv.yanspm.com-error.log;
}
</code></pre></div></div>
<p>Vérifier et relancer nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
sudo systemctl restart nginx
</code></pre></div></div>
<p>Accès lien https://priv.yanspm.com</p>
<h3 id="autorisation-ldap--jwt-les-fichiers-php">Autorisation ldap + jwt (les fichiers php)</h3>
<p>Liste des fichiers</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/var/www/private/
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>authclient.php
easter_spring_eggs_flowers_pastel_1920x1080.jpg
generkey.php
index.php
jwtclass.php
login.php
portal.php
test.php
veriftoken.php
yannick-white-black.png
</code></pre></div></div>
<ul>
<li><a href="https://redbyte.eu/en/blog/using-the-nginx-auth-request-module/">Using the NGINX Auth Request Module</a></li>
</ul>
<h3 id="créer-un-serveur-dautorisation-local---autorisesrv">Créer un serveur dautorisation local - autorise.srv</h3>
<p>Ajouter au fichier <strong>/etc/hosts</strong><code class="language-plaintext highlighter-rouge">127.0.1.1 autorise.srv</code><br />
Le fichier de configuration nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/autorise.srv.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 8888;
listen [::]:8888;
server_name autorise.srv;
root /var/www/private/ ;
index authclient.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
access_log /var/log/nginx/autorise.srv-access.log;
error_log /var/log/nginx/autorise.srv-error.log;
}
</code></pre></div></div>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
sudo systemctl restart nginx
</code></pre></div></div>
<h2 id="application-single-sign-on-pour-php-compatible-ajax">Application Single Sign-On pour PHP (compatible Ajax)</h2>
<ul>
<li>https://github.com/jasny/sso.git</li>
</ul>
<p>Jasny\SSO est une solution relativement simple et directe pour une implémentation SSO (Single Sign on). Avec SSO, la connexion à un site Web unique vous authentifiera pour tous les sites affiliés.</p>
<h3 id="comment-cela-fonctionne">Comment cela fonctionne</h3>
<p>Lors de lutilisation de SSO, quand peut distinguer 3 parties :</p>
<ul>
<li>Client - Cest le navigateur du visiteur</li>
<li>Courtier - Le site Web qui est visité</li>
<li>Serveur - Lendroit où se trouvent les informations et les identifiants de lutilisateur</li>
</ul>
<p>Le courtier a une identité et un secret. Ceux-ci sont connus à la fois du courtier et du serveur.</p>
<p>Lorsque le client visite le courtier, il crée un jeton aléatoire, qui est stocké dans un cookie. Le courtier enverra ensuite le client au serveur, en lui transmettant lidentifiant et le jeton du courtier. Le serveur crée un hachage à laide du broker id, du broker secret et du token. Ce hachage est utilisé pour créer un lien vers la session de lutilisateur. Lorsque le lien est créé, le serveur redirige le client vers le courtier.</p>
<p>Le courtier peut créer le même hachage de lien en utilisant le token (à partir du cookie), lidentifiant du courtier et le secret du courtier. Lors de lexécution des requêtes, il passe qui a comme identifiant de session.</p>
<p>Le serveur remarquera que lidentifiant de session est un lien et utilisera la session liée. Ainsi, le courtier et le client utilisent la même session. Lorsquun autre courtier sinscrit, il utilisera également la même session.</p>
<p>Pour une explication plus détaillée, veuillez lire <a href="https://github.com/jasny/sso/wiki">cet article</a>.</p>
<h3 id="installer-composer-et-librairies">Installer composer et librairies</h3>
<p>Installer php composer<br />
Vous pouvez télécharger le script composer à partir du site Web getcomposer.org en exécutant la commande suivante. Il créera un fichier composer.phar dans le répertoire en cours.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sS https://getcomposer.org/installer | php
</code></pre></div></div>
<p>Copiez le fichier composer.phar dans le répertoire bin pour le rendre disponible nimporte où dans le système. Définissez également lautorisation dexécution sur le fichier. Jai changé le nom de fichier de composer.phar en compositeur pour une utilisation facile.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mv composer.phar /usr/local/bin/composer
chmod +x /usr/local/bin/composer
</code></pre></div></div>
<p>Installer cette librairie via composer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>composer require jasny/sso
</code></pre></div></div>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2019-07-10T00:00:00+02:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2019/07/10/Autorite-de-certification-et-certificats-OpenSSL.html">Autorité de certification et authentification par certificat client (OpenSSL,nginx)</a></div><div class="next"><span>SUIVANT</span><a href="/2019/07/11/debian-10-buster-une-distribution-qui-a-du-chien.html">Debian 10 Buster , une distribution qui a du chien</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>