2722 lines
232 KiB
HTML
2722 lines
232 KiB
HTML
|
<!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>Nginx, PHP8.0, MariaDB et Nextcloud - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="Nextcloud peut être installé sur n’importe quel serveur supportant une version récente de PHP et supportant MariaDB (base de données par défaut), MySQL ou Po...">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2021/09/18/Nextcloud22_Nginx_PHP8-FPM_MariaDB_SSL-TLS.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} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {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;">Nginx, PHP8.0, MariaDB et Nextcloud</h1></header></div><meta itemprop="headline" content="Nginx, PHP8.0, MariaDB et Nextcloud"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=nextcloud">nextcloud</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">18 sept. 2021</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F">23 sept. 2021</span></li></ul></div><meta itemprop="datePublished" content="2021-09-23T00:00:00+02:00">
|
|||
|
<meta itemprop="keywords" content="nextcloud"><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">⇧</button>
|
|||
|
|
|||
|
<script>
|
|||
|
//Get the button
|
|||
|
var mybutton = document.getElementById("myBtn");
|
|||
|
|
|||
|
// When the user scrolls down 20px from the top of the document, show the button
|
|||
|
window.onscroll = function() {scrollFunction()};
|
|||
|
|
|||
|
function scrollFunction() {
|
|||
|
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|||
|
mybutton.style.display = "block";
|
|||
|
} else {
|
|||
|
mybutton.style.display = "none";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// When the user clicks on the button, scroll to the top of the document
|
|||
|
function topFunction() {
|
|||
|
document.body.scrollTop = 0;
|
|||
|
document.documentElement.scrollTop = 0;
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
<!-- end custom article top snippet -->
|
|||
|
<div class="article__content" itemprop="articleBody"><details>
|
|||
|
<summary><b>Afficher/cacher Sommaire</b></summary>
|
|||
|
<!-- affichage sommaire -->
|
|||
|
<div class="toc-aside js-toc-root"></div>
|
|||
|
</details><p><em>Nextcloud peut être installé sur n’importe quel serveur supportant une version récente de PHP et supportant MariaDB (base de données par défaut), MySQL ou PostgreSQL.</em></p>
|
|||
|
|
|||
|
<p>Serveur debian/ubuntu à jour<br />
|
|||
|
Utilisateur avec droits sudo</p>
|
|||
|
|
|||
|
<h2 id="nginx-php80-mariadb">Nginx PHP8.0 MariaDB</h2>
|
|||
|
|
|||
|
<h3 id="nginx">nginx</h3>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install nginx
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Oter le commentaire de la ligne <code class="language-plaintext highlighter-rouge">server_tokens off;</code> dans la configuration de base <code class="language-plaintext highlighter-rouge">/etc/nginx/nginx.conf</code></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>worker_processes</strong> : laisser <strong>auto</strong> ou pour profiter pleinement de la puissance de votre serveur, il est recommandé de mettre autant de worker_processes que de cœurs disponibles sur votre serveur. Pour connaître le nombre de cœurs sur votre serveur, il suffit de lancer la commande : <code class="language-plaintext highlighter-rouge">grep processor /proc/cpuinfo | wc -l</code></li>
|
|||
|
<li><strong>server_tokens</strong> : pour des raisons de sécurité, il est recommandé de désactiver l’envoi d’informations telles que le numéro de version de votre Nginx. Pour cela, décommentez cette directive dans le bloc http.</li>
|
|||
|
<li>modifier le fichier <code class="language-plaintext highlighter-rouge">/etc/nginx/nginx.conf</code></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>On autorise tls1.2 et tls1.3 uniquement et ciphers off</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
|
|||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|||
|
ssl_prefer_server_ciphers off;
|
|||
|
[...]
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Relancer nginx : <code class="language-plaintext highlighter-rouge">sudo systemctl restart nginx</code></p>
|
|||
|
|
|||
|
<h3 id="php-80">PHP 8.0</h3>
|
|||
|
|
|||
|
<p>Ajout du dépôt sury.org</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour installer la version de 8 de php, ajouter le dépôt sury.</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install</span> <span class="nt">-y</span> lsb-release apt-transport-https ca-certificates wget
|
|||
|
wget <span class="nt">-O</span> /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
|
|||
|
<span class="nb">echo</span> <span class="s2">"deb https://packages.sury.org/php/ </span><span class="si">$(</span>lsb_release <span class="nt">-sc</span><span class="si">)</span><span class="s2"> main"</span> |tee /etc/apt/sources.list.d/php.list
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installer php8.0</p>
|
|||
|
|
|||
|
<p>Mise à jour des dépôts :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>installer les paquets PHP nécessaires à nextcloud</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install php8.0 php8.0-cli php8.0-gd php8.0-imap php8.0-mysql php8.0-soap php8.0-apcu php8.0-common php8.0-gmp php8.0-intl php8.0-opcache php8.0-xml php8.0-curl php8.0-igbinary php8.0-readline php8.0-zip php8.0-bcmath php8.0-fpm php8.0-imagick php8.0-mbstring php8.0-redis imagemagick
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="mariadb">MariaDB</h3>
|
|||
|
|
|||
|
<p><a href="/htmldoc/Debian%2010%20Buster%20-%20installer%20et%20configurer%20MariaDB.html">Debian 10 Buster : installer et configurer MariaDB</a></p>
|
|||
|
|
|||
|
<h2 id="nextcloud">Nextcloud</h2>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.jjworld.fr/installer-nextcloud-creer-son-cloud-personnel/">Installer Nextcloud 22 – Ubuntu et Debian</a></li>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/">Nextcloud Server Administration Guide</a></li>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/user_manual/fr/">Manuel utilisateur de Nextcloud (fr)</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="installation">Installation</h3>
|
|||
|
|
|||
|
<p>On télécharge Nextcloud 22</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://download.nextcloud.com/server/releases/latest-22.tar.bz2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Télécharger le SHA256</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://download.nextcloud.com/server/releases/latest-22.tar.bz2.sha256
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier l’intégrité de l’archive téléchargée</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sha256sum -c latest-22.tar.bz2.sha256 < latest-22.tar.bz2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Doit donner le résultat suivant : <strong>latest-22.tar.bz2: OK</strong></p>
|
|||
|
|
|||
|
<p>Vérifier la signature PGP et la provenance de l’archive téléchargée (FACULTATIF)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2.asc
|
|||
|
sudo wget https://nextcloud.com/nextcloud.asc
|
|||
|
gpg --import nextcloud.asc
|
|||
|
gpg --verify latest.tar.bz2.asc latest.tar.bz2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Donne le résultat suivant</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpg: Signature faite le jeu. 08 avril 2021 15:34:38 CEST
|
|||
|
gpg: avec la clef RSA 28806A878AE423A28372792ED75899B9A724937A
|
|||
|
gpg: Bonne signature de « Nextcloud Security <security@nextcloud.com> » [inconnu]
|
|||
|
gpg: Attention : cette clef n'est pas certifiée avec une signature de confiance.
|
|||
|
gpg: Rien n'indique que la signature appartient à son propriétaire.
|
|||
|
Empreinte de clef principale : 2880 6A87 8AE4 23A2 8372 792E D758 99B9 A724 937A
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Décompresser l’archive Nextcloud :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tar -xvf latest-22.tar.bz2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Déplacement</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mv nextcloud /var/www/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Supprimez les fichiers et signatures téléchargés :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm latest-22.tar.bz2*
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="utilisateur-nextcloud">Utilisateur nextcloud</h3>
|
|||
|
|
|||
|
<p>Lors du déploiement basique d’un serveur HTTP, l’utilisateur sous lequel fonctionne ce serveur (Apache, Nginx…) est la plupart du temps www-data, nobody ou apache. Cela signifie que si plusieurs sites existent sous la même instance de Nginx, tous utilisent le même utilisateur. Or si l’un des sites s’avère corrompu par un utilisateur malveillant alors l’assaillant peut profiter pleinement de tous les droits de l’utilisateur sous lequel tourne le serveur web. Tous les sites s’avèrent donc vulnérables.</p>
|
|||
|
|
|||
|
<p>Pour des raisons évidentes de sécurité, il est donc recommandé de cloisonner ces utilisateurs et d’avoir un utilisateur dédié à la gestion du dossier nextcloud. Cet utilisateur aura des droits aussi restreints que possible à ce répertoire.
|
|||
|
Par défaut, les fichiers de Nextcloud possèdent les permissions suivantes :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>répertoires : 755 (permission de lecture, d’écriture et d’exécution pour le propriétaire et permission de lecture et d’exécution pour le groupe et les autres)</li>
|
|||
|
<li>fichiers : 644 (permission de lecture et d’écriture pour le propriétaire et permission de lecture uniquement pour le groupe et les autres).</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Nous allons donc modifier le propriétaire du répertoire <code class="language-plaintext highlighter-rouge">/var/www/nextcloud</code> et l’attribuer à un nouvel utilisateur dédié : <strong>nextcloud</strong></p>
|
|||
|
|
|||
|
<p>Par ailleurs, Nginx est lancé sous l’utilisateur <strong>www-data</strong> et doit avoir accès en lecture au répertoire <code class="language-plaintext highlighter-rouge">/var/www/nextcloud</code> pour lire les ressources statiques (HTML, CSS, JS, etc.). Nous allons donc attribuer le répertoire <code class="language-plaintext highlighter-rouge">/var/www/nextcloud</code> au groupe <strong>www-data</strong>. Enfin nous retirerons toutes les permissions de ce répertoire aux autres utilisateurs.</p>
|
|||
|
|
|||
|
<p>Créez un utilisateur nextcloud</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd -r nextcloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Modifiez le propriétaire et le groupe du répertoire /var/www/nextcloud :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown -R nextcloud:www-data /var/www/nextcloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Retirez toutes les permissions aux autres utilisateurs :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod -R o-rwx /var/www/nextcloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="mariadb-1">MariaDB</h3>
|
|||
|
|
|||
|
<p>Installation de MariaDB</p>
|
|||
|
|
|||
|
<p>Comme d’habitude, on utilise la commande apt-get pour installer les paquets de MariaDB</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install mariadb-server
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Mot de passe base nextcloud</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tr -cd '[:alnum:]' < /dev/urandom | fold -w16 | head -n1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Accès base par su</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Tout comme pour la gestion du répertoire nextcloud et pour plus de sécurité, vous allez tout d’abord créer un utilisateur MySQL <strong>nextcloud</strong> dédié à la base de données nextcloud, renseigner un mot de passe et ensuite lui donner les droits sur cette base de données.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql -u root <<-EOF
|
|||
|
CREATE DATABASE nextcloud;
|
|||
|
CREATE USER "nextcloud"@"localhost";
|
|||
|
SET password FOR "nextcloud"@"localhost" = password('xxxxxxxxxxxxxxxxxx');
|
|||
|
GRANT ALL PRIVILEGES ON nextcloud.* TO "nextcloud"@"localhost" IDENTIFIED BY "xxxxxxxxxxxxxxxxxx";
|
|||
|
FLUSH PRIVILEGES;
|
|||
|
EOF
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="cloudxoyazxyz">cloud.xoyaz.xyz</h3>
|
|||
|
|
|||
|
<p>Domaine xoyaz.xyz OVH</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL 3600
|
|||
|
@ IN SOA dns106.ovh.net. tech.ovh.net. (2021091801 86400 3600 3600000 300)
|
|||
|
IN NS ns106.ovh.net.
|
|||
|
IN NS dns106.ovh.net.
|
|||
|
IN A 5.2.79.127
|
|||
|
IN AAAA 2a04:52c0:101:82::1
|
|||
|
cloud IN A 45.145.166.51
|
|||
|
cloud IN AAAA 2a04:ecc0:8:a8:4567:833:0:1
|
|||
|
hms IN A 45.145.166.51
|
|||
|
hms IN AAAA 2a04:ecc0:8:a8:4567:833:0:1
|
|||
|
wg IN CNAME xoyaz.xyz.
|
|||
|
zic IN CNAME xoyaz.xyz.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Certificats Let’s Encrypt sur le domaine cloud.xoyaz.xyz</strong><br />
|
|||
|
Installation des certificats</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>acme.sh --ecc --install-cert -d hms.xoyaz.xyz -d cloud.xoyaz.xyz --key-file /etc/ssl/private/xoyaz.xyz-key.pem --fullchain-file /etc/ssl/private/xoyaz.xyz-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Editer le crontab</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>56 0 * * * "/home/userhms/.acme.sh"/acme.sh --cron --home "/home/userhms/.acme.sh" --renew-hook "/home/userhms/.acme.sh/acme.sh --ecc --install-cert -d hms.xoyaz.xyz -d cloud.xoyaz.xyz --key-file /etc/ssl/private/xoyaz.xyz-key.pem --fullchain-file /etc/ssl/private/xoyaz.xyz-fullchain.pem --reloadcmd 'sudo systemctl reload nginx.service'" > /dev/null
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>PHP pool nextcloud</strong><br />
|
|||
|
Création du pool nextcloud <code class="language-plaintext highlighter-rouge">/etc/php/8.0/fpm/pool.d/nextcloud.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/php/8.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/nextcloud.sock
|
|||
|
|
|||
|
listen.owner = nextcloud
|
|||
|
listen.group = www-data
|
|||
|
|
|||
|
user = nextcloud
|
|||
|
group = www-data
|
|||
|
|
|||
|
pm = ondemand
|
|||
|
pm.max_children = 56
|
|||
|
pm.process_idle_timeout = 60s
|
|||
|
pm.max_requests = 500
|
|||
|
|
|||
|
env[HOSTNAME] = $HOSTNAME
|
|||
|
env[PATH] = /usr/local/bin:/usr/bin:/bin
|
|||
|
env[TMP] = /tmp
|
|||
|
env[TMPDIR] = /tmp
|
|||
|
env[TEMP] = /tmp
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>mémoire pour PHP</strong> , ajouter <code class="language-plaintext highlighter-rouge">memory_limit = 512M</code> dans le fichier <code class="language-plaintext highlighter-rouge">/etc/php/8.0/fpm/php.ini</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sed -i -e "s/^memory_limit \+= \+.*$/memory_limit = 512M/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sudo sed -i -e "s/^output_buffering \+= \+.*$/output_buffering = 0/g" /etc/php/8.0/fpm/php.ini
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/php/8.0/fpm/php.ini |egrep "memory_limit|^output_buffering"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>output_buffering = 0
|
|||
|
memory_limit = 512M
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Cache PHP : OPcache</strong></p>
|
|||
|
|
|||
|
<p><em>OPcache (qui signifie Optimizer Plus Cache) est introduit depuis la version 5.5.0 de PHP. Il sert à cacher l’opcode de PHP, c’est-à-dire les instructions de bas niveau générées par la machine virtuelle PHP lors de l’exécution d’un script. Autrement dit, le code pré-compilé est stocké en mémoire. Cela évite ainsi l’étape de compilation à chaque requête PHP. De plus, OPcache va optimiser l’exécution du code afin d’en améliorer les performances.</em></p>
|
|||
|
|
|||
|
<p>Alternative A: Éditez le fichier /etc/php/8.0/fpm/php.ini,ajouter les lignes suivantes dans la section [opcache] :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/php/8.0/fpm/php.ini
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[opcache]
|
|||
|
opcache.enable = 1
|
|||
|
opcache.interned_strings_buffer = 8
|
|||
|
opcache.max_accelerated_files = 10000
|
|||
|
opcache.memory_consumption = 128
|
|||
|
opcache.save_comments = 1
|
|||
|
opcache.revalidate_freq = 1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Alternative B: Exécuter les instructions suivantes</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sed -i -e "s/^;* *opcache\.enable *= *.*$/opcache.enable=1/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sed -i -e "s/^;* *opcache\.memory_consumption *= *.*$/opcache.memory_consumption=128/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sed -i -e "s/^;* *opcache\.interned_strings_buffer *= *.*$/opcache.interned_strings_buffer=8/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sed -i -e "s/^;* *opcache\.max_accelerated_files *= *.*$/opcache.max_accelerated_files=10000/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sed -i -e "s/^;* *opcache\.revalidate_freq *= *.*$/opcache.revalidate_freq=1/g" /etc/php/8.0/fpm/php.ini
|
|||
|
sed -i -e "s/^;* *opcache\.save_comments *= *.*$/opcache.save_comments=1/g" /etc/php/8.0/fpm/php.ini
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/php/8.0/fpm/php.ini | \
|
|||
|
egrep "^;* *opcache\.enable *=|^;* *opcache\.interned_strings_buffer *=\
|
|||
|
|^;* *opcache\.max_accelerated_files *=|^;* *opcache\.memory_consumption *=\
|
|||
|
|^;* *opcache\.save_comments *=|^;* *opcache\.revalidate_freq *="
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La nouvelle configuration sera prise en compte après redémarrage du service PHP-FPM :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart php8.0-fpm.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Nginx cloud.xoyaz.xyz.conf</strong></p>
|
|||
|
|
|||
|
<p>NGINX Configuration <a href="https://docs.nextcloud.com/server/22/admin_manual/installation/nginx.html">https://docs.nextcloud.com/server/22/admin_manual/installation/nginx.html</a></p>
|
|||
|
|
|||
|
<p>Le fichier de configuration web <code class="language-plaintext highlighter-rouge">cloud.xoyaz.xyz.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/nginx/conf.d/cloud.xoyaz.xyz.conf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upstream php-handler {
|
|||
|
server unix:/var/run/php/nextcloud.sock;
|
|||
|
}
|
|||
|
|
|||
|
server {
|
|||
|
listen 80;
|
|||
|
listen [::]:80;
|
|||
|
server_name cloud.xoyaz.xyz;
|
|||
|
# enforce https
|
|||
|
return 301 https://$server_name:443$request_uri;
|
|||
|
}
|
|||
|
|
|||
|
server {
|
|||
|
listen 443 ssl http2;
|
|||
|
listen [::]:443 ssl http2;
|
|||
|
server_name cloud.xoyaz.xyz;
|
|||
|
|
|||
|
# Use Mozilla's guidelines for SSL/TLS settings
|
|||
|
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
|||
|
# NOTE: some settings below might be redundant
|
|||
|
ssl_certificate /etc/ssl/private/xoyaz.xyz-fullchain.pem;
|
|||
|
ssl_certificate_key /etc/ssl/private/xoyaz.xyz-key.pem;
|
|||
|
|
|||
|
# TLS 1.3 only
|
|||
|
ssl_protocols TLSv1.3;
|
|||
|
ssl_prefer_server_ciphers off;
|
|||
|
|
|||
|
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
|||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
|||
|
|
|||
|
# Virtual Host Configs
|
|||
|
include /etc/nginx/conf.d/hms.xoyaz.xyz.d/*.conf;
|
|||
|
|
|||
|
# OCSP stapling
|
|||
|
ssl_stapling on;
|
|||
|
ssl_stapling_verify on;
|
|||
|
|
|||
|
# verify chain of trust of OCSP response using Root CA and Intermediate certs
|
|||
|
ssl_trusted_certificate /etc/ssl/private/xoyaz.xyz-fullchain.pem;
|
|||
|
|
|||
|
# replace with the IP address of your resolver
|
|||
|
resolver 8.8.8.8;
|
|||
|
|
|||
|
|
|||
|
# Add headers to serve security related headers
|
|||
|
# Before enabling Strict-Transport-Security headers please read into this
|
|||
|
# topic first.
|
|||
|
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
|
|||
|
#
|
|||
|
# 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 Referrer-Policy "no-referrer" always;
|
|||
|
add_header X-Content-Type-Options "nosniff" always;
|
|||
|
add_header X-Download-Options "noopen" always;
|
|||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|||
|
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
|||
|
add_header X-Robots-Tag "none" always;
|
|||
|
add_header X-XSS-Protection "1; mode=block" always;
|
|||
|
|
|||
|
# Remove X-Powered-By, which is an information leak
|
|||
|
fastcgi_hide_header X-Powered-By;
|
|||
|
|
|||
|
# 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;
|
|||
|
|
|||
|
# The following rule is only needed for the Social app.
|
|||
|
# Uncomment it if you're planning to use this app.
|
|||
|
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
|
|||
|
|
|||
|
location = /.well-known/carddav {
|
|||
|
return 301 $scheme://$host:$server_port/remote.php/dav;
|
|||
|
}
|
|||
|
location = /.well-known/caldav {
|
|||
|
return 301 $scheme://$host:$server_port/remote.php/dav;
|
|||
|
}
|
|||
|
|
|||
|
# Anything else is dynamically handled by Nextcloud
|
|||
|
location ^~ /.well-known { return 301 /index.php$uri; }
|
|||
|
|
|||
|
# 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;
|
|||
|
}
|
|||
|
|
|||
|
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\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/) {
|
|||
|
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
|
|||
|
set $path_info $fastcgi_path_info;
|
|||
|
try_files $fastcgi_script_name =404;
|
|||
|
include fastcgi_params;
|
|||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|||
|
fastcgi_param PATH_INFO $path_info;
|
|||
|
fastcgi_param HTTPS on;
|
|||
|
# Avoid sending the security headers twice
|
|||
|
fastcgi_param modHeadersAvailable true;
|
|||
|
# Enable pretty urls
|
|||
|
fastcgi_param front_controller_active true;
|
|||
|
fastcgi_pass php-handler;
|
|||
|
fastcgi_intercept_errors on;
|
|||
|
fastcgi_request_buffering off;
|
|||
|
}
|
|||
|
|
|||
|
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
|
|||
|
try_files $uri/ =404;
|
|||
|
index index.php;
|
|||
|
}
|
|||
|
|
|||
|
# Adding the cache control header for js, css and map files
|
|||
|
# Make sure it is BELOW the PHP block
|
|||
|
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
|
|||
|
try_files $uri /index.php$request_uri;
|
|||
|
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;" always;
|
|||
|
#
|
|||
|
# 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 Referrer-Policy "no-referrer" always;
|
|||
|
add_header X-Content-Type-Options "nosniff" always;
|
|||
|
add_header X-Download-Options "noopen" always;
|
|||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|||
|
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
|||
|
add_header X-Robots-Tag "none" always;
|
|||
|
add_header X-XSS-Protection "1; mode=block" always;
|
|||
|
|
|||
|
# Optional: Don't log access to assets
|
|||
|
access_log off;
|
|||
|
}
|
|||
|
|
|||
|
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
|
|||
|
try_files $uri /index.php$request_uri;
|
|||
|
# Optional: Don't log access to other assets
|
|||
|
access_log off;
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier et recharger nginx</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
|
|||
|
sudo systemctl reload nginx
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="paramétrage">Paramétrage</h3>
|
|||
|
|
|||
|
<p>Lancer <a href="https://cloud.xoyaz.xyz">https://cloud.xoyaz.xyz</a></p>
|
|||
|
|
|||
|
<p>Créer un compte administrateur et son mot de passe
|
|||
|
admin
|
|||
|
Saisir les informations sur la base , utilisateur et mot de passe <br />
|
|||
|
<img src="/images/nextcloud.rnmkcy.eu001.png" alt="" width="200" /> <img src="/images/nextcloud.rnmkcy.eu002.png" alt="" width="200" /> <img src="/images/nextcloud.rnmkcy.eu003.png" alt="" width="200" /></p>
|
|||
|
|
|||
|
<p class="error">Ne pas installer les applications recommandées<br />
|
|||
|
Ne pas tenir compte de l’erreur d’adressage <a href="https://apps/files/">https://apps/files/</a> à la fin de l’installation<br />
|
|||
|
Fermer l’onglet et réouvrir le lien <a href="https://cloud.xoyaz.xyz">https://cloud.xoyaz.xyz</a></p>
|
|||
|
|
|||
|
<p>Réinitialiser le mot de passe admin nextcloud</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u nextcloud php /var/www/nextcloud/occ user:resetpassword admin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="authentification-à-deux-facteurs">Authentification à deux facteurs</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/user_manual/fr/user_2fa.html">Utilisation de l’authentification à deux facteurs</a></li>
|
|||
|
<li><a href="https://www.aukfood.fr/securiser-son-compte-nextcloud-avec-le-2fa/">Sécuriser son compte Nextcloud avec le 2FA</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Cette activation de la double authentification passe par plusieurs étapes.<br />
|
|||
|
La première est d’installer une (ou plusieurs applications) permettant d’avoir un deuxième facteur d’authentification. Ces applications sont listées <a href="https://apps.nextcloud.com/categories/security">le magasin des applications Nextcloud catégorie Sécurité</a>. Il existe plusieurs applications, chacunes d’elles ayant une fonctionnalité précise.</p>
|
|||
|
|
|||
|
<p>Installer l’application <a href="https://apps.nextcloud.com/apps/twofactor_totp">TOTP two-factor provider</a> <br />
|
|||
|
<img src="/images/nextcloud.rnmkcy.eu006.png" alt="" width="600" /> <br />
|
|||
|
Ensuite se rendre dans Paramètres → Sécurité<br />
|
|||
|
<img src="/images/nextcloud.rnmkcy.eu005.png" alt="" width="600" /> <br />
|
|||
|
Il faut sauver les code de récupération TOTP<br />
|
|||
|
Paramétrer les applications TOTP avec le code ou QrCode<br />
|
|||
|
Vérifier pour valider le passage en authorisation à deux facteurs TOTP<br />
|
|||
|
Se reconnecter à l’application et après saisie login/Mot de passe , un code est exigé <br />
|
|||
|
<img src="/images/nextcloud.rnmkcy.eu008.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<h2 id="opérations-sur-nextcloud">Opérations sur nextcloud</h2>
|
|||
|
|
|||
|
<h3 id="optimisation">Optimisation</h3>
|
|||
|
|
|||
|
<p><img src="/images/nextcloud-secure.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p><strong>Votre installation n’a pas de préfixe de région par défaut.</strong> , ajouter <code class="language-plaintext highlighter-rouge">'default_phone_region' => 'FR',</code> dans le le fichier <code class="language-plaintext highlighter-rouge">/var/www/nextcloud/config/config.php</code> ou exécuter la commande suivante <br />
|
|||
|
Configuration de la région par défaut pour les numéros de téléphone</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -u nextcloud php /var/www/nextcloud/occ config:system:set default_phone_region --value="FR"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Cache de données : APCu & Redis</strong></p>
|
|||
|
|
|||
|
<p><em>APCu permet notamment de mettre en cache les variables PHP et de les stocker en mémoire vive. Redis est un système de gestion de base de données NoSQL avec un système de clef-valeur scalable (s’adapte à la charge). Une des principales caractéristiques de Redis est de conserver l’intégralité des données en RAM. Cela permet d’obtenir d’excellentes performances en évitant les accès disques, particulièrement coûteux.</em><br />
|
|||
|
<a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04">How To Install and Secure Redis on Ubuntu 18.04</a></p>
|
|||
|
|
|||
|
<p>Installez les paquets APCu et Redis :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install php8.0-apcu redis-server php8.0-redis
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ajoutez les lignes suivantes dans le fichier /var/www/nextcloud/config/config.php :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /var/www/nextcloud/config/config.php
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 'memcache.local' => '\OC\Memcache\APCu',
|
|||
|
'memcache.distributed' => '\OC\Memcache\Redis',
|
|||
|
'memcache.locking' => '\OC\Memcache\Redis',
|
|||
|
'redis' => [
|
|||
|
'host' => 'localhost',
|
|||
|
'port' => 6379,
|
|||
|
],
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La nouvelle configuration sera prise en compte après redémarrage du service PHP-FPM :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart php8.0-fpm.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si tout est bien paramétré , voici le message <br />
|
|||
|
<img src="/images/nextcloud.rnmkcy.eu004.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p><strong>Stockage externe</strong><br />
|
|||
|
<img src="/images/cloud_xoyaz_xyz07.png" alt="" width="600" /><br />
|
|||
|
<img src="/images/cloud_xoyaz_xyz08.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p><strong>Travaux cron</strong></p>
|
|||
|
|
|||
|
<p>Vous pouvez programmer des tâches cron de trois façons : en utilisant AJAX, Webcron ou cron. La méthode par défaut consiste à utiliser AJAX. Cependant, la méthode recommandée est d’utiliser cron.</p>
|
|||
|
|
|||
|
<p>Si systemd est installé sur le système, un timer systemd peut être une alternative à un cronjob.</p>
|
|||
|
|
|||
|
<p>Cette approche nécessite deux fichiers : <code class="language-plaintext highlighter-rouge">nextcloudcron.service</code> et <code class="language-plaintext highlighter-rouge">nextcloudcron.timer</code><br />
|
|||
|
Créez ces deux fichiers dans <code class="language-plaintext highlighter-rouge">/etc/systemd/system/</code></p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">/etc/systemd/system/nextcloudcron.service</code> doit ressembler à ceci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
|
|||
|
Description=Nextcloud cron.php job
|
|||
|
|
|||
|
[Service]
|
|||
|
User=nextcloud
|
|||
|
ExecStart=/usr/bin/php -f /var/www/nextcloud/cron.php
|
|||
|
KillMode=process
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Remplacez l’utilisateur <code class="language-plaintext highlighter-rouge">User</code> par l’utilisateur de votre serveur http (<strong>www-data</strong> si ce n’est pas <strong>nextcloud</strong>) et <code class="language-plaintext highlighter-rouge">/var/www/nextcloud/cron.php</code> par l’emplacement de cron.php dans votre répertoire nextcloud.</p>
|
|||
|
|
|||
|
<p>Le paramètre <code class="language-plaintext highlighter-rouge">KillMode=process</code> est nécessaire pour que les programmes externes qui sont lancés par la tâche cron continuent à fonctionner après la fin de la tâche cron.</p>
|
|||
|
|
|||
|
<p>Notez que le fichier <strong>.service</strong> unit n’a pas besoin d’une section <code class="language-plaintext highlighter-rouge">[Install]</code>. Veuillez vérifier votre installation car nous l’avons recommandé dans les versions précédentes de ce manuel d’administration.</p>
|
|||
|
|
|||
|
<p>Le fichier <code class="language-plaintext highlighter-rouge">/etc/systemd/system/nextcloudcron.timer</code> devrait ressembler à ceci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
|
|||
|
Description=Run Nextcloud cron.php every 5 minutes
|
|||
|
|
|||
|
[Timer]
|
|||
|
OnBootSec=5min
|
|||
|
OnUnitActiveSec=5min
|
|||
|
Unit=nextcloudcron.service
|
|||
|
|
|||
|
[Install]
|
|||
|
WantedBy=timers.target
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les parties importantes de l’unité de minuterie sont <strong>OnBootSec</strong> et <strong>OnUnitActiveSec</strong>. <strong>OnBootSec</strong> démarre la minuterie 5 minutes après le démarrage, sinon vous devriez la démarrer manuellement après chaque démarrage. <strong>OnUnitActiveSec</strong> déclenchera une minuterie de 5 minutes après la dernière activation de l’unité de service.</p>
|
|||
|
|
|||
|
<p>Maintenant, tout ce qui reste à faire est de démarrer et d’activer le minuteur en exécutant cette commande :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl enable --now nextcloudcron.timer
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lorsque l’option <code class="language-plaintext highlighter-rouge">--now</code> est utilisée avec enable, l’unité respective sera également démarrée.</p>
|
|||
|
|
|||
|
<p class="info">Note : Il n’est pas obligatoire de sélectionner l’option Cron dans le menu d’administration pour les travaux en arrière-plan, car une fois que cron.php est exécuté à partir de la ligne de commande ou du service cron, il sera automatiquement réglé sur Cron.<br />
|
|||
|
<img src="/images/cloud_xoyaz_xyz06.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p>Vérifier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl list-timers
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NEXT LEFT LAST PASSED UNIT ACTIVATES
|
|||
|
Thu 2021-09-23 21:59:15 CEST 3min 45s left Thu 2021-09-23 21:54:15 CEST 1min 14s ago nextcloudcron.timer nextcloudcron.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Nouveau mot de passe utilisateur en ligne de commande</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>php occ user:resetpassword NOM_UTILISATEUR
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Exemple, changer le mot de passe administrateur</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>php occ user:resetpassword admin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Base de données MariaDB</strong><br />
|
|||
|
Edition du fichier mysql.cnf</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>section mysqld</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[mysqld]
|
|||
|
innodb_buffer_pool_size=512M
|
|||
|
innodb_io_capacity=4000
|
|||
|
|
|||
|
|
|||
|
transaction_isolation = READ-COMMITTED
|
|||
|
binlog_format = ROW
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer MariaDB</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart mariadb.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Configuration de Redis</strong><br />
|
|||
|
Source : <a href="https://docs.nextcloud.com/server/19/admin_manual/configuration_server/caching_configuration.html">Documentation Nextcloud – Redis</a><br />
|
|||
|
Ajout de l’utilisateur nextcloud au groupe redis</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -a -G redis nextcloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Configuration du fichier <code class="language-plaintext highlighter-rouge">redis.conf</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
sed -i -e "s/^#* *port +*.*$/port 0/g" /etc/redis/redis.conf
|
|||
|
sed -i -e "s/^#* *unixsocket +*.*$/unixsocket \/var\/run\/redis\/redis-server.sock/g" /etc/redis/redis.conf
|
|||
|
sed -i -e "s/^#* *unixsocketperm+*.*$/unixsocketperm 770/g" /etc/redis/redis.conf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/redis/redis.conf | egrep "^#*port +|^#* *unixsocket +|^#* *unixsocketperm +"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>port 0
|
|||
|
unixsocket /var/run/redis/redis-server.sock
|
|||
|
unixsocketperm 770
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrage de Redis</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart redis-server.service
|
|||
|
ps ax | grep redis
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 8111 ? Ssl 0:00 /usr/bin/redis-server 127.0.0.1:0
|
|||
|
8120 pts/0 R+ 0:00 grep redis
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>File Locking et Memory Cache</strong><br />
|
|||
|
Source : <a href="https://docs.nextcloud.com/server/15/admin_manual/configuration_files/files_locking_transactional.html">File Locking</a> et <a href="https://docs.nextcloud.com/server/19/admin_manual/configuration_server/caching_configuration.html">Memory Caching</a></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
cd /var/www/nextcloud
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Configuration avec la commande occ:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Activation de filelocking
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set filelocking.enabled --value="true"
|
|||
|
|
|||
|
# Configuration du Redis
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set redis host --value="/var/run/redis/redis-server.sock"
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set redis port --value="0"
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set redis timeout --value="0.0"
|
|||
|
|
|||
|
# Configuration de memcache.distributed (à effectuer après la configuration de Redis)
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set memcache.distributed --value="\OC\Memcache\Redis"
|
|||
|
|
|||
|
# Configuration de memcache.local et memcache.locking
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set memcache.local --value="\OC\Memcache\APCu"
|
|||
|
sudo -u nextcloud php /var/www/nextcloud/occ config:system:set memcache.locking --value="\OC\Memcache\Redis"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>En cas d’erreur</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>An unhandled exception has been thrown:
|
|||
|
OC\HintException: [0]: Memcache \OC\Memcache\APCu not available for local cache (Is the matching PHP module installed and enabled?)
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Il faut ajouter <code class="language-plaintext highlighter-rouge">apc.enable_cli=1</code> au fichier <code class="language-plaintext highlighter-rouge">/etc/php/8.0/mods-available/apcu.ini</code> puis relancer le service</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>extension=apcu.so
|
|||
|
apc.enable_cli=1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrage nginx fpm :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart php8.0-fpm.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /var/www/nextcloud/config/config.php | egrep "'filelocking\.enabled|'memcache\.local|'memcache\.locking|'host|'port|'timeout|'memcache\.distributed"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 'filelocking.enabled' => 'true',
|
|||
|
'memcache.local' => '\\OC\\Memcache\\APCu',
|
|||
|
'memcache.distributed' => '\\OC\\Memcache\\Redis',
|
|||
|
'memcache.locking' => '\\OC\\Memcache\\Redis',
|
|||
|
'host' => '/var/run/redis/redis-server.sock',
|
|||
|
'port' => '0',
|
|||
|
'timeout' => '0.0',
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrage nginx fpm :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart php8.0-fpm.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Documentation</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_database/linux_database_configuration.html#configuring-a-mysql-or-mariadb-database">Configuring a MySQL or MariaDB database</a></li>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/server_tuning.html#enable-php-opcache">Enable PHP OPcache</a></li>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/caching_configuration.html">Memory Caching</a></li>
|
|||
|
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html">uploading big files > 512MB</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="mise-à-niveau-manuelle">Mise à niveau manuelle</h3>
|
|||
|
|
|||
|
<p>Commencez toujours par faire une nouvelle sauvegarde et désactivez toutes les applications tierces.</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Sauvegardez votre base de données Nextcloud Server existante, le répertoire de données et le fichier config.php. (Voir Sauvegarde, pour les informations de restauration voir Restauration de la sauvegarde)</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Téléchargez et décompressez la dernière version du serveur Nextcloud (fichier d’archive) depuis nextcloud.com/install/ dans un répertoire vide en dehors de votre installation actuelle.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Note
|
|||
|
Pour décompresser votre nouvelle archive, exécutez : unzip nextcloud-[version].zip ou tar -xjf nextcloud-[version].tar.bz2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Arrêtez votre serveur Web.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Si vous exécutez une tâche cron pour l’entretien de nextcloud, désactivez-la en commentant l’entrée dans le fichier crontab</p>
|
|||
|
|
|||
|
<p>crontab -u www-data -e</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(Mettez un # au début de la ligne correspondante).
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Renommez votre répertoire Nextcloud actuel, par exemple nextcloud-old.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>La décompression de la nouvelle archive crée un nouveau répertoire nextcloud peuplé de vos nouveaux fichiers de serveur. Déplacez ce répertoire et son contenu vers l’emplacement original de votre ancien serveur. Par exemple <code class="language-plaintext highlighter-rouge">/var/www/</code>, de sorte que vous ayez à nouveau <code class="language-plaintext highlighter-rouge">/var/www/nextcloud</code>.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Copiez le fichier <code class="language-plaintext highlighter-rouge">config/config.php</code> de votre ancien répertoire Nextcloud vers votre nouveau répertoire Nextcloud.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Si vous gardez votre répertoire <code class="language-plaintext highlighter-rouge">data/</code> dans votre répertoire <code class="language-plaintext highlighter-rouge">nextcloud/</code>, copiez-le de votre ancienne version de Nextcloud vers votre nouveau <code class="language-plaintext highlighter-rouge">nextcloud/</code>. Si vous le conservez en dehors de <code class="language-plaintext highlighter-rouge">nextcloud/</code>, vous n’avez rien à faire avec lui, car son emplacement est configuré dans votre config.php original, et aucune des étapes de mise à niveau ne le touche.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Si vous utilisez une application tierce, il se peut qu’elle ne soit pas toujours disponible dans votre instance Nextcloud mise à niveau/nouvelle. Pour vérifier cela, comparez une liste des applications dans le nouveau dossier <code class="language-plaintext highlighter-rouge">nextcloud/apps/</code> à une liste des applications dans votre ancien dossier <code class="language-plaintext highlighter-rouge">nextcloud/apps/</code> sauvegardé. Si vous trouvez des applications tierces dans l’ancien dossier qui doivent être dans la nouvelle instance/mise à niveau, copiez-les simplement et assurez-vous que les autorisations sont configurées comme indiqué ci-dessous.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Si vous utilisez un thème tiers, assurez-vous de le copier de votre répertoire <code class="language-plaintext highlighter-rouge">themes/</code> vers votre nouveau répertoire. Il est possible que vous ayez à le modifier après la mise à niveau.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Ajustez la propriété et les permissions des fichiers :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R www-data:www-data nextcloud
|
|||
|
find nextcloud/ -type d -exec chmod 750 {} \ ;
|
|||
|
find nextcloud/ -type f -exec chmod 640 {} \ ;
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Redémarrez votre serveur Web.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Maintenant, lancez la mise à niveau depuis la ligne de commande en utilisant occ, comme cet exemple sur Ubuntu Linux :</p>
|
|||
|
|
|||
|
<p>sudo -u www-data php occ upgrade</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>( !) cette commande DOIT être exécutée à partir du répertoire d'installation de nextcloud.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>L’opération de mise à niveau prend quelques minutes à quelques heures, en fonction de la taille de votre installation. Lorsqu’elle est terminée, vous verrez un message de réussite ou un message d’erreur qui vous indiquera où la mise à niveau a échoué.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Réactivez le cron-job nextcloud. (Voir l’étape 4 ci-dessus).</p>
|
|||
|
|
|||
|
<p>crontab -u www-data -e</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(Supprimez le # au début de la ligne correspondante dans le fichier crontab).
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Connectez-vous et jetez un coup d’oeil au bas de votre page d’administration pour vérifier le numéro de version. Vérifiez vos autres paramètres pour vous assurer qu’ils sont corrects. Allez sur la page Apps et vérifiez les applications principales pour vous assurer que les bonnes sont activées. Réactivez vos applications tierces.</p>
|
|||
|
|
|||
|
<h3 id="sauvegarde-de-nextcloud">Sauvegarde de Nextcloud</h3>
|
|||
|
|
|||
|
<p>Source : <a href="https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html">Nextcloud Backup</a></p>
|
|||
|
|
|||
|
<h4 id="création-des-répertoires-de-sauvegarde">Création des répertoires de sauvegarde</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Fichiers
|
|||
|
mkdir -p /backups/nextcloud/files
|
|||
|
# Base de données
|
|||
|
mkdir -p /backups/nextcloud/database
|
|||
|
# Permissions
|
|||
|
chmod -R o-rwx /backups/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="activation-mode-maintenance">Activation mode Maintenance</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Activation
|
|||
|
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --on
|
|||
|
# Vérification
|
|||
|
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="sauvegarde-des-fichiers">Sauvegarde des fichiers</h4>
|
|||
|
|
|||
|
<p>dans un répertoire /backups/nextcloud/</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Sauf répertoire data et corbeille
|
|||
|
rsync -Aavx /var/www/nextcloud/ \
|
|||
|
/backups/nextcloud/files/nextcloud-backup_`date +"%Y%m%d_%H%M%S"`/ \
|
|||
|
--exclude={'data/*','*/files_trashbin/files/*'}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le répertoire de sauvegarde sera /backups/nextcloud/files/nextcloud-backup_20201010_153025/ pour une sauvegarde effectuée le 10 Octobre 2020 à 15:30:25.</p>
|
|||
|
|
|||
|
<p>Important : Si vous souhaitez tout de même sauvegarder le répertoire data et la corbeille, il faudra supprimer le paramètre –exclude.</p>
|
|||
|
|
|||
|
<h4 id="sauvegarde-base-de-données-mysqlmariadb">Sauvegarde base de données MySQL/MariaDB</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysqldump --single-transaction -h localhost -u nextcloud -pVotreMotDePasse nextcloud > \
|
|||
|
/backups/nextcloud/database/nextcloud-sqlbkp_`date +"%Y%m%d_%H%M%S"`.bak
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>-h : nom ou IP du serveur de base de données<br />
|
|||
|
-u : utilisateur de la base de données<br />
|
|||
|
-p : mot de passe de l’utilisateur</p>
|
|||
|
|
|||
|
<p>Attention :</p>
|
|||
|
|
|||
|
<p>– Pas d’espace entre -p et le mot de passe
|
|||
|
– Remplacer VotreMotDePasse par le mot de passe de l’utilisateur.</p>
|
|||
|
|
|||
|
<h4 id="désactivation-mode-maintenance">Désactivation mode Maintenance</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Désactivation
|
|||
|
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="exemple-de-script-de-sauvegarde">Exemple de script de sauvegarde</h4>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
|
|||
|
<span class="c"># Path</span>
|
|||
|
<span class="nv">nextcloudPath</span><span class="o">=</span>/var/www/nextcloud/
|
|||
|
<span class="nv">occPath</span><span class="o">=</span><span class="nv">$nextcloudPath</span><span class="se">\o</span>cc
|
|||
|
<span class="nv">sourcePath</span><span class="o">=</span>/var/www/nextcloud/
|
|||
|
<span class="nv">mainDestinationPath</span><span class="o">=</span>/backups/nextcloud/<span class="sb">`</span><span class="nb">date</span> +<span class="s2">"%Y/%m"</span><span class="sb">`</span>/
|
|||
|
<span class="nv">filesDestinationPath</span><span class="o">=</span><span class="nv">$mainDestinationPath</span><span class="se">\f</span>iles/
|
|||
|
<span class="nv">databaseDestinationPath</span><span class="o">=</span><span class="nv">$mainDestinationPath</span><span class="se">\d</span>atabase/
|
|||
|
<span class="c"># Database</span>
|
|||
|
<span class="nv">dbhost</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> <span class="nv">$nextcloudPath</span><span class="se">\c</span>onfig/config.php | egrep <span class="s2">"dbhost"</span> | <span class="nb">sed</span> <span class="s1">'s/^.*\=> *'</span><span class="se">\'</span><span class="s1">'//'</span> | <span class="nb">sed</span> <span class="s1">'s/'</span><span class="se">\'</span><span class="s1">',.*$//'</span><span class="si">)</span>
|
|||
|
<span class="nv">dbname</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> <span class="nv">$nextcloudPath</span><span class="se">\c</span>onfig/config.php | egrep <span class="s2">"dbname"</span> | <span class="nb">sed</span> <span class="s1">'s/^.*\=> *'</span><span class="se">\'</span><span class="s1">'//'</span> | <span class="nb">sed</span> <span class="s1">'s/'</span><span class="se">\'</span><span class="s1">',.*$//'</span><span class="si">)</span>
|
|||
|
<span class="nv">dbuser</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> <span class="nv">$nextcloudPath</span><span class="se">\c</span>onfig/config.php | egrep <span class="s2">"dbuser"</span> | <span class="nb">sed</span> <span class="s1">'s/^.*\=> *'</span><span class="se">\'</span><span class="s1">'//'</span> | <span class="nb">sed</span> <span class="s1">'s/'</span><span class="se">\'</span><span class="s1">',.*$//'</span><span class="si">)</span>
|
|||
|
<span class="nv">dbpassword</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> <span class="nv">$nextcloudPath</span><span class="se">\c</span>onfig/config.php | egrep <span class="s2">"dbpassword"</span> | <span class="nb">sed</span> <span class="s1">'s/^.*\=> *'</span><span class="se">\'</span><span class="s1">'//'</span> | <span class="nb">sed</span> <span class="s1">'s/'</span><span class="se">\'</span><span class="s1">',.*$//'</span><span class="si">)</span>
|
|||
|
<span class="c"># Verbose</span>
|
|||
|
<span class="nv">cyan</span><span class="o">=</span><span class="s1">'\e[1;36m'</span>
|
|||
|
<span class="nv">white</span><span class="o">=</span><span class="s1">'\e[1;37m'</span>
|
|||
|
<span class="nv">neutral</span><span class="o">=</span><span class="s1">'\e[0;m'</span>
|
|||
|
<span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="k">${</span><span class="nv">cyan</span><span class="k">}</span><span class="s2">dbhost : </span><span class="k">${</span><span class="nv">white</span><span class="k">}</span><span class="nv">$dbhost</span><span class="k">${</span><span class="nv">neutral</span><span class="k">}</span><span class="s2">"</span>
|
|||
|
<span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="k">${</span><span class="nv">cyan</span><span class="k">}</span><span class="s2">dbname : </span><span class="k">${</span><span class="nv">white</span><span class="k">}</span><span class="nv">$dbname</span><span class="k">${</span><span class="nv">neutral</span><span class="k">}</span><span class="s2">"</span>
|
|||
|
<span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="k">${</span><span class="nv">cyan</span><span class="k">}</span><span class="s2">dbuser : </span><span class="k">${</span><span class="nv">white</span><span class="k">}</span><span class="nv">$dbuser</span><span class="k">${</span><span class="nv">neutral</span><span class="k">}</span><span class="s2">"</span>
|
|||
|
<span class="c">#echo -e "${cyan}dbpassword : ${white}$dbpassword${neutral}"</span>
|
|||
|
<span class="nb">read</span> <span class="nt">-t</span> 10 <span class="nt">-p</span> <span class="s2">"The backup will start after 10 seconds"</span> <span class="o">||</span> <span class="nb">true</span>
|
|||
|
<span class="c"># Destinations creation</span>
|
|||
|
<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="nv">$filesDestinationPath</span>
|
|||
|
<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="nv">$databaseDestinationPath</span>
|
|||
|
<span class="nb">chmod</span> <span class="nt">-R</span> o-rwx /backups/
|
|||
|
<span class="c"># Maintenance mode activation</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-u</span> www-data php <span class="nv">$occPath</span> maintenance:mode <span class="nt">--on</span>
|
|||
|
<span class="c"># Database backup</span>
|
|||
|
mysqldump <span class="nt">--single-transaction</span> <span class="nt">-h</span> <span class="nv">$dbhost</span> <span class="nt">-u</span> <span class="nv">$dbuser</span> <span class="nt">-p</span><span class="nv">$dbpassword</span> <span class="nv">$dbname</span> <span class="o">></span> <span class="nv">$databaseDestinationPath</span><span class="se">\n</span>extcloud-sqlbkp_<span class="sb">`</span><span class="nb">date</span> +<span class="s2">"%Y%m%d_%H%M%S"</span><span class="sb">`</span>.bak
|
|||
|
<span class="c"># Files backup</span>
|
|||
|
rsync <span class="nt">-Aavx</span> <span class="nv">$sourcePath</span> <span class="nv">$filesDestinationPath</span><span class="se">\n</span>extcloud-backup_<span class="sb">`</span><span class="nb">date</span> +<span class="s2">"%Y%m%d_%H%M%S"</span><span class="sb">`</span>/ <span class="nt">--exclude</span><span class="o">={</span><span class="s1">'data/*'</span>,<span class="s1">'*/files_trashbin/files/*'</span><span class="o">}</span>
|
|||
|
<span class="c">#rsync -Aavx $sourcePath $filesDestinationPath\nextcloud-backup_`date +"%Y%m%d_%H%M%S"`/</span>
|
|||
|
<span class="c"># Maintenance mode deactivation</span>
|
|||
|
<span class="nb">sudo</span> <span class="nt">-u</span> www-data php <span class="nv">$occPath</span> maintenance:mode <span class="nt">--off</span>
|
|||
|
<span class="nb">exit </span>0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Exemple de restauration : <a href="https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html?highlight=restore">Nextcloud – Restoring backup</a></p>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2021-09-18T00:00:00+02:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2021/09/14/HostMyServers-VPS-server85393-Debian-Buster-HDD-250Go.html">HostMyServers, server85393 Debian 10 (HDD 250Go) - hms.xoyaz.xyz</a></div><div class="next"><span>SUIVANT</span><a href="/2021/09/23/Debian-Python-3.html">Debian Python version 3 par défaut</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} {title}</a> (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>
|
|||
|
|