yannstatic/static/2018/11/23/KVM8-vps-27199-Debian9-cinay.pw_.html

4645 lines
319 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>KVM8 Core 4 Ram 8Go SSD 40Go Debian Stretch cinay.pw - YannStatic</title>
<meta name="description" content="KVM Debian Stretch Yunohost cinay.pw">
<link rel="canonical" href="https://static.rnmkcy.eu/2018/11/23/KVM8-vps-27199-Debian9-cinay.pw_.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;">KVM8 Core 4 Ram 8Go SSD 40Go Debian Stretch cinay.pw</h1></header></div><meta itemprop="headline" content="KVM8 Core 4 Ram 8Go SSD 40Go Debian Stretch cinay.pw"><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=serveur">serveur</a>
</li><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=messagerie">messagerie</a>
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">23&nbsp;nov.&nbsp;&nbsp;2018</span>
<span title="Modification" style="color:#00FF7F">16&nbsp;mars&nbsp;&nbsp;2018</span></li></ul></div><meta itemprop="datePublished" content="2018-03-16T00:00:00+01:00">
<meta itemprop="keywords" content="serveur,messagerie"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h2 id="kvm-debian-stretch-yunohost-cinaypw">KVM Debian Stretch Yunohost cinay.pw</h2>
<p><img src="/images/debian9a.png" alt="Debian 9" /></p>
<p>Package: 8 GB Mémoire, 4 CPU, 40 GB SSD, 100 Mbps<br />
Selected Location: Paris<br />
Debian Jessie 64<br />
Livraison : vps-27199 93.113.206.145</p>
<ul>
<li>Domaine : cinay.pw</li>
<li>IPv4 du serveur : 93.113.206.145</li>
<li>IPv6 du serveur : 2a03:75c0:39:6a3f::1</li>
</ul>
<h3 id="première-connexion-ssh">Première connexion SSH</h3>
<p>Connexion sur “KVM-FirstHeberg GP4 Core 4 Ram 8Go SSD 40Go”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh root@93.113.206.145
</code></pre></div></div>
<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>
<p>Modifier <strong>hostname</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostnamectl set-hostname --static vps27199
</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.0.1 localhost
93.113.206.145 cinay.pw vps27199
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
</code></pre></div></div>
<p>Vérifications</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostname
vps27199
hostname --fqdn
cinay.pw
</code></pre></div></div>
<h3 id="locales">Locales</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="timezone">TimeZone</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: Wed Mar 14 13:26:39 CET 2018.
Universal Time is now: Wed Mar 14 12:26:39 UTC 2018.
</code></pre></div></div>
<h3 id="création-utilisateur">Création utilisateur</h3>
<p>Utilisateur <strong>adxo</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /home/adxo/ -s /bin/bash adxo
</code></pre></div></div>
<p>Mot de passe <strong>adxo</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd adxo
</code></pre></div></div>
<p>Visudo pour les accès root via utilisateur <strong>adxo</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install sudo
echo</span> <span class="s2">"adxo 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 adxo@93.113.206.145
</code></pre></div></div>
<h3 id="openssh">OpenSSH</h3>
<p><img src="/images/ssh_logo1.png" alt="OpenSSH" /></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-vps-27199
</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-vps-27199.pub adxo@93.113.206.145:/home/adxo/
</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 adxo@93.113.206.145
</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> /home/<span class="nv">$USER</span>/kvm-vps-27199.pub <span class="o">&gt;&gt;</span> /home/<span class="nv">$USER</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/$USER/.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/$USER/kvm-vps-27199.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">55027</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 #Installer par défaut sur debian stretch
</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 55027 -i ~/.ssh/kvm-vps-27199 adxo@93.113.206.145
</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="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">"cinay.pw"</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[0m"</span>
<span class="nb">echo</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;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 Ip </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 eth0 | <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;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 Ip </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="nv">$pays</span><span class="sb">`</span><span class="s2">
</span><span class="se">\0</span><span class="s2">33[0m"</span>
curl fr.wttr.in/Nantes?0
</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="sauvegarde-distante-via-serveur-yanspmcom-">Sauvegarde distante (via serveur yanspm.com )</h3>
<p><img src="/images/rsync.png" alt="Rsync" /></p>
<ul>
<li><a href="/doku.php?id=sauvegarde#rsync_a_distance_sans_acces_root">Sauvegarde pilotée par shuttle</a></li>
</ul>
<p><u>Autoriser un serveur distant</u> à se connecter via <strong>ssh</strong> pour y exécuter <strong>rsync</strong></p>
<p>Installer rsync</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install rsync # debian
</code></pre></div></div>
<p>Ajout utilisateur de backupuser qui ne peut exécuter que rsync et de la clé publique du “serveur de sauvegarde”</p>
<p>Création utilisateur backup</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd backupuser -c "limited backup user" -m -u 4210
</code></pre></div></div>
<p>Dossier ssh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /home/backupuser/.ssh
</code></pre></div></div>
<p>Ajout clé publique ssh dans le fichier authorized_keys du nouvel utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /home/backupuser/.ssh/authorized_keys
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrIKzB0NZOO8/XNLHWeYiZr0Yt/OW1KFvYXVO5GBcj7Ckpha95F5j5tCZxLZoY4PmbfMlN7h89QfshqnDrTpB9tTrcAbLVC3084xAUnC53B6wj6jXEn7OkNo/SOCAHTwqESq4qzARTjkwIw3uPFuqbN0LkZXg8CX61XliMxDNXFddLlwQoGDEz73ZHcKjsrGXZXUMG7obxNCbHt9zg29Widc+8mZuPM2u5YvtjV/1MHnU9GmeXBI3tKziihAnPkmRwoVPUcuEhzZLCKO98M1SDtKQs47sDwQVptqX1WVYDVeMt8vfkF8Uxj5294cB07MKB6cjVmVrQlfxf+EdGLcAR yann@shuttle
</code></pre></div></div>
<p>Création script bash <strong>rsync-wrapper.sh</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /home/backupuser/rsync-wrapper.sh
</code></pre></div></div>
<p>Contenu du script</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nb">date</span> <span class="o">&gt;</span> /home/backupuser/backuplog
<span class="c">#echo $@ &gt;&gt; /home/backupuser/backuplog</span>
/usr/bin/sudo /usr/bin/rsync <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span><span class="p">;</span>
</code></pre></div></div>
<p>Droits sur le fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown backupuser:backupuser /home/backupuser/rsync-wrapper.sh
sudo chmod 755 /home/backupuser/rsync-wrapper.sh
</code></pre></div></div>
<p>Edition fichier <strong>sudoers</strong> pour un accès root à lexécution de rsync</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<p>Ajouter ligne suivante en fin de fichier,exécution en mode root de rsync</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "backupuser ALL=NOPASSWD: /usr/bin/rsync" &gt;&gt; /etc/sudoers
exit
</code></pre></div></div>
<h3 id="réseau-ipv4-ipv6">Réseau IPV4 IPV6</h3>
<p>Configuré par défaut (FirstHeberg)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/network/interfaces
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Generate by postinstall at 2018-03-12 11:43:34
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 93.113.206.145
netmask 255.255.255.0
network 93.113.206.0
broadcast 93.113.206.255
gateway 93.113.206.1
iface eth0 inet6 static
address 2a03:75c0:39:6a3f::1
netmask 64
gateway fe80::1
post-up ip route add default via fe80::1 dev eth0
</code></pre></div></div>
<h3 id="nginx-php7-mariadb">Nginx PHP7 MariaDb</h3>
<p><img src="/images/nginx-php7-mariadb1.png" alt="lemp" /></p>
<ul>
<li><a href="https://static.ouestline.net/linux/2017/10/03/Serveur-web-nginx-PHP7.html">Serveur web nginx PHP7</a></li>
</ul>
<p>Script <strong>debian9-compil-nginx-php7.sh</strong> pour compiler et installer nginx + php7 sur debian stretch</p>
<p>Définition des chemins et fichiers de configuration nginx<br />
<strong>/etc/nginx/conf.d/cinay.pw.conf</strong> configuration de base du domaine<br />
Création dossier <strong>/etc/nginx/conf.d/cinay.pw.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/cinay.pw.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/cinay.pw.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/cinay.pw.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.0-fpm.sock; # PHP7.0
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
include conf.d/cinay.pw.d/*.conf;
access_log /var/log/nginx/cinay.pw.log;
error_log /var/log/nginx/cinay.pw.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>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>
<h3 id="installer-le-résolveur-dns-unbound">Installer le résolveur DNS Unbound</h3>
<p><img src="/images/unbound-250.png" alt="DNS Unbound" /></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.</em></p>
<p>Passage en mode super utilisateur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s # ou su
</code></pre></div></div>
<p>Désinstaller bind</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt remove --purge bind* -y
rm -r /var/cache/bind/
</code></pre></div></div>
<p>Installation des outils dns et du paquet Unbound :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install dnsutils unbound -y
</code></pre></div></div>
<p>Téléchargement de la liste des serveurs DNS racines :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/lib/unbound/ &amp;&amp; wget ftp://ftp.internic.net/domain/named.cache
</code></pre></div></div>
<p>Mise en place de cette liste pour le serveur Unbound :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mv named.cache root.hints &amp;&amp; chown unbound:unbound root.hints
</code></pre></div></div>
<p>Les fichiers de configuration sont situés sous <strong>/etc/unbound/unbound.conf.d/</strong><br />
<strong>root-auto-trust-anchor-file.conf</strong> qui est créé par défaut à linstallation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server:
# The following line will configure unbound to perform cryptographic
# DNSSEC validation using the root trust anchor.
auto-trust-anchor-file: "/var/lib/unbound/root.key"
</code></pre></div></div>
<p><strong>qname-minimisation.conf</strong> qui est créé par défaut à linstallation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server:
# Send minimum amount of information to upstream servers to enhance
# privacy. Only sends minimum required labels of the QNAME and sets
# QTYPE to NS when possible.
# See RFC 7816 "DNS Query Name Minimisation to Improve Privacy" for
# details.
qname-minimisation: yes
</code></pre></div></div>
<p>Ajout dun fichier de configuration<br />
<strong>dns-yan.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/unbound/unbound.conf.d/dns-yan.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server:
interface: 0.0.0.0
interface: ::0
access-control: 0.0.0.0/0 allow
access-control: ::/0 allow
root-hints: "/var/lib/unbound/root.hints"
verbosity: 0
#qname-minimisation: yes
num-threads: 2
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
rrset-cache-size: 100m
msg-cache-size: 50m
outgoing-range: 465
so-rcvbuf: 4m
so-sndbuf: 4m
port: 53
do-ip4: yes
do-ip6: yes
do-udp: yes
do-tcp: yes
do-daemonize: yes
hide-identity: yes
hide-version: yes
harden-glue: yes
harden-dnssec-stripped: yes
harden-referral-path: yes
use-caps-for-id: yes
prefetch: yes
</code></pre></div></div>
<p>Redémarrer le service <strong>dnsunbound</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart unbound
</code></pre></div></div>
<p>Les commandes suivantes ne fonctionneront que si le paquet “dnsutils” est installé sur votre système Debian!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig @127.0.0.1 afnic.fr +short +dnssec
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>192.134.5.25
A 8 2 600 20180406223409 20180307194345 64860 afnic.fr. lhw7AmNSkeZOtNN/9rJuGYxTdUcXSR3xlbsKz2xjNbFxQT5FwKILTW+E WWawrrbjo79uaG7kAvfMWrah4ijWtz9qGyd76qTr3XVdXB3+pbIsRr6X /I/ryQAy9w8tP3FvXHHU7IxihP+Ei2M5licCYitt1YZUyXuNFdNpdhq7 FRT+tq78yn1PEm121f32IRQ2Fjy9qZz9O0LU7roYZ6XFoPU9x3PU590J mpkywT9t6LpyeW5GK5zSL+Zb5eiFhfp33abkMf7b6Pc7xixcGN8h8SDQ Ry98Ne0EIqHKnyh/zzRszc1kBfP5kJXmcY/X3+4xLvKmvKNnBLT0dsn1 q1Hl1A==
</code></pre></div></div>
<p>Si la commande dig-command a fonctionné, vous pouvez maintenant définir Unbound comme premier résolveur DNS pour votre système de messagerie:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install resolvconf -y
echo "nameserver 127.0.0.1" &gt;&gt; /etc/resolvconf/resolv.conf.d/head
</code></pre></div></div>
<p>Le résultat de la commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nslookup afnic.fr | grep Server
</code></pre></div></div>
<p>devrait ressembler à ceci:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Server: 127.0.0.1
</code></pre></div></div>
<p>Vérifier la résolution de nom à partir du serveur :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig @127.0.0.1 afnic.fr
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; &lt;&lt;&gt;&gt; DiG 9.10.3-P4-Debian &lt;&lt;&gt;&gt; @127.0.0.1 afnic.fr
; (1 server found)
...
;; SERVER: 127.0.0.1#53(127.0.0.1)
...
</code></pre></div></div>
<p>La résolution fonctionne</p>
<blockquote>
<p>Maintenant, vous disposez de votre propre résolveur DNS.</p>
</blockquote>
<p>Mise à jour automatique des serveurs DNS de la racine ,créer un bash</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/unbound/dnsunbound-update-root-dns.sh
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nv">TmpName</span><span class="o">=</span><span class="si">$(</span><span class="nb">mktemp</span><span class="si">)</span>
<span class="nv">TmpDiff</span><span class="o">=</span><span class="si">$(</span><span class="nb">mktemp</span><span class="si">)</span>
<span class="nv">TmpErr</span><span class="o">=</span><span class="si">$(</span><span class="nb">mktemp</span><span class="si">)</span>
<span class="nv">REPORT_EMAIL</span><span class="o">=</span><span class="s2">"admin"</span>
<span class="nv">URL</span><span class="o">=</span><span class="s2">"https://www.internic.net/domain/named.cache"</span>
wget <span class="nt">-nv</span> <span class="nv">$URL</span> <span class="nt">-O</span> <span class="nv">$TmpName</span> 2&gt; <span class="nv">$TmpErr</span>
<span class="c"># On intercepte toute erreur</span>
<span class="c"># et on stoppe le script dans ce cas</span>
<span class="c"># On continue sinon</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="nt">-ne</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
</span><span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">Script was stopped at this point. A manual action may be required.</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="nv">$TmpErr</span>
mail <span class="nt">-s</span> <span class="s2">"[DNS - </span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-n</span><span class="si">)</span><span class="s2">] Root hints file download failed"</span> <span class="nv">$REPORT_EMAIL</span> &lt; <span class="nv">$TmpErr</span>
<span class="nb">rm</span> <span class="nv">$TmpErr</span>
<span class="nb">rm</span> <span class="nv">$TmpDiff</span>
<span class="nb">rm</span> <span class="nv">$TmpName</span>
<span class="nb">exit </span>0
<span class="k">else
</span><span class="nb">rm</span> <span class="nv">$TmpErr</span>
<span class="nv">shaTMP</span><span class="o">=</span><span class="si">$(</span><span class="nb">sha512sum</span> <span class="nv">$TmpName</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span><span class="si">)</span>
<span class="nv">shaHINTS</span><span class="o">=</span><span class="si">$(</span><span class="nb">sha512sum</span> /var/lib/unbound/root.hints | <span class="nb">awk</span> <span class="s1">'{print $1}'</span><span class="si">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$shaTMP</span> <span class="o">=</span> <span class="nv">$shaHINTS</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="c"># Si le fichier récupéré est identique à celui</span>
<span class="c"># utilisé par Unbound, on fait... rien</span>
<span class="nb">rm</span> <span class="nv">$TmpName</span>
<span class="nb">exit </span>0
<span class="k">else
</span><span class="nb">printf</span> <span class="s2">"A new root hints file was spotted on InterNIC server.</span><span class="se">\n</span><span class="s2">File downloaded and old root.hints file replaced.</span><span class="se">\n</span><span class="s2">Here is the diff:</span><span class="se">\n\n</span><span class="s2">"</span> <span class="o">&gt;</span> <span class="nv">$Tmp</span><span class="err">$</span>
diff <span class="nv">$TmpName</span> /var/lib/unbound/root.hints <span class="o">&gt;&gt;</span> <span class="nv">$TmpDiff</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n\n</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="nv">$TmpDiff</span>
<span class="nb">mv</span> <span class="nt">-f</span> <span class="nv">$TmpName</span> /var/lib/unbound/root.hints
<span class="nb">chown </span>unbound: /var/lib/unbound/root.hints
<span class="nb">chmod </span>644 /var/lib/unbound/root.hints
<span class="nb">sleep </span>5
service unbound restart
<span class="nb">printf</span> <span class="s2">"Unbound status is </span><span class="si">$(</span>service unbound status | <span class="nb">grep </span>Active | <span class="nb">awk</span> <span class="s1">'{print $2 " " $3}'</span><span class="si">)</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="nv">$TmpDiff</span>
mail <span class="nt">-s</span> <span class="s2">"[DNS - </span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-n</span><span class="si">)</span><span class="s2">] Update in Root Hints"</span> <span class="nv">$REPORT_EMAIL</span> &lt; <span class="nv">$TmpDiff</span>
<span class="nb">rm</span> <span class="nv">$TmpDiff</span>
<span class="k">fi
fi
</span><span class="nb">exit </span>0
</code></pre></div></div>
<p>Droits en exécution</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x /etc/unbound/dnsunbound-update-root-dns.sh
</code></pre></div></div>
<p>Planification journalière</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
</code></pre></div></div>
<p>Ajouter en fin de fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Mise à jour automatique des serveurs DNS de la racine
50 02 * * * /etc/unbound/dnsunbound-update-root-dns.sh
</code></pre></div></div>
<h3 id="certificats-ssl-letsencrypt-acme">Certificats SSL letsencrypt (acme)</h3>
<p><img src="/images/letsencrypt-logo1.png" alt="SSL Letsencrypt" /></p>
<ul>
<li><a href="https://static.ouestline.net/linux/2017/08/31/Acme-Certficats-Serveurs.html">Acme et Lets Encrypt</a></li>
</ul>
<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="MyBRE3Oq2FZrLC2N"
export OVH_AS="U8rSfBLK0OYNRoeaCZvatqxUcf5aE8bj"
</code></pre></div></div>
<p>Génération des certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/root/.acme.sh/acme.sh --dns dns_ovh --issue --keylength 4096 -d cinay.pw -d smtp.cinay.pw -d imap.cinay.pw -d webmail.cinay.pw -d mail.cinay.pw -d nc.cinay.pw
</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 4096 -d cinay.pw -d smtp.cinay.pw -d imap.cinay.pw -d webmail.cinay.pw -d mail.cinay.pw -d nc.cinay.pw
</code></pre></div></div>
<p>Certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
[mercredi 14 mars 2018, 14:17:27 (UTC+0100)] Your cert is in /root/.acme.sh/cinay.pw/cinay.pw.cer
[mercredi 14 mars 2018, 14:17:27 (UTC+0100)] Your cert key is in /root/.acme.sh/cinay.pw/cinay.pw.key
[mercredi 14 mars 2018, 14:17:27 (UTC+0100)] The intermediate CA cert is in /root/.acme.sh/cinay.pw/ca.cer
[mercredi 14 mars 2018, 14:17:27 (UTC+0100)] And the full chain certs is there: /root/.acme.sh/cinay.pw/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/cinay.pw/fullchain.cer /etc/ssl/private/cinay.pw-fullchain.pem # full chain certs
ln -s /root/.acme.sh/cinay.pw/cinay.pw.key /etc/ssl/private/cinay.pw-key.pem # cert key
ln -s /root/.acme.sh/cinay.pw/cinay.pw.cer /etc/ssl/private/cinay.pw-chain.pem # cert
ln -s /root/.acme.sh/cinay.pw/ca.cer /etc/ssl/private/cinay.pw-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
44 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" &gt; /dev/null
</code></pre></div></div>
<blockquote>
<p>NOTE: Sous-domaines <strong>webmail.cinay.pw -&gt; Rainloop</strong> et <strong>nc.cinay.pw -&gt; Nextcloud , imap smtp et mail</strong></p>
</blockquote>
<h3 id="nginx--ssl--header--diffie-hellmann">Nginx + SSL + header + diffie-hellmann</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/cinay.pw-fullchain.pem;
ssl_certificate_key /etc/ssl/private/cinay.pw-key.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_prefer_server_ciphers on;
# Ciphers with intermediate compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&amp;openssl=1.0.1t&amp;hsts=yes&amp;profile=intermediate
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&amp;openssl=1.0.1t&amp;hsts=yes&amp;profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android before 5.0, Internet Explorer before 10, ...)
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
</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> # Quelques explications https://www.alsacreations.com/article/lire/1723-tour-horizon-https-et-en-tetes-de-securite.html
#HSTS est un dispositif de sécurité par lequel un site web peut déclarer aux navigateurs quils doivent communiquer avec lui en utilisant exclusivement le protocole HTTPS, au lieu du HTTP
add_header Strict-Transport-Security "max-age=31536000;";
# Seul le site utilise peut utiliser iFrame
add_header Content-Security-Policy "frame-ancestors 'self'";
#se protéger contre le détournement de clic (clickjacking)
add_header X-Frame-Options "SAMEORIGIN";
# Empêche les navigateurs de détecter incorrectement les scripts qui ne sont pas des scripts
add_header X-Content-Type-Options "nosniff";
# Bloquer les pages à charger lorsqu'elles détectent des attaques XSS
add_header X-XSS-Protection "1; mode=block";
#Supprimer les ## des lignes pour activer la fonction correspondante
#CSP permet dautoriser seulement les domaines déclarés à exécuter du script JavaScript, une feuille de style css, etc.
# Content-Security-Policy : https://openweb.eu.org/articles/content-security-policy
## add_header Content-Security-Policy "default-src 'self'";
# Désactiver les références pour les navigateurs qui ne prennent pas en charge strict-origin-when-cross-origin
# Referrer-Policy : https://scotthelme.co.uk/a-new-security-header-referrer-policy/
# Utilise strict-origin-when-cross-origin pour les navigateurs qui le font
## add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
</code></pre></div></div>
<p><strong>Diffie-Hellmann</strong><br />
Générer une clé Diffie-Hellmann<br />
<em>En cryptographie, léchange de clés Diffie-Hellman, du nom de ses auteurs Whitfield Diffie et Martin Hellman, est une méthode par laquelle deux agents nommés conventionnellement <strong>A</strong> et<strong>B</strong> peuvent se mettre daccord sur un nombre (quils peuvent utiliser comme clé pour chiffrer la conversation suivante) sans quun troisième agent appelé <strong>D</strong> puisse découvrir le nombre, même en ayant écouté tous leurs échanges.</em></p>
<blockquote>
<p>ATTENTION : Génération clé Diffie-Hellmann très très longue en temps , 30 minutes minimum…</p>
</blockquote>
<p>Générer une clé</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl dhparam -out /etc/ssl/private/dh4096.pem -outform PEM -2 4096
</code></pre></div></div>
<p>Droits pour root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod 600 /etc/ssl/private/dh4096.pem
</code></pre></div></div>
<p>Le fichier de configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/dh_param
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # 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;
</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/cinay.pw.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 ##
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cinay.pw;
#### 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;
include dh_param;
root /var/www/ ;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.0-fpm.sock; # PHP7.0
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
include conf.d/cinay.pw.d/*.conf;
access_log /var/log/nginx/cinay.pw-access.log;
error_log /var/log/nginx/cinay.pw-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 cinay.pw
</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.13.9
Date: Mon, 12 Mar 2018 12:46:04 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: https:///
</code></pre></div></div>
<p>Tester le lien <a href="https://cinay.pw">https://cinay.pw</a></p>
<p>Vérification headers <a href="https://securityheaders.io">https://securityheaders.io</a><br />
Vérification complète <a href="https://observatory.mozilla.org/analyze.html?host=cinay.pw">https://observatory.mozilla.org/analyze.html?host=cinay.pw</a></p>
<h3 id="parefeu-iptables-v4-v6">parefeu (iptables V4 V6)</h3>
<p><img src="/images/iptables1.png" alt="parefeu Iptables" /></p>
<p>Créer un script pour mettre en place des règles de base.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
sudo nano parefeu
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="c"># Efface toutes les règles en cours. -F toutes. -X utilisateurs</span>
iptables <span class="nt">-t</span> filter <span class="nt">-F</span>
iptables <span class="nt">-t</span> filter <span class="nt">-X</span>
iptables <span class="nt">-t</span> nat <span class="nt">-F</span>
iptables <span class="nt">-t</span> nat <span class="nt">-X</span>
iptables <span class="nt">-t</span> mangle <span class="nt">-F</span>
iptables <span class="nt">-t</span> mangle <span class="nt">-X</span>
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-F</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-X</span>
ip6tables <span class="nt">-t</span> mangle <span class="nt">-F</span>
ip6tables <span class="nt">-t</span> mangle <span class="nt">-X</span>
<span class="c"># stratégie (-P) par défaut : bloc tout l'entrant le forward et autorise le sortant</span>
iptables <span class="nt">-t</span> filter <span class="nt">-P</span> INPUT DROP
iptables <span class="nt">-t</span> filter <span class="nt">-P</span> FORWARD DROP
iptables <span class="nt">-t</span> filter <span class="nt">-P</span> OUTPUT ACCEPT
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-P</span> INPUT DROP
ip6tables <span class="nt">-t</span> filter <span class="nt">-P</span> FORWARD DROP
ip6tables <span class="nt">-t</span> filter <span class="nt">-P</span> OUTPUT ACCEPT
<span class="c"># Ne pas casser les connexions etablies</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-m</span> state <span class="nt">--state</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-m</span> state <span class="nt">--state</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT
<span class="c"># Autoriser Loopback</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-i</span> lo <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-o</span> lo <span class="nt">-j</span> ACCEPT
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-i</span> lo <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-o</span> lo <span class="nt">-j</span> ACCEPT
<span class="c"># Autoriser icmp</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">-j</span> ACCEPT
<span class="c"># SSH</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 55027 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 55027 <span class="nt">-j</span> ACCEPT
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 55027 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 55027 <span class="nt">-j</span> ACCEPT
<span class="c"># DNS in/out</span>
<span class="c"># /!\ Il faut autoriser le DNS AVANT de déclarer des hosts sinon pas de résolution de nom possible</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> udp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
<span class="c">#</span>
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> udp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">--dport</span> 53 <span class="nt">-j</span> ACCEPT
<span class="c"># HTTP + HTTPS</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
<span class="c"># IMAP SMTP</span>
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 993 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 587 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 25 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 993 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 587 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 25 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 993 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 587 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 25 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 993 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 587 <span class="nt">-j</span> ACCEPT
ip6tables <span class="nt">-t</span> filter <span class="nt">-A</span> OUTPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 25 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>
<p>fichier exécutable :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod +x parefeu
</code></pre></div></div>
<p>Vous pourrez le tester en lexécutant directement en ligne de commande.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
./parefeu
</code></pre></div></div>
<p>En cas derreur, redémarrez le serveur, les règles seront oubliées et vous permettront de reprendre la main.<br />
En revanche, si les tests savèrent concluants, ajoutez le lancement des règles iptables au démarrage.<br />
Après avoir exécuté le script précédent,vérifier la présence des règles</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -L
ip6tables -L
</code></pre></div></div>
<p>Lancement du parefeu au démarrage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install iptables-persistent
</code></pre></div></div>
<p>Faut-il enregistrer les règles IPv4 actuelles ? OUI<br />
Faut-il enregistrer les règles IPv6 actuelles ? OUI<br />
Les tables sont enregistrés sous <strong>/etc/iptables/</strong> , <strong>rules.v4</strong> pour IPv4 et <strong>rules.v6</strong> pour IPv6<br />
Sauvegarde/Restauration manuelle des régles iptables</p>
<p><code class="language-plaintext highlighter-rouge">iptables-save &gt; /etc/iptables/rules.v4</code><br />
<code class="language-plaintext highlighter-rouge">ip6tables-save &gt; /etc/iptables/rules.v6</code><br />
<code class="language-plaintext highlighter-rouge">iptables-restore &lt; /etc/iptables/rules.v4</code><br />
<code class="language-plaintext highlighter-rouge">ip6tables-restore &lt; /etc/iptables/rules.v6</code></p>
<p>En cas de modification pouvez sauver les nouvelles règles du pare-feu</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dpkg-reconfigure iptables-persistent
</code></pre></div></div>
<h2 id="serveur-de-messagerie">Serveur de messagerie</h2>
<p><img src="/images/serveur-messagerie.png" alt="Serveur de messagerie" /></p>
<p><a href="https://mondedie.fr/d/5750-Tuto-Installer-un-serveur-de-mail-avec-Postfix-Dovecot-et-Rainloop">Installation sécurisée dun serveur de mail avec Postfix, Dovecot et Rainloop</a><br />
<a href="https://linode.com/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8/">Configure SPF and DKIM With Postfix on Debian 8</a><br />
<a href="https://linode.com/docs/email/postfix/email-with-postfix-dovecot-and-mysql/#adding-new-domains-email-addresses-and-aliases">Email with Postfix, Dovecot, and MySQL</a></p>
<h3 id="prérequis">Prérequis</h3>
<ul>
<li>Domaine : cinay.pw</li>
<li>IPv4 du serveur : x.x.x.x</li>
<li>IPv6 du serveur : xxxx:xxxx:xx:xxxx::1</li>
<li>Courrier entrant : cinay.pw ou imap.cinay.pw sur port 993 (imaps)</li>
<li>Courrier sortant : cinay.pw ou smtp.cinay.pw sur port 587 (submission)</li>
<li>Compte courrier : yann@cinay.pw</li>
<li>Certificats : Lets Encrypt</li>
<li>Serveur Debian Stretch + Nginx + PHP7 + MariaDb + accès SSH</li>
<li>DNS de base configuré (OVH)</li>
</ul>
<blockquote>
<p>Par défaut ,courrier entrant et sortant sur <strong>cinay.pw</strong></p>
</blockquote>
<p>Vérifier que les enregistrements MX de votre configuration DNS du domaine <strong>cinay.pw</strong> pointent vers votre serveur:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig +short MX cinay.pw
10 cinay.pw.
</code></pre></div></div>
<p>Les certificats letsencrypt</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/ssl/private/cinay.pw-fullchain.pem
/etc/ssl/private/cinay.pw-key.pem
/etc/ssl/private/cinay.pw-chain.pem
/etc/ssl/private/cinay.pw-ca.pem
</code></pre></div></div>
<p>Toutes les opérations se font en mode su</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
</code></pre></div></div>
<h3 id="postfix">Postfix</h3>
<p><img src="/images/postfix.png" alt="Postfix" /></p>
<p>On commence par installer Postfix avec le support de mysql. Les domaines, comptes utilisateurs et alias seront ainsi gérés directement au sein dune base de données, que vous pourrez administrer grâce à vos outils habituels, comme phpMyAdmin par exemple.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install postfix postfix-mysql -y
</code></pre></div></div>
<p>Postfix, compléter les options comme ceci :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Configuration type du serveur de messagerie : Site Internet
Nom de courrier : cinay.pw
</code></pre></div></div>
<p>Générer les paramètres DH :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl dhparam -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512
openssl dhparam -out /etc/postfix/dh_2048.pem -2 -rand /var/run/egd-pool 2048 # on peur coder 2048 au lieu de 1024
</code></pre></div></div>
<p>Création dune base postfix et dun utilisateur postfix ayant tous les privilèges sur la base :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql -u root -p
</code></pre></div></div>
<p>La requête :</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="k">postfix</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'postfix'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'iq9awn3wEuUPxsi6qrdU'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="nv">`postfix`</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'postfix'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>
<span class="n">QUIT</span>
</code></pre></div></div>
<h4 id="postfixadmin">PostfixAdmin</h4>
<p><a href="/images/postfixadmin.png">PostfixAdmin</a></p>
<p>Télécharger la dernière version sur le dossier /var/www</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/www
wget 'http://sourceforge.net/projects/postfixadmin/files/postfixadmin/postfixadmin-3.1/postfixadmin-3.1.tar.gz/download' -O pfa.tar.gz
tar -zxvf pfa.tar.gz
mv postfixadmin-3.1 pfa
rm pfa.tar.gz
chown -R www-data. pfa
cd pfa
</code></pre></div></div>
<p>Il faut également télécharger <strong>php imap</strong></p>
<p>apt install php7.0-imap -y</p>
<p>Vous navez plus quà créer le fichier <strong>config.local.php</strong> dans le répertoire de PostfixAdmin <strong>/var/www/pfa</strong> :</p>
<p>nano /var/www/pfa/config.local.php</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;?php
$CONF['configured'] = true;
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'iq9awn3wEuUPxsi6qrdU';
$CONF['database_name'] = 'postfix';
$CONF['admin_email'] = 'admin@cinay.pw';
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['fetchmail'] = 'NO';
$CONF['encrypt'] = 'md5crypt';
?&gt;
</code></pre></div></div>
<p>Les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown www-data.www-data /var/www/pfa/config.local.php
</code></pre></div></div>
<p>Pour éviter lerreur lors de laccès à <strong>setup.php</strong> : <em>ERROR: the templates_c directory doesnt exist or isnt writeable for the webserver</em> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /var/www/pfa/templates_c
chown -R www-data: /var/www/pfa/templates_c/
</code></pre></div></div>
<p>Rendez-vous sur le <strong>setup.php</strong> de PostfixAdmin depuis votre navigateur <a href="https://cinay.pw/pfa/setup.php">https://cinay.pw/pfa/setup.php</a> <br />
Une vérification est effectué et si tout est OK ,il faut créer un “Setup password” puis générer un hash bouton “generate password hash”<br />
Editer le fichier le fichier <strong>config.local.php</strong> pour y ajouter le hash du “Setup password” :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$CONF['setup_password'] = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
</code></pre></div></div>
<p>Ajouter un administrateur (Create superadmin account) nommé postfixadmin@cinay.pw<br />
Le message suivant “You can now login to PostfixAdmin using the account you just created.” nous indique que lèon peut se connecter</p>
<p>Ouvrir linterface dadministration de PostfixAdmin <a href="https://cinay.pw/pfa/login.php">https://cinay.pw/pfa/login.php</a> avec <strong>postfixadmin@cinay.pw</strong> , vous devez ajouter un nouveau domaine puis un nouveau compte courrier.</p>
<ul>
<li>Domaine : cinay.pw</li>
<li>Compte courriel : yan@cinay.pw</li>
<li>Modifier les alias abuse,postmaster,hostmaster et webmaster pour quils pointent vers yan@cinay.pw</li>
</ul>
<h4 id="configuration-de-postfix">Configuration de Postfix</h4>
<p>Maintenant nous allons devoir configurer Postfix pour quil prenne en charge correctement les connexions SMTP et lenvoie des messages sur le réseau pour chaque utilisateur créé via PostfixAdmin.
Faites une sauvegarde du fichier de conf de Postfix <strong>/etc/postfix/main.cf</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp /etc/postfix/main.cf /etc/postfix/main.cf.bak
nano /etc/postfix/main.cf
</code></pre></div></div>
<p>Les paramètres . Noubliez pas de modifier la valeur de <strong>myhostname</strong> et <strong>mydomain</strong> en indiquant votre <strong>FQDN</strong>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#######################
## Paramètres généraux
#######################
compatibility_level = 2
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
readme_directory = no
delay_warning_time = 4h
mailbox_command = procmail -a "$EXTENSION"
recipient_delimiter = +
disable_vrfy_command = yes
message_size_limit = 502400000
mailbox_size_limit = 1024000000
inet_interfaces = all
inet_protocols = ipv4
myhostname = cinay.pw
mydomain = cinay.pw
mydestination = localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
relayhost =
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
####################
## Paramètres TLS
####################
# Smtp ( OUTGOING / Client )
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/ssl/private/cinay.pw-ca.pem
smtp_tls_protocols = !SSLv3
smtp_tls_mandatory_protocols = !SSLv3
smtp_tls_mandatory_ciphers = high
smtp_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, 3DES, RC2, RC4, MD5, PSK, SRP, DSS, AECDH, ADH
smtp_tls_note_starttls_offer = yes
# ---------------------------------------------------------------------------------------------------
# Smtpd ( INCOMING / Server )
smtpd_tls_loglevel = 1
smtpd_tls_auth_only = yes
smtpd_tls_security_level = may
smtpd_tls_received_header = yes
smtpd_tls_protocols = !SSLv3
smtpd_tls_mandatory_protocols = !SSLv3
smtpd_tls_mandatory_ciphers = medium
# Infos (voir : postconf -d)
# Medium cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:+RC4:@STRENGTH
# High cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:!MEDIUM:+RC4:@STRENGTH
# smtpd_tls_exclude_ciphers = NE PAS modifier cette directive pour des raisons de compatibilité
# avec les autres serveurs de mail afin d'éviter une erreur du type
# "no shared cipher" ou "no cipher overlap" puis un fallback en
# plain/text...
# smtpd_tls_cipherlist = Ne pas modifier non plus !
smtpd_tls_CAfile = $smtp_tls_CAfile
smtpd_tls_cert_file = /etc/ssl/private/cinay.pw-chain.pem
smtpd_tls_key_file = /etc/ssl/private/cinay.pw-key.pem
smtpd_tls_dh1024_param_file = $config_directory/dh_2048.pem
smtpd_tls_dh512_param_file = $config_directory/dh_512.pem
tls_preempt_cipherlist = yes
tls_random_source = dev:/dev/urandom
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
lmtp_tls_session_cache_database = btree:${data_directory}/lmtp_scache
###############################################################################################
## Paramètres de connexion SASL
## C'est ici que l'on déclare Dovecot comme une passerelle pour authentifier les utilisateurs.
## Postfix peut s'appuyer sur Dovecot pour identifier les connexions SMTP.
###############################################################################################
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_sasl_local_domain = $mydomain
smtpd_sasl_authenticated_header = yes
broken_sasl_auth_clients = yes
##############################
## VIRTUALS MAPS PARAMETERS ##
##############################
# Gestion et du stockage des emails.
# Utilisateur "vmail" avec UID/GID de 5000, avec un HOME par défaut pointant sur "/var/mail".
# Postfix doit le savoir donc on lui indique avec les 4 paramètres suivants :
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_minimum_uid = 5000
virtual_mailbox_base = /var/mail
# Les 4 règles suivantes permettent à Postfix de savoir comment se connecter et lire la base de donnée
# afin de récupérer des informations sur les différents domaines, adresses virtuelles et alias.
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
smtpd_sender_login_maps = mysql:/etc/postfix/mysql-sender-login-maps.cf
######################
## ERRORS REPORTING ##
######################
# notify_classes = bounce, delay, resource, software
notify_classes = resource, software
error_notice_recipient = hostmaster@cinay.pw
# delay_notice_recipient = admin@domain.tld
# bounce_notice_recipient = admin@domain.tld
# 2bounce_notice_recipient = admin@domain.tld
###############################################################################################
## Règles sur les adresses de destination
## permit_sasl_authenticated : Accepter la connexion lorsque le client est authentifié
## reject_non_fqdn_recipient : Refuser les adresses de destinations invalides (non FQDN)
###############################################################################################
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_recipient,
reject_unauth_destination,
reject_unknown_recipient_domain,
reject_rbl_client zen.spamhaus.org
###############################################################################################
## Règles sur l'échange HELO qui survient avant la connexion
## reject_invalid_helo_hostname : Refuser les échanges HELO invalides
## reject_non_fqdn_helo_hostname : Refuser les noms d'hôte invalides (non FQDN)
## reject_unknown_helo_hostname : Refuser les noms d'hôte qui n'ont pas de champ DNS A ou MX dans leurs DNS.
###############################################################################################
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
# reject_unknown_helo_hostname
###############################################################################################
## Règles de connexion des clients
## permit_sasl_authenticated : Accepter la connexion lorsque le client est authentifié
## reject_plaintext_session : Refuser les connexions non sécurisées
## reject_unauth_pipelining : Refuser les défauts lors de la connexion
###############################################################################################
smtpd_client_restrictions =
permit_mynetworks,
permit_inet_interfaces,
permit_sasl_authenticated,
# reject_plaintext_session,
# reject_unauth_pipelining
###############################################################################################
## Règles sur les expéditeurs
## reject_non_fqdn_sender : Refuser les expéditeurs invalides (non FQDN)
## reject_unknown_sender_domain : Refuser les expéditeurs qui n'ont pas de champ DNS A ou MX dans leurs DNS.
## reject_sender_login_mismatch : Refuser les expéditeurs locaux non authentifiés
###############################################################################################
smtpd_sender_restrictions =
reject_non_fqdn_sender,
reject_unknown_sender_domain,
# reject_sender_login_mismatch
#----------------------------------------------------------------------------------------------
# Le paramètre "virtual_transport" est très très important, il permet à Postfix de savoir où envoyer les emails reçus.
# Dans notre cas, on utilise le protocole **LMTP** pour les acheminer jusqu'à Dovecot
virtual_transport = lmtp:unix:private/dovecot-lmtp
</code></pre></div></div>
<p>Cest terminé pour le fichier de configuration principale, je vous laccorde il y a pas mal de paramètres à prendre en compte mais dans le cas dun serveur SMTP cest pas étonnant. <br />
Vous pouvez aller voir la documentation de Postfix si vous voulez avoir plus dinformations sur sa configuration. http://www.postfix.org/postconf.5.html<br />
Fichier de configuration complet <strong>main.cf</strong> : https://gist.github.com/hardware/b26918353c6325c09310</p>
<h4 id="configuration-de-postfix-pour-mysqlmariadb">Configuration de Postfix pour MySQL/MariaDb</h4>
<p>Créer les 4 fichiers de configuration qui vont permettre à Postfix dinteragir avec MySQL :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/postfix/mysql-virtual-mailbox-domains.cf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hosts = 127.0.0.1
user = postfix
password = iq9awn3wEuUPxsi6qrdU
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = 0 and active = 1
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/postfix/mysql-virtual-mailbox-maps.cf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hosts = 127.0.0.1
user = postfix
password = iq9awn3wEuUPxsi6qrdU
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/postfix/mysql-virtual-alias-maps.cf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hosts = 127.0.0.1
user = postfix
password = iq9awn3wEuUPxsi6qrdU
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/postfix/mysql-sender-login-maps.cf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hosts = 127.0.0.1
user = postfix
password = iq9awn3wEuUPxsi6qrdU
dbname = postfix
query = SELECT username FROM mailbox WHERE username='%s' AND active = 1
</code></pre></div></div>
<p>Si vous voulez activer le port 587 pour vous connecter de manière sécurisé par SMTPS avec nimporte quel client mail, il faut décommenter/modifier les lignes suivantes dans le fichier <strong>/etc/postfix/master.cf</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/postfix/master.cf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>submission inet n - - - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_dh1024_param_file=/etc/postfix/dh_2048.pem
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
</code></pre></div></div>
<p>Et noubliez pas de décommentez cette ligne aussi si ce nest pas déjà fait :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#smtp inet n - y - - smtpd
smtp inet n - - - - smtpd
</code></pre></div></div>
<h3 id="dovecot">Dovecot</h3>
<p><img src="/images/dovecot.png" alt="Dovecot" /></p>
<p><em>Dovecot est un serveur IMAP et POP3 pour les systèmes dexploitation Unix et dérivés, conçu avec comme premier but la sécurité. Dovecot est distribué en double licence MIT et GPL version 2.</em></p>
<p>Installation des paquets :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql -y
</code></pre></div></div>
<h4 id="configuration-de-dovecot">Configuration de dovecot</h4>
<p>Ajoutez la liste des protocoles activés <code class="language-plaintext highlighter-rouge">protocols = imap lmtp</code> après linstruction “!include_try” dans le fichier <strong>/etc/dovecot/dovecot.conf</strong>. Dans notre cas, nous allons activer IMAP pour la récupération des emails via le port 993 et LMTP pour lacheminement des emails entre Postfix et Dovecot :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/dovecot.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp
listen = *
# Assurez-vous que cette ligne est bien décommentée :
!include conf.d/*.conf
</code></pre></div></div>
<p>On indique le chemin du conteneur local qui contiendra tous nos emails. Editez le fichier <strong>10-mail.conf</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/conf.d/10-mail.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##
## Mailbox locations and namespaces
##
# Le contenur local est organisé de cette manière :
mail_location = maildir:/var/mail/vhosts/%d/%n/mail
maildir_stat_dirs=yes
namespace inbox {
inbox = yes
}
mail_uid = 5000
mail_gid = 5000
first_valid_uid = 5000
last_valid_uid = 5000
mail_privileged_group = vmail
</code></pre></div></div>
<p>Les emails seront stockés dans le répertoire <strong>/var/mail</strong>. On doit donc créer un répertoire correspondant à notre domaine (celui qui est présent dans la table “domain”).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /var/mail/vhosts/cinay.pw
</code></pre></div></div>
<p>Maintenant on ajoute un nouvel utilisateur et un nouveau groupe nommé <strong>vmail</strong> avec un UID/GID de 5000 :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail
chown -R vmail:vmail /var/mail
</code></pre></div></div>
<p>Editer le fichier <strong>10-auth.conf</strong> et modifier les lignes suivantes :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/conf.d/10-auth.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##
## Authentication processes
##
disable_plaintext_auth = yes
auth_mechanisms = plain login
#!include auth-system.conf.ext # Commenter cette ligne
!include auth-sql.conf.ext # décommenter cette ligne
</code></pre></div></div>
<p>Maintenant on va définir deux méthodes qui vont permettrent à Dovecot de savoir comment obtenir les utilisateurs et les mots de passe correspondants lors de la connexion. Editez le fichier <strong>auth-sql.conf.ext</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/conf.d/auth-sql.conf.ext
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Authentication for SQL users. Included from 10-auth.conf.
#
# Le mot de passe est obtenu à partir de la base de donnée
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
# Par contre le nom d'utilisateur est obtenu de manière statique à partir du conteneur local
# %d = domaine.tld
# %n = utilisateur
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
</code></pre></div></div>
<p>Ensuite editez le fichier <strong>dovecot-sql.conf.ext</strong> avec le contenu suivant :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/dovecot-sql.conf.ext
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Paramètres de connexion
driver = mysql
connect = host=127.0.0.1 dbname=postfix user=postfix password=iq9awn3wEuUPxsi6qrdU
# Permet de définir l'algorithme de hachage.
# Pour plus d'information: http://wiki2.dovecot.org/Authentication/PasswordSchemes
# /!\ ATTENTION : ne pas oublier de vérifier ou modifier le paramètre "$CONF['encrypt'] = 'md5crypt';" de PostfixAdmin
default_pass_scheme = MD5-CRYPT
# Requête de récupération du mot de passe du compte utilisateur
password_query = SELECT password FROM mailbox WHERE username = '%u'
</code></pre></div></div>
<p>Modifiez les permissions sur le répertoire <strong>/etc/dovecot</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
</code></pre></div></div>
<p>Editer le fichier <strong>10-master.conf</strong> avec le contenu suivant :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/conf.d/10-master.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
service_count = 0
}
service imap {
}
service lmtp {
# On autorise Postfix à transférer les emails dans le spooler de Dovecot via LMTP
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
# On autorise Postfix à se connecter à Dovecot via LMTP
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
# On indique à Dovecot les permissions du conteneur local
unix_listener auth-userdb {
mode = 0600
user = vmail
group = vmail
}
user = dovecot
}
service auth-worker {
user = vmail
}
</code></pre></div></div>
<p>Enfin, editez le fichier <strong>10-ssl.conf</strong> avec le contenu suivant :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/dovecot/conf.d/10-ssl.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##
## SSL settings
##
ssl = required
ssl_cert = &lt;/etc/ssl/private/cinay.pw-chain.pem
ssl_key = &lt;/etc/ssl/private/cinay.pw-key.pem
#ssl_protocols = !SSLv2 !SSLv3
ssl_protocols = !SSLv3
ssl_cipher_list = ALL:!aNULL:!eNULL:!LOW:!MEDIUM:!EXP:!RC2:!RC4:!DES:!3DES:!MD5:!PSK:!SRP:!DSS:!AECDH:!ADH:@STRENGTH
ssl_prefer_server_ciphers = yes # Dovecot &gt; 2.2.x
ssl_dh_parameters_length = 4096 # Dovecot &gt; 2.2.x
#ssl_dh_parameters_length = 2048 # Dovecot &gt; 2.2.x
</code></pre></div></div>
<h3 id="redémarrage-des-services-et-vérification-des-ports">Redémarrage des services et vérification des ports</h3>
<p>On redémarre Postfix et Dovecot :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart postfix dovecot
</code></pre></div></div>
<p>Puis on vérifie que les ports 25 (SMTP), 587 (SMTPS) et 993 (IMAPS) sont bien en écoute sur 0.0.0.0. Noubliez pas de les ouvrir au niveau de votre Firewall :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netstat -ptna
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Proto Recv-Q Send-Q Adresse locale Adresse distante Etat PID/Program name
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 6116/master
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 6009/dovecot
tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN 6116/master
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 6009/dovecot
</code></pre></div></div>
<p>Vous pouvez tester le serveur Postfix localement à partir du terminal en utilisant une connexion directe avec netcat, telnet ou similaire. Les commandes suivantes doivent être exécutées dans lordre correct pour que le serveur ferme la connexion.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nc cinay.pw 25
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>220 cinay.pw ESMTP Postfix (Debian/GNU)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EHLO $hostname
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>250-cinay.pw
250-PIPELINING
250-SIZE 502400000
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
</code></pre></div></div>
<p>Si vous voyez 250-STARTTLS, cest que le serveur supporte bien lauthentification par STARTTLS.</p>
<h3 id="reverse-dns">Reverse DNS</h3>
<p>Un enregistrement DNS inversé (aussi appelé “PTR record” correspond à un FQDN à une adresse IP. De nombreux fournisseurs de messagerie populaires vérifient les enregistrements PTR dautres serveurs de messagerie et refusent de recevoir leurs e-mails sils ne peuvent pas trouver un nom de domaine correct pour leurs adresses IP. Vous aurez besoin denregistrements PTR pour toutes les adresses IP de votre serveur. Ils doivent tous pointer vers mail. cinay. pw. Dans la plupart des cas, les entrées DNS inversées peuvent être réglées via linterface web de votre hébergeur serveur ou via léquipe de support du serveur.</p>
<h3 id="spf-records">SPF records</h3>
<p>SPF records a été inventé pour soutenir la lutte contre les serveurs de spam. Malheureusement, cela sest avéré être un malentendu et vous ne pouvez plus vous fier à ces enregistrements. SPF décrit quels serveurs de messagerie sont autorisés à envoyer des e-mails pour un domaine et lesquels ne le sont pas. Dans certains cas (par exemple les listes de diffusion), le concept SPF ne fonctionne pas. Certains fournisseurs sattendent toujours à ce que vous établissiez un record SPF - si ce nest pas le cas, vous obtiendrez un point sur votre “score de crédibilité anti-spam”. Faisons donc un compromis et fournissons un disque SPF neutre:</p>
<p><code class="language-plaintext highlighter-rouge">cinay.pw. 3600 IN TXT "v=spf1 a mx ip4:93.113.206.145 ip6:2a03:75c0:39:6a3f::1 -all"</code></p>
<p>Les mauvais fournisseurs de services « mail » seront satisfaits, mais nous ne soutenons pas les mauvaises pratiques de SPF. Lenregistrement SPF est également défini pour vos autres domaines “xoyize. xyz” et “oli. ovh”, mais dune manière légèrement différente:</p>
<p><code class="language-plaintext highlighter-rouge">xoyize.xyz. 3600 IN TXT v=spf1 include:cinay.pw ?all</code></p>
<h3 id="dmarc">DMARC</h3>
<p>Les enregistrements DMARC fixent des règles pour les serveurs de messagerie étrangers, qui leur indiquent comment traiter les e-mails non authentifiés ou incorrectement authentifiés. Si un spammeur envoie un faux e-mail et utilise votre domaine cinay.pw, le serveur destinataire consultera le DNS et demandera lenregistrement DMARC. Sil découvre que SPF ou DKIM échoue (ce qui sera le cas), le serveur procédera selon lenregistrement DMARC. Cest une bonne idée de rejeter de tels courriels:</p>
<p><code class="language-plaintext highlighter-rouge">_dmarc.cinay.pw. 3600 IN TXT v=DMARC1; p=reject;</code></p>
<p>Définissez lenregistrement DMARC pour vos autres domaines en conséquence:</p>
<p><code class="language-plaintext highlighter-rouge">_dmarc.xoyize.xyz. 3600 IN TXT v=DMARC1; p=reject;</code></p>
<p>Vous pouvez créer vos propres enregistrements de politique DMARC sur <a href="https://elasticemail.com/dmarc/">https://elasticemail.com/dmarc/</a>.</p>
<h3 id="rspamd">Rspamd</h3>
<p><img src="/images/rspamd.png" alt="rspamd" /></p>
<p><a href="https://linuxize.com/post/install-and-integrate-rspamd/">Install and integrate Rspamd</a><br />
Les dépôts officiels de Debian contiennent une version obsolète de Rspamd, utilisez donc le Rspamd-Repository pour linstallation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install -y lsb-release wget -y
wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
echo "deb http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" &gt; /etc/apt/sources.list.d/rspamd.list
echo "deb-src http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" &gt;&gt; /etc/apt/sources.list.d/rspamd.list
</code></pre></div></div>
<p>Mettez à jour les sources de paquets et installez Rspamd:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
apt install rspamd -y
</code></pre></div></div>
<p>Arrêter le servcie Rspamd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl stop rspamd
</code></pre></div></div>
<h4 id="configuration-de-base">Configuration de base</h4>
<p>Au lieu de modifier les fichiers de configuration stock, nous allons créer de nouveaux fichiers dans le répertoire <strong>/etc/rspamd/local.d/</strong> qui écraseront le réglage par défaut.</p>
<p>Les fichiers suivants sont maintenant créés dans <strong>/etc/rspamd/local.d/</strong>:</p>
<p><strong>/etc/rspamd/local.d/worker-normal.inc</strong>: Paramètres pour le Rspamd worker</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bind_socket = "127.0.0.1:11333";
</code></pre></div></div>
<p>Lagent mandataire écoute sur le port 11332 et prend en charge le protocole Milter. Pour que Postfix puisse communiquer avec Rspamd, nous devons activer le mode Milter: <strong>/etc/rspamd/local.d/worker-proxy.inc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bind_socket = "127.0.0.1:11332";
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
</code></pre></div></div>
<p>Ensuite, nous avons besoin de mettre en place un mot de passe pour le “controller worker” qui donne accès à linterface web de Rspamd. Pour générer un lancement de mot de passe crypté:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rspamadm pw --encrypt -p P4ssvv0rD
</code></pre></div></div>
<p>Et coller le code dans le fichier <strong>/etc/rspamd/local.d/worker-controller.inc</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type = "controller";
count = 1;
password = "$2$aib.........................bqxiy";
secure_ip = "127.0.0.1";
secure_ip = "::1";
static_dir = "${WWWDIR}";
</code></pre></div></div>
<p>Pour accéder à linterface web, nous configurerons plus tard Nginx en tant que proxy inverse pour le serveur web du contrôleur.<br />
Nous utiliserons Redis en tant que backend pour les statistiques Rspamd: <strong>/etc/rspamd/local.d/classifier-bayes.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>servers = "127.0.0.1";
backend = "redis";
</code></pre></div></div>
<p>Les entêtes milter <strong>/etc/rspamd/local.d/milter_headers.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
</code></pre></div></div>
<p>Redémarrer le service Rspamd:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart rspamd
</code></pre></div></div>
<h4 id="rspamd-dkim">Rspamd DKIM</h4>
<p>Rspamd ne soccupe pas seulement du filtrage des spams, mais est également capable de signer des e-mails via DKIM. Tout dabord, une clé de signature doit être créée:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /var/lib/rspamd/dkim/
rspamadm dkim_keygen -b 2048 -s 2018 -k /var/lib/rspamd/dkim/2018.key &gt; /var/lib/rspamd/dkim/2018.txt
chown -R _rspamd:_rspamd /var/lib/rspamd/dkim
chmod 440 /var/lib/rspamd/dkim/*
</code></pre></div></div>
<p>2018 est le nom de la touche DKIM (également appelée “sélecteur”). Jutilise lannée en cours comme nom. Pour une clé de signature DKIM (<strong>/var/lib/rspamd/dkim/2018.key</strong>) il y a aussi une clé publique correspondante, qui doit être publiée dans le DNS (<strong>/var/lib/rspamd/dkim/2018.txt</strong>)<br />
Enregistrement DNS de sortie avec clé publique:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /var/lib/rspamd/dkim/2018.txt
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2018._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/al5HqXUpe+HUazCr6t9lv2VOZLR369PPB4t+dgljZQvgUsIKoYzfS/w9NagS32xZYxi1dtlDWuRfTU/ahHO2MYzE0zHE4lMfwb6VkNCG+pM6bAkCwc5cFvyRygwxAPEiHAtmtU5b0i9LY25Z/ZWgyBxEWZ0Wf+hLjYHvnvMqewPsduUqKVjDOdUqeBb1VAu3WFErOAGVUYfKqFX"
"+yfz36Alb7/OMAort8A5Vo5t5k0vxTHzkYYg5KB6tLS8jngrNucGjyNL5+k0ijPs3yT7WpTGL3U3SEa8cX8WvOO1fIpWQz4yyZJJ1Mm62+FskSc7BHjdiMHE64Id/UBDDVjxwIDAQAB"
) ;
</code></pre></div></div>
<p>La partie importante commence par v=DKIM1 et se termine par AQAB (dans cet exemple). Placez maintenant cette partie de la sortie dans un nouvel enregistrement DNS.<br />
<strong>Assurez-vous que le préfixe _domainkey-subdomain-prefix correspond au préfixe de votre sélecteur! (“2018”)</strong><br />
Si votre enregistrement nest pas accepté par votre hébergeur DNS, une clé de 2048 bits peut être trop longue. Vous pouvez générer une clé plus courte en spécifiant -b 1024 au lieu de -b 2048 et en exécutant à nouveau la commande rspamadm dkim_keygen</p>
<p>Créer <strong>/etc/rspamd/local.d/dkim_signing.conf</strong> et définissez “2018” comme sélecteur:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>path = "/var/lib/rspamd/dkim/$selector.key";
selector = "2018";
### Enable DKIM signing for alias sender addresses
allow_username_mismatch = true;
</code></pre></div></div>
<p>Cette configuration est également copiée dans /etc/rspamd/local.d/arc.conf, puisque le «  ARC module » utilise les mêmes paramètres.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp -R /etc/rspamd/local.d/dkim_signing.conf /etc/rspamd/local.d/arc.conf
</code></pre></div></div>
<h4 id="redis">Redis</h4>
<p><img src="/images/redis.png" alt="Redis" /></p>
<p>Rspamd utilise Redis comme cache de données. Linstallation est simple:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install redis-server
</code></pre></div></div>
<p><strong>/etc/rspamd/local.d/redis.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>servers = "127.0.0.1";
</code></pre></div></div>
<h4 id="rspamd-postfix">Rspamd postfix</h4>
<p>Nous devons configurer Postfix pour utiliser le Rspamd Milter.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postconf -e "milter_protocol = 6"
postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"
postconf -e "milter_default_action = accept"
postconf -e "smtpd_milters = inet:127.0.0.1:11332"
postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"
</code></pre></div></div>
<p>Ajout au fichier <strong>/etc/postfix/main.cf</strong> rspamd dkimm</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##
## Spam filter and DKIM signatures via Rspamd
##
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_default_action = accept
smtpd_milters = inet:127.0.0.1:11332
non_smtpd_milters = inet:127.0.0.1:11332
</code></pre></div></div>
<p>Redémarrer postfix</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart postfix
</code></pre></div></div>
<h4 id="dovecot-sieve-filtrer-les-mails-côté-serveur">Dovecot Sieve (Filtrer les mails côté serveur)</h4>
<p>Vous connaissez très certainement les filtres côté clients, tout bon client mail possède un système de filtre permettant de trier automatiquement les mails en fonction de différents critères que vous pouvez définir. <strong>Sieve</strong> cest exactement la même chose mais côté serveur, il possède un langage de script pour définir soit même lensemble des règles.On intègre dovecot à rspamd.</p>
<p>Pour installer sieve, exécuter la commande suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install dovecot-sieve dovecot-managesieved
</code></pre></div></div>
<p>Ensuite dans le fichier <strong>/etc/dovecot/conf.d/20-lmtp.conf</strong>, ajouter le contenu suivant :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>protocol lmtp {
postmaster_address = postmaster@cinay.pw
mail_plugins = $mail_plugins sieve
}
</code></pre></div></div>
<p>Dans le fichier <strong>/etc/dovecot/conf.d/20-managesieve.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
service managesieve-login {
inet_listener sieve {
port = 4190
}
...
}
...
service managesieve {
process_limit = 1024
}
...
</code></pre></div></div>
<p>Dans le fichier <strong>/etc/dovecot/conf.d/20-imap.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
protocol imap {
...
#mail_plugins = $mail_plugins imap_quota imap_sieve
mail_plugins = $mail_plugins imap_sieve
...
}
...
</code></pre></div></div>
<p>Dans le fichier <strong>/etc/dovecot/conf.d/90-sieve.conf</strong>, modifier la configuration du plugin :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_before = /var/mail/sieve/default.sieve
#sieve = file:/var/mail/sieve/%d/%n/scripts;active=/var/mail/sieve/%d/%n/active-script.sieve
###
### Spam learning
###
# From elsewhere to Spam folder
imapsieve_mailbox1_name = Spam
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/var/mail/sieve/learn-spam.sieve
# From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Spam
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/var/mail/sieve/learn-ham.sieve
sieve_pipe_bin_dir = /usr/bin
sieve_global_extensions = +vnd.dovecot.pipe
#quota = maildir:User quota
#quota_exceeded_message = Benutzer %u hat das Speichervolumen überschritten. / User %u has exhausted allowed storage space.
}
</code></pre></div></div>
<p>Puis :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /var/mail/sieve/
touch /var/mail/sieve/default.sieve
</code></pre></div></div>
<p>Par défaut, vous pouvez mettre toutes les règles dans le fichier <strong>default.sieve</strong>, elles sappliqueront à toutes les adresses, les règles spécifiques à une adresse doivent être mises dans le fichier <strong>/var/mail/vhosts/xoyize.xyz/adresse/.dovecot.sieve</strong>. Attention si ce fichier existe, le fichier par défaut (default.sieve) ne sera pas lu pour lutilisateur courant.</p>
<p>Pour ce tutoriel, on va ajouter dans <strong>/var/mail/sieve/default.sieve</strong> une règle basique mais très utile :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require ["fileinto"];
if header :contains "Subject" "***SPAM***" {
fileinto "Spam";
}
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
}
if header :is "X-Spam" "Yes" {
fileinto "Spam";
}
</code></pre></div></div>
<p>Rspamd apprendra de ses erreurs si vous déplacez un courrier hors de votre dossier “Spam” et vice versa. Sieve reconnaît le processus de déplacement et déclenche un processus dapprentissage Rspam. Créez les deux fichiers de configuration suivants dans <strong>/var/mail/sieve/</strong>:</p>
<p><strong>/var/mail/sieve/learn-spam.sieve</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamc" ["learn_spam"];
</code></pre></div></div>
<p><strong>/var/mail/sieve/learn-ham.sieve</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamc" ["learn_ham"];
</code></pre></div></div>
<p>Et pour finir compiler les règles avec la commande sievec :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sievec /var/mail/sieve/default.sieve
sievec /var/mail/sieve/learn-spam.sieve
sievec /var/mail/sieve/learn-ham.sieve
chown -R vmail:vmail /var/mail/sieve
</code></pre></div></div>
<p>et on redémarre Dovecot :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart dovecot
</code></pre></div></div>
<h4 id="lancer-rspamd">Lancer Rspamd</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart postfix dovecot rspamd
</code></pre></div></div>
<h4 id="rspamd-via-tunnel-ssh">Rspamd via tunnel SSH</h4>
<p>Accès à linterface web Rspamd via tunnel SSH (alternative à Nginx)<br />
Si votre machine locale est un ordinateur Linux ou MAC, entrez la commande suivante pour lier linterface web à votre port TCP 8080 local:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 8080:localhost:11334 benutzer@mail.cinay.pw -N # sans clé
ssh -p 55027 -i ~/.ssh/kvm-vps-27199 -L 8080:localhost:11334 adxo@cinay.pw -N # avec clé
</code></pre></div></div>
<p>Linterface web peut alors être consultée via http://localhost:8080. CTRL+C annule la connexion.</p>
<p><img src="/images/rspamd-1.png" alt="rspamd" title="exemple statistique rspamd" /></p>
<h3 id="postfix-modifier-les-entêtes-de-message">Postfix ,modifier les entêtes de message</h3>
<p><em>Cacher les informations sensibles qui sont contenues dans les headers des mails que vous envoyez, comme votre adresse ip LAN/WAN, le User-Agent…etc.</em><br />
On va utiliser les regex. Créer le fichier <strong>/etc/postfix/header_checks</strong> et y ajouter :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/^Received:.*with ESMTPSA/ IGNORE
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^User-Agent:/ IGNORE
</code></pre></div></div>
<p>Ensuite modifier la configuration de postfix en ajoutant les lignes suivantes dans <strong>/etc/postfix/main.cf</strong> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postconf -e "mime_header_checks = regexp:/etc/postfix/header_checks"
postconf -e "header_checks = regexp:/etc/postfix/header_checks"
</code></pre></div></div>
<p>Et pour finir, il faut reconstruire la hash table et redémarrer postfix :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postmap /etc/postfix/header_checks
systemctl reload postfix
</code></pre></div></div>
<h3 id="fail2ban">Fail2ban</h3>
<p><img src="/images/fail2ban.png" alt="Fail2ban" /></p>
<p><em>Fail2ban lit des fichiers de log et bannit les adresses IP qui ont obtenu un trop grand nombre déchecs lors de lauthentification. Il met à jour les règles du pare-feu pour rejeter cette adresse IP. Ces règles peuvent êtres défines par lutilisateur.</em></p>
<p>Les commandes sont exécutées en mode su sudo</p>
<p>Installation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install fail2ban
</code></pre></div></div>
<p><strong>fail2ban.conf</strong></p>
<p>Rien à faire dans le fichier <strong>/etc/fail2ban/fail2ban.conf</strong>, vous pouvez laisser les options par défaut</p>
<p><strong>jail.conf</strong></p>
<p>Copier la configuration par défaut afin quelle ne soit pas supprimée en cas de mise à jour.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
</code></pre></div></div>
<p>Ce fichier est beaucoup plus intéressant, il contient tous les services à monitorer, et vous allez le découvrir, fail2ban ne se limite pas à SSH…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/fail2ban/jail.local
</code></pre></div></div>
<blockquote>
<p>Tous les commentaires ont été supprimés pour allèger le fichier.<br />
Les commentaires sont visibles dans le fichier original <strong>jail.conf</strong></p>
</blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[INCLUDES]
before = paths-debian.conf
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 600
findtime = 600
maxretry = 3
backend = auto
usedns = warn
logencoding = auto
filter = %(__name__)s
destemail = root@localhost
sender = root@localhost
mta = sendmail
protocol = tcp
chain = INPUT
port = 0:65535
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
banaction = iptables-multiport
banaction_allports = iptables-allports
protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
action = %(action_)s
</code></pre></div></div>
<p>Pour envoyer un mail contenant le whois, placez la variable sur :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>action = %(action_mw)s
</code></pre></div></div>
<p>Pour envoyer un mail avec le whois ET les logs, placez la variable sur :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>action = %(action_mwl)s
</code></pre></div></div>
<p>Pour activer la surveillance dun service, il suffit de placer la variable “enabled” à “true”</p>
<p>Par défaut la protection du service SSH est activée, pas les autres.</p>
<p>Si votre ssh nécoute pas sur le port 22, pensez à le changer… (port = N° de port).</p>
<p>Rappelez vous également que le loglevel de SSHD (<strong>/etc/ssh/sshd_config</strong>) doit absolument être positionné sur DEBUG (<strong>LogLevel DEBUG</strong>) sans quoi, Fail2ban ne bloquera rien concernant SSH.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#
# JAILS
#
# SSH
[sshd]
enabled = true
port = 55027
logpath = %(sshd_log)s
backend = %(sshd_backend)s
# Mail servers
[postfix]
enabled = true
port = smtp,ssmtp,submission
filter = postfix
logpath = /var/log/mail.log
[sasl]
enabled = true
port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
filter = postfix-sasl
# You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize.
logpath = /var/log/mail.log
[dovecot]
enabled = true
port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
filter = dovecot
logpath = /var/log/mail.log
# nginx
[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
</code></pre></div></div>
<p>Redémarrer fail2ban pour implémenter les règles:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart fail2ban
</code></pre></div></div>
<p>Afficher les règles de pare-feu actuelles</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -S
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N f2b-dovecot
-N f2b-nginx-http-auth
-N f2b-postfix
-N f2b-sasl
-N f2b-sshd
-A INPUT -p tcp -m multiport --dports 25,465,587 -j f2b-postfix
-A INPUT -p tcp -m multiport --dports 80,443 -j f2b-nginx-http-auth
-A INPUT -p tcp -m multiport --dports 55027 -j f2b-sshd
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p tcp -m tcp --dport 55027 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 587 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 55027 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 587 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A f2b-dovecot -j RETURN
-A f2b-nginx-http-auth -j RETURN
-A f2b-postfix -j RETURN
-A f2b-sasl -j RETURN
-A f2b-sshd -j RETURN
</code></pre></div></div>
<h3 id="clients-de-messagerie-linux-thunderbird-et-android-k9mail">Clients de messagerie (Linux Thunderbird et Android K9mail)</h3>
<p>La configuration dun client mail</p>
<p><img src="/images/yan-xoyize-xyz1.png" alt="thunderbird" title="exemple configuration thunderbird" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IMAP imap.cinay.pw ou cinay.pw 993 SSL/TLS Mot de Passe Normal
SMTP smtp.cinay.pw ou cinay.pw 587 STARTTLS Mot de Passe Normal
Utilisateur yan@cinay.pw
</code></pre></div></div>
<blockquote>
<p>Les adresses imap.cinay.pw et smtp.cinay.pw sont arbitraires, vous pouvez très bien mettre à la place le FQDN de votre serveur (exemple: cinay.pw), ça marchera très bien aussi. Le plus important ce sont les ports et les algorithmes de chiffrement/dauthentification (SSL/TLS - STARTTLS).</p>
</blockquote>
<h3 id="ajout-de-domaine-au-serveur-de-messagerie">Ajout de domaine au serveur de messagerie</h3>
<p>Utiliser <strong>PostFixAdmin</strong> pour ajouter des domaines et les utilisateurs associés<br />
Exemple pour un ajout des domaines <strong>oli.ovh</strong> et <strong>xoyize.xyz</strong> il faut ajouter les champs DNS suivants au gestionnaire du domaine</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>oli.ovh. 3600 IN MX 10 cinay.pw.
oli.ovh. 3600 IN TXT "v=spf1 include:cinay.pw ?all"
_dmarc.oli.ovh. 3600 IN TXT "v=DMARC1; p=reject;"
</code></pre></div></div>
<p><strong>xoyize.xyz</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xoyize.xyz. 3600 IN MX 10 cinay.pw.
xoyize.xyz. 3600 IN TXT "v=spf1 include:cinay.pw ?all"
_dmarc.xoyize.xyz. 3600 IN TXT "v=DMARC1"
</code></pre></div></div>
<p>Il faut paramétrer les clients de messagerie avec le serveur <strong>cinay.pw</strong> et les utilisateurs du domaine <strong>oli.ovh</strong></p>
<h2 id="nextcloud">Nextcloud</h2>
<p><img src="/images/nextcloud_logo.png" alt="Nextcloud" /></p>
<h3 id="installation">Installation</h3>
<h4 id="prérequis-1">Prérequis</h4>
<p><em>Toutes les commandes sont effectuées dans un terminal en super utilisateur (root)</em></p>
<p>Les paquets debian : <code class="language-plaintext highlighter-rouge">apt install php7.0 php7.0-fpm php7.0-mysql php7.0-curl php7.0-json php7.0-gd php7.0-mcrypt php7.0-tidy php7.0-intl php7.0-imagick php7.0-xml php7.0-mbstring php7.0-zip</code></p>
<p>Créer une base mariadb Nextcloud</p>
<p>mysql -uroot -p</p>
<p>sur le prompt <code class="language-plaintext highlighter-rouge">MariaDB [(none)]&gt;</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost' IDENTIFIED BY 'w5C4AGeTzFY4Fz';
FLUSH PRIVILEGES;
QUIT
</code></pre></div></div>
<h4 id="installer-la-dernière-version-nextcloud">Installer la dernière version nextcloud</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/www
wget https://download.nextcloud.com/server/releases/nextcloud-13.0.0.zip
unzip nextcloud-13.0.0.zip
mkdir /var/www/nextcloud/data
rm nextcloud-13.0.0.zip
# il est recommandé davoir un utilisateur dédié à la gestion du dossier nextcloud. Cet utilisateur aura des droits aussi restreints que possible à ce répertoire.
useradd nextcloud --comment "limited nextcloud user" --no-create-home
# modifier le propriétaire du répertoire /var/www/nextcloud et lattribuer à un nouvel utilisateur dédié : nextcloud.
chown -R nextcloud:www-data /var/www/nextcloud
# retirer toutes les permissions de ce répertoire aux autre utilisateurs
chmod -R o-rwx /var/www/nextcloud
</code></pre></div></div>
<h4 id="pool-php70-fpm-nextcloud">Pool php7.0-fpm-nextcloud</h4>
<p>Création du pool dédié à Nextcloud</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/php/7.0/fpm/pool.d/nextcloud.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[nextcloud]
listen = /run/php/php7.0-fpm-nextcloud.sock
; Set permissions for unix socket, if one is used.
listen.owner = nextcloud
listen.group = www-data
listen.mode = 0660
; Unix user/group of processes.
user = nextcloud
group = www-data
pm = dynamic
pm.max_children = 6
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 5
pm.max_requests = 500
pm.status_path = /fpm-status
ping.path = /ping
request_terminate_timeout = 1d
request_slowlog_timeout = 5s
slowlog = /var/log/nginx/nextcloud.slow.log
rlimit_files = 4096
rlimit_core = 0
chdir = /var/www/nextcloud/
catch_workers_output = yes
clear_env = no
php_value[upload_max_filesize] = 10G
php_value[post_max_size] = 10G
php_value[default_charset] = UTF-8
</code></pre></div></div>
<p>Redémarrez le service php-fpm afin dactiver le nouveau pool nextcloud :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart php7.0-fpm.service
</code></pre></div></div>
<p>Vérifier si aucune erreur <code class="language-plaintext highlighter-rouge">systemctl status php7.0-fpm.service</code></p>
<h3 id="nextcloud-nginx-vhost">Nextcloud nginx vhost</h3>
<p>Deux alternatives</p>
<ul>
<li>Alternative A : Nginx vhost cinay.pw/nextcloud ,accès <a href="https://cinay.pw/nextcloud">https://cinay.pw/nextcloud</a></li>
<li>Alternative B : Nginx vhost nc.cinay.pw (sous-domaine),accès <a href="https://nc.cinay.pw">https://nc.cinay.pw</a></li>
</ul>
<h4 id="alternative-a--nginx-vhost-cinaypwnextcloud">Alternative A : Nginx vhost cinay.pw/nextcloud</h4>
<p>La configuration vhost</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/nginx/conf.d/cinay.pw.d/nextcloud.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>location ^~ /nextcloud {
alias /var/www/nextcloud/;
if ($scheme = http) {
rewrite ^ https://$server_name$request_uri? permanent;
}
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';
# Set max upload size
client_max_body_size 10G;
fastcgi_buffers 64 4K;
# Disable gzip to avoid the removal of the ETag header
gzip off;
# Errors pages
error_page 403 /nextcloud/core/templates/403.php;
error_page 404 /nextcloud/core/templates/404.php;
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /nextcloud/public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /nextcloud/public.php?service=host-meta-json last;
location /nextcloud {
rewrite ^ /nextcloud/index.php$uri;
}
location = /nextcloud/robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/nextcloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_pass unix:/run/php/php7.0-fpm-nextcloud.sock;
fastcgi_intercept_errors on;
}
location ~ ^/nextcloud/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
location ~* \.(?:css|js)$ {
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers
add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
# Optional: Don't log access to other assets
access_log off;
}
}
</code></pre></div></div>
<p>Vérification</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
</code></pre></div></div>
<p>Relancer php-fpm et nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart php7.0-fpm nginx
</code></pre></div></div>
<p>Accès https://cinay.pw/nextcloud</p>
<h4 id="alternative-b--nginx-vhost-nccinaypw">Alternative B : Nginx vhost nc.cinay.pw</h4>
<p>Pour afficher la page de connexion Nextcloud sur <a href="https://nc.cinay.pw">https://nc.cinay.pw</a><br />
Créer le fichier <strong>/etc/nginx/conf.d/nc.cinay.pw.conf</strong> avec le contenu suivant</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
server {
listen 80;
listen [::]:80;
server_name nc.cinay.pw;
# enforce https
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name nc.cinay.pw;
include ssl_params;
include header_params;
include dh_param;
add_header Strict-Transport-Security "max-age=31536000;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
# Path to the root of your installation
root /var/www/nextcloud/;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
#Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff|svg|gif)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
# add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
</code></pre></div></div>
<p>Vérification</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx -t
</code></pre></div></div>
<p>Relancer php-fpm et nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart php7.0-fpm nginx
</code></pre></div></div>
<h4 id="nextcloud-première-connexion">Nextcloud première connexion</h4>
<p>Suivant alternative choisie : https://cinay.pw/nextcloud ou https://nc.cinay.pw<br />
Créer un compte administrateur admin + mot de passe<br />
Répertoire des données /var/www/nextcloud/data<br />
Base MariaDb (MySql) nextcloud , utilisateur nextcloud + mot de passe accès</p>
<blockquote>
<p>NOTE : Si vous voulez passer de lalternative A vers B ,lL faut modifier le fichier de configuration de nextcloud</p>
</blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 'trusted_domains' =&gt;
array (
0 =&gt; 'nc.cinay.pw',
),
'datadirectory' =&gt; '/var/www/nextcloud/data',
'overwrite.cli.url' =&gt; 'https://nc.cinay.pw',
</code></pre></div></div>
<h3 id="nextcloud-les-caches">Nextcloud les caches</h3>
<p><a href="https://static.ouestline.net/linux/2017/09/13/Nextcloud-Debian-Stretch.html#les-caches">Nextcloud Debian Stretch: les caches</a></p>
<p>Après installation du cache ,se connecter en <strong>admin</strong> , Paramètres -&gt; Paramètres de base</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Avertissements de sécurité &amp; configuration
Il est important pour la sécurité et la performance de votre instance que tout soit configuré correctement. Pour vous aider dans cette tâche, nous faisons des vérifications automatiques. Veuillez consulter la section Trucs et Astuces et la documentation pour plus d'informations.
x Tous les tests ont réussi.
</code></pre></div></div>
<h3 id="nextcloud-double-authentification-admin">Nextcloud double authentification (admin)</h3>
<p>Se connecter en <strong>admin</strong> sur nextcloud<br />
Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>Administration</strong> -&gt; <strong>+Applications</strong> -&gt; <strong>Sécurité</strong><br />
“Two Factor TOTP Provider” ,cliquer sur <strong>Activer</strong></p>
<p><img src="/images/2fa1.png" alt="2fa" title="Confirmer le mot de passe admin" /></p>
<p>Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>Administration</strong> -&gt; <strong>Paramètres</strong> -&gt; <strong>Sécurité</strong><br />
Cliquer <strong>Générer des codes de récupération</strong></p>
<p><img src="/images/2fa2.png" alt="2fa" /></p>
<p>Deuxième facteur dauthentification du mot de passe temporaire à usage unique</p>
<p><img src="/images/2fa.png" alt="2fa" /></p>
<p>Cocher la case <strong>Activer les mots de passe à usage unique (TOTP)</strong><br />
Votre nouveau secret TOTP est : <strong>kfkfiiehhdyyhdkz</strong><br />
Scannez ce QR code avec votre application android TOTP (<a href="https://f-droid.org/repo/org.shadowice.flocke.andotp_15.apk">andOTP</a>, <a href="https://f-droid.org/repo/org.shadowice.flocke.andotp_15.apk.asc">Signature PGP</a>)</p>
<p><img src="/images/2fa3.png" alt="2fa" /></p>
<p>Ue fois le code QR scanné, il faut saisir le code pour confirmer lactivation</p>
<h3 id="nextcloud-utilisateur-calendar-contacts-et-mail">Nextcloud Utilisateur, Calendar, Contacts et Mail</h3>
<h4 id="connexion-admin">Connexion admin</h4>
<p>Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>Utilisateurs</strong><br />
“Groupes” “+Ajouter un groupe” <strong>users</strong><br />
Ajouter un utilisateur <strong>yan</strong> , <strong>mot de passe</strong> ,groupe <strong>users</strong> , cliquer sur <strong>Créer</strong></p>
<p>Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>+Applications</strong> -&gt; <strong>Pack dapplications</strong><br />
Activer <strong>Calendar</strong><br />
Activer <strong>Contacts</strong><br />
Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>+Applications</strong> -&gt; <strong>Bureautique &amp;Texte</strong><br />
Activer <strong>Markdown Editor</strong> ,<strong>Notes</strong><br />
Activer <strong>Mail</strong> (client email imap smtp)</p>
<p><img src="/images/nextcloud-icones.png" alt="icones" title="Mail, Contacts, Agenda, Notes, Tâches" /></p>
<p><strong>Stockage externe</strong><br />
Cliquer sur licône <strong>A</strong> en haut à droite puis <strong>+Applications</strong> -&gt; <strong>Vos applications</strong><br />
Activer <strong>External storage support</strong></p>
<p>Pour une utilisation dun <strong>support externe</strong> à nextcloud, il faut créer ,en mode cli, un dossier <strong>local</strong> avec les droits nextcloud</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -
mkdir /mnt/local
# modifier le propriétaire du répertoire /var/www/nextcloud et lattribuer à un nouvel utilisateur dédié : nextcloud.
chown -R nextcloud:www-data /var/www/nextcloud
# retirer toutes les permissions de ce répertoire aux autre utilisateurs
chmod -R o-rwx /var/www/nextcloud
</code></pre></div></div>
<p>Il faut en connexion <strong>admin</strong> ,cliquer sur licône <strong>A</strong> en haut à droite puis <strong>Paramètres</strong> et dans la zone <em>Administration</em> sur <strong>Stockages externes</strong> <br />
Configurer le support externe</p>
<p><img src="/images/nc-ext.png" alt="Stockages externes" /></p>
<h4 id="connexion-utilisateur">Connexion utilisateur</h4>
<p>Cliquer sur licône <strong>Y</strong> en haut à droite puis <strong>Paramètres</strong><br />
Remplir le champ “Adresse e-mail”</p>
<p><strong>Messagerie</strong> : Cliquer sur licône <img src="/images/icone-mail.png" alt="icone mail" /> (en haut à gauche de lécran) et compléter</p>
<p><img src="/images/nc-email.png" alt="Mail" /></p>
<p><strong>Calendrier</strong> : Cliquer sur licône <img src="/images/icone-calendar.png" alt="icone mail" /><br />
Cliquer sur les <code class="language-plaintext highlighter-rouge">...</code> de <strong>Personnel</strong> ,”Editer”<br />
et renommer lagenda <strong>yan</strong>, choisir éventuellement une couleur autre et valider par clic sur licône <img src="/images/valider.png" alt="icone valider" /></p>
<p><strong>Contacts</strong> : Cliquer sur licône <img src="/images/icone-contacts.png" alt="icone mail" /> et renommer le carnet dadresses <strong>yan</strong></p>
<p>Activer lauthentification en deux étapes (voir opération précédente avec <strong>admin</strong>)</p>
<p><strong>Synchronisation client</strong><br />
Pour utiliser la synchronisation client , il faut aller dans <strong>Paramètres</strong> -&gt; <strong>Sécurité</strong> et cliquer sur <strong>Créer un nouveau mot de passe dapplication</strong> (donner un nom dapplication)<br />
Ce sera le mot de passe à utiliser pour la synchronisation de fichiers/dossiers (<u>Impératif quand on active la double authentification</u>)</p>
<p><img src="/images/security-nextcloud.png" alt="mp appli" /></p>
<h3 id="nextcloud-thèmes">Nextcloud Thèmes</h3>
<p>Changement de thème<br />
Se positionner dasn le dossier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/www/nextcloud/themes
</code></pre></div></div>
<p>Cloner le thème choisi</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/mwalbeck/nextcloud-breeze-dark.git
</code></pre></div></div>
<p>Valider le thème dans le fichier de configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /var/www/nextcloud/config/config.php
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 'theme' =&gt; 'nextcloud-breeze-dark',
</code></pre></div></div>
<h2 id="gitlab-serveur">GitLab serveur</h2>
<p><img src="/images/gitlab.png" alt="GitLab" /></p>
<h3 id="certificat-ssl-gitlabcinaypw">Certificat SSL gitlab.cinay.pw</h3>
<p>Il faut regénérer les certificats SSL en ajoutant le sous-domaine <strong>gitlab</strong><br />
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="MyBRE3Oq2FZrLC2N"
export OVH_AS="U8rSfBLK0OYNRoeaCZvatqxUcf5aE8bj"
</code></pre></div></div>
<p>Génération des certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/root/.acme.sh/acme.sh --dns dns_ovh --issue --keylength 4096 -d cinay.pw -d smtp.cinay.pw -d imap.cinay.pw -d webmail.cinay.pw -d mail.cinay.pw -d nc.cinay.pw -d gitlab.cinay.pw
</code></pre></div></div>
<h3 id="installer-gitlab">Installer gitlab</h3>
<p><a href="https://packages.gitlab.com/gitlab/gitlab-ce">Gitlab Gitlab-ce APT/YUM repository for GitLab Community Edition packages</a><br />
Passer en mode super utilisateur (root)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -LJO https://packages.gitlab.com/gitlab/gitlab-ce/packages/debian/stretch/gitlab-ce_10.5.4-ce.0_amd64.deb/download
dpkg -i gitlab-ce_10.5.4-ce.0_amd64.deb
</code></pre></div></div>
<h3 id="configuration-gitlab">Configuration gitlab</h3>
<p>on nutilise pas le serveur nginx embarqué dans gitlab-ce</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/gitlab/gitlab.rb
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>external_url 'https://gitlab.cinay.pw'
nginx['enable'] = false
web_server['external_users'] = ['www-data']
</code></pre></div></div>
<p>Générer la configuration</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gitlab-ctl reconfigure # Patienter quelques minutes !!!
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Running handlers complete
Chef Client finished, 368/525 resources updated in 02 minutes 07 seconds
gitlab Reconfigured!
</code></pre></div></div>
<h3 id="nginx-gitlab-proxy">Nginx gitlab proxy</h3>
<p>Ajout www-data au groupe gitlab-www</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod -aG gitlab-www www-data
</code></pre></div></div>
<p>Créer le fichier de configuration nginx <strong>/etc/nginx/conf.d/gitlab.cinay.pw.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upstream gitlab-workhorse {
server unix:/var/opt/gitlab/gitlab-workhorse/socket fail_timeout=0;
}
server {
listen 80;
listen [::]:80;
server_name gitlab.cinay.pw;
# enforce https
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name gitlab.cinay.pw;
include ssl_params;
include header_params;
include dh_param;
location / {
client_max_body_size 0;
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse;
}
}
</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 nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl reload nginx
</code></pre></div></div>
<h3 id="connexion-site-gitlabcinaypw">Connexion site gitlab.cinay.pw</h3>
<p>A la première connexion au site <a href="https://gitlab.cinay.pw">https://gitlab.cinay.pw</a> , il faut renseigné le mot de passe “admin”<br />
Cliquer sur <strong>Register</strong> et créer un utilisateur<br />
Full name : Cin Yan<br />
Username : yan<br />
Email : yan@cinay.pw<br />
Password : xxxxxxxxx</p>
<p>Créer un groupe <strong>spm</strong> avec accès <strong>Public</strong> (<a href="https://gitlab.cinay.pw/spm">https://gitlab.cinay.pw/spm</a>)</p>
<h2 id="git-client">Git client</h2>
<p><img src="/images/git.png" alt="Git" /></p>
<p><em>git est un logiciel de gestion de versions.</em></p>
<p>Installation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install git #debian
sudo pacman -S git #archlinux/manjaro
</code></pre></div></div>
<p>On dispose dun serveur décentralisé de type gitlab , <a href="https://gitlab.cinay.pw">https://gitlab.cinay.pw</a></p>
<p>Configuration globale de Git</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global user.name "Cin Yan"
git config --global user.email "yan@cinay.pw"
</code></pre></div></div>
<p>Il faut également ajouter en fin de fichier <strong>~/.gitconfig</strong> les 4 lignes suivantes (si inexistantes)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[credential]
helper = store
[core]
editor = nano
</code></pre></div></div>
<p>Modifier ou créer <strong>~/.git-credentials</strong> pour un accès auto<br />
<code class="language-plaintext highlighter-rouge">https://yan:Mot-de-passe@gitlab.cinay.pw</code></p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2018-11-23T00:00:00+01:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2018/11/23/KVM4-FirstHeberg-vps-26381-Debian9-xoyize.xyz.html">KVM4 FirstHeberg vps-26381 Debian9 xoyize.xyz</a></div><div class="next"><span>SUIVANT</span><a href="/2018/11/23/PC2-Manjaro-XFCE.html">Manjaro (Ordinateur Bureau PC2)</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>