]>
Commit | Line | Data |
---|---|---|
1 | # Server configuration | |
2 | ||
3 | ||
4 | ||
5 | ## Requirements | |
6 | ||
7 | ### Operating system and web server | |
8 | ||
9 | Shaarli can be hosted on dedicated/virtual servers, or shared hosting. The smallest DigitalOcean VPS (Droplet with 1 CPU, 1 GiB RAM and 25 GiB SSD) costs about $5/month and will run any Shaarli installation without problems. | |
10 | ||
11 | You need write access to the Shaarli installation directory - you should have received instructions from your hosting provider on how to connect to the server using SSH (or FTP for shared hosts). | |
12 | ||
13 | Examples in this documentation are given for [Debian](https://www.debian.org/), a GNU/Linux distribution widely used in server environments. Please adapt them to your specific Linux distribution. | |
14 | ||
15 | ### Network and domain name | |
16 | ||
17 | Try to host the server in a region that is geographically close to your users. | |
18 | ||
19 | A **domain name** ([DNS record](https://opensource.com/article/17/4/introduction-domain-name-system-dns)) pointing to the server's public IP address is required to obtain a SSL/TLS certificate and setup HTTPS to secure client traffic to your Shaarli instance. | |
20 | ||
21 | You can obtain a domain name from a [registrar](https://en.wikipedia.org/wiki/Domain_name_registrar) ([1](https://www.ovh.co.uk/domains), [2](https://www.gandi.net/en/domain)), or from free subdomain providers ([1](https://freedns.afraid.org/)). If you don't have a domain name, please set up a private domain name ([FQDN](ttps://en.wikipedia.org/wiki/Fully_qualified_domain_name)) in your clients' [hosts files](https://en.wikipedia.org/wiki/Hosts_(file)) to access the server (direct access by IP address can result in unexpected behavior). | |
22 | ||
23 | Setup a **firewall** (using `iptables`, [ufw](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-debian-10), [fireHOL](https://firehol.org/) or any frontend of your choice) to deny all incoming traffic except `tcp/80` and `tcp/443`, which are needed to access the web server (and any other posrts you might need, like SSH). If the server is in a private network behind a NAT, ensure these **ports are forwarded** to the server. | |
24 | ||
25 | Shaarli makes outbound HTTP/HTTPS connections to websites you bookmark to fetch page information (title, thumbnails), the server must then have access to the Internet as well, and a working DNS resolver. | |
26 | ||
27 | ||
28 | ### PHP | |
29 | ||
30 | Supported PHP versions: | |
31 | ||
32 | Version | Status | Shaarli compatibility | |
33 | :---:|:---:|:---: | |
34 | 7.3 | Supported | Yes | |
35 | 7.2 | Supported | Yes | |
36 | 7.1 | Supported | Yes | |
37 | 7.0 | EOL: 2018-12-03 | Yes (up to Shaarli 0.10.x) | |
38 | 5.6 | EOL: 2018-12-31 | Yes (up to Shaarli 0.10.x) | |
39 | 5.5 | EOL: 2016-07-10 | Yes | |
40 | 5.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x) | |
41 | 5.3 | EOL: 2014-08-14 | Yes (up to Shaarli 0.8.x) | |
42 | ||
43 | Required PHP extensions: | |
44 | ||
45 | Extension | Required? | Usage | |
46 | ---|:---:|--- | |
47 | [`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS | |
48 | [`php-json`](http://php.net/manual/en/book.json.php) | required | configuration parsing | |
49 | [`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support | |
50 | [`php-gd`](http://php.net/manual/en/book.image.php) | optional | required to use thumbnails | |
51 | [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->รจ->f`) | |
52 | [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way | |
53 | [`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster) | |
54 | ||
55 | Some [plugins](Plugins.md) may require additional configuration. | |
56 | ||
57 | ||
58 | ## SSL/TLS (HTTPS) | |
59 | ||
60 | We recommend setting up [HTTPS](https://en.wikipedia.org/wiki/HTTPS) on your webserver for secure communication between clients and the server. | |
61 | ||
62 | For public-facing web servers this can be done using free SSL/TLS certificates from [Let's Encrypt](https://en.wikipedia.org/wiki/Let's_Encrypt), a non-profit certificate authority provididing free certificates. | |
63 | ||
64 | - [How to secure Apache with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-debian-10) | |
65 | - [How to secure Nginx with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-debian-10) | |
66 | - [How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates](https://www.digitalocean.com/community/tutorials/how-to-use-certbot-standalone-mode-to-retrieve-let-s-encrypt-ssl-certificates-on-debian-10). | |
67 | ||
68 | In short: | |
69 | ||
70 | ```bash | |
71 | # install certbot | |
72 | sudo apt install certbot | |
73 | ||
74 | # stop your webserver if you already have one running | |
75 | # certbot in standalone mode needs to bind to port 80 (only needed on initial generation) | |
76 | sudo systemctl stop apache2 | |
77 | sudo systemctl stop nginx | |
78 | ||
79 | # generate initial certificates - Let's Encrypt ACME servers must be able to access your server! | |
80 | sudo certbot certonly --standalone --noninteractive --agree-tos --email "admin@shaarli.mydomain.org" -d shaarli.mydomain.org | |
81 | # this will generate a private key and certificate at /etc/letsencrypt/live/shaarli.mydomain.org/{privkey,fullchain}.pem | |
82 | ||
83 | # restart the web server | |
84 | sudo systemctl start apache2 | |
85 | sudo systemctl start nginx | |
86 | ``` | |
87 | ||
88 | If you don't want to rely on a certificate authority, or the server can only be accessed from your own network, you can also generate self-signed certificates. Not that this will generate security warnings in web browsers/clients trying to access Shaarli: | |
89 | ||
90 | - [How To Create a Self-Signed SSL Certificate for Apache](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-on-debian-10) | |
91 | - [How To Create a Self-Signed SSL Certificate for Nginx](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-on-debian-10) | |
92 | ||
93 | -------------------------------------------------------------------------------- | |
94 | ||
95 | ## Examples | |
96 | ||
97 | The following examples assume a Debian-based operating system is installed. On other distributions you may have to adapt details such as package installation procedures, configuration file locations, and webserver username/group (`www-data` or `httpd` are common values). | |
98 | ||
99 | In these examples we assume the document root for your web server/virtualhost is at `/var/www/shaarli.mydomain.org/`: | |
100 | ||
101 | ```bash | |
102 | sudo mkdir -p /var/www/shaarli.mydomain.org/ | |
103 | ``` | |
104 | ||
105 | You can install Shaarli at the root of your virtualhost, or in a subdirectory as well. See [Directory structure](Directory-structure) | |
106 | ||
107 | ||
108 | ### Apache | |
109 | ||
110 | ```bash | |
111 | # Install apache + mod_php and PHP modules | |
112 | sudo apt update | |
113 | sudo apt install apache2 libapache2-mod-php php-json php-mbstring php-gd php-intl php-curl php-gettext | |
114 | ||
115 | # Edit the virtualhost configuration file with your favorite editor | |
116 | sudo nano /etc/apache2/sites-available/shaarli.mydomain.org.conf | |
117 | ``` | |
118 | ||
119 | ```apache | |
120 | <VirtualHost *:80> | |
121 | ServerName shaarli.mydomain.org | |
122 | DocumentRoot /var/www/shaarli.mydomain.org/ | |
123 | ||
124 | # Log level. Possible values include: debug, info, notice, warn, error, crit, alert, emerg. | |
125 | LogLevel warn | |
126 | # Log file locations | |
127 | ErrorLog /var/log/apache2/error.log | |
128 | CustomLog /var/log/apache2/access.log combined | |
129 | ||
130 | # Redirect HTTP requests to HTTPS | |
131 | RewriteEngine on | |
132 | RewriteRule ^.well-known/acme-challenge/ - [L] | |
133 | # except for Let's Encrypt ACME challenge requests | |
134 | RewriteCond %{HTTP_HOST} =shaarli.mydomain.org | |
135 | RewriteRule ^ https://shaarli.mydomain.org%{REQUEST_URI} [END,NE,R=permanent] | |
136 | </VirtualHost> | |
137 | ||
138 | <VirtualHost *:443> | |
139 | ServerName shaarli.mydomain.org | |
140 | DocumentRoot /var/www/shaarli.mydomain.org/ | |
141 | ||
142 | # Log level. Possible values include: debug, info, notice, warn, error, crit, alert, emerg. | |
143 | LogLevel warn | |
144 | # Log file locations | |
145 | ErrorLog /var/log/apache2/error.log | |
146 | CustomLog /var/log/apache2/access.log combined | |
147 | ||
148 | # SSL/TLS configuration (for Let's Encrypt certificates) | |
149 | SSLEngine on | |
150 | SSLCertificateFile /etc/letsencrypt/live/shaarli.mydomain.org/fullchain.pem | |
151 | SSLCertificateKeyFile /etc/letsencrypt/live/shaarli.mydomain.org/privkey.pem | |
152 | ||
153 | # Let's Encrypt settings from https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf | |
154 | SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 | |
155 | SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 | |
156 | SSLHonorCipherOrder off | |
157 | SSLSessionTickets off | |
158 | SSLOptions +StrictRequire | |
159 | ||
160 | # SSL/TLS configuration (for self-signed certificates) | |
161 | #SSLEngine on | |
162 | #SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem | |
163 | #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key | |
164 | ||
165 | # Optional, log PHP errors, useful for debugging | |
166 | #php_flag log_errors on | |
167 | #php_flag display_errors on | |
168 | #php_value error_reporting 2147483647 | |
169 | #php_value error_log /var/log/apache2/shaarli-php-error.log | |
170 | ||
171 | <Directory /var/www/shaarli.mydomain.org/> | |
172 | # Required for .htaccess support | |
173 | AllowOverride All | |
174 | Order allow,deny | |
175 | Allow from all | |
176 | </Directory> | |
177 | ||
178 | <LocationMatch "/\."> | |
179 | # Prevent accessing dotfiles | |
180 | RedirectMatch 404 ".*" | |
181 | </LocationMatch> | |
182 | ||
183 | <LocationMatch "\.(?:ico|css|js|gif|jpe?g|png)$"> | |
184 | # allow client-side caching of static files | |
185 | Header set Cache-Control "max-age=2628000, public, must-revalidate, proxy-revalidate" | |
186 | </LocationMatch> | |
187 | ||
188 | # serve the Shaarli favicon from its custom location | |
189 | Alias favicon.ico /var/www/shaarli.mydomain.org/images/favicon.ico | |
190 | ||
191 | </VirtualHost> | |
192 | ``` | |
193 | ||
194 | ```bash | |
195 | # Enable the virtualhost | |
196 | sudo a2ensite shaarli | |
197 | ||
198 | # mod_ssl must be enabled to use TLS/SSL certificates | |
199 | # https://httpd.apache.org/docs/current/mod/mod_ssl.html | |
200 | sudo a2enmod ssl | |
201 | ||
202 | # mod_rewrite must be enabled to use the REST API | |
203 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html | |
204 | sudo a2enmod rewrite | |
205 | ||
206 | # mod_version must only be enabled if you use Apache 2.2 or lower | |
207 | # https://httpd.apache.org/docs/current/mod/mod_version.html | |
208 | # sudo a2enmod version | |
209 | ||
210 | # restart the apache service | |
211 | systemctl restart apache | |
212 | ``` | |
213 | ||
214 | See [How to install the Apache web server](https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-debian-10) for a complete guide. | |
215 | ||
216 | ### Nginx | |
217 | ||
218 | Guide on setting up the Nginx web server: [How to install the Nginx web server](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-debian-10) | |
219 | ||
220 | You will also need to install the [PHP-FPM](http://php-fpm.org) interpreter as detailed [here](https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mariadb-php-lemp-stack-on-debian-10#step-3-%E2%80%94-installing-php-for-processing). Nginx and PHP-FPM must be running using the same user and group, here we assume the user/group to be `www-data:www-data` but this may vary depending on your Linux distribution. | |
221 | ||
222 | ||
223 | ```bash | |
224 | # install nginx and php-fpm | |
225 | sudo apt update | |
226 | sudo apt install nginx php-fpm | |
227 | ||
228 | # Edit the virtualhost configuration file with your favorite editor | |
229 | sudo nano /etc/nginx/sites-available/shaarli.mydomain.org | |
230 | ``` | |
231 | ||
232 | ```nginx | |
233 | server { | |
234 | listen 80; | |
235 | server_name shaarli.mydomain.org; | |
236 | ||
237 | # redirect all plain HTTP requests to HTTPS | |
238 | return 301 https://shaarli.mydomain.org$request_uri; | |
239 | } | |
240 | ||
241 | server { | |
242 | listen 443 ssl; | |
243 | server_name shaarli.mydomain.org; | |
244 | root /var/www/shaarli.mydomain.org; | |
245 | ||
246 | # log file locations | |
247 | # combined log format prepends the virtualhost/domain name to log entries | |
248 | access_log /var/log/nginx/access.log combined; | |
249 | error_log /var/log/nginx/error.log; | |
250 | ||
251 | # paths to private key and certificates for SSL/TLS | |
252 | ssl_certificate /etc/ssl/shaarli.mydomain.org.crt; | |
253 | ssl_certificate_key /etc/ssl/private/shaarli.mydomain.org.key; | |
254 | ||
255 | # increase the maximum file upload size if needed: by default nginx limits file upload to 1MB (413 Entity Too Large error) | |
256 | client_max_body_size 100m; | |
257 | ||
258 | # relative path to shaarli from the root of the webserver | |
259 | location / { | |
260 | # default index file when no file URI is requested | |
261 | index index.php; | |
262 | try_files $uri /index.php$is_args$args; | |
263 | } | |
264 | ||
265 | location ~ (index)\.php$ { | |
266 | try_files $uri =404; | |
267 | # slim API - split URL path into (script_filename, path_info) | |
268 | fastcgi_split_path_info ^(.+\.php)(/.+)$; | |
269 | # pass PHP requests to PHP-FPM | |
270 | fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; | |
271 | fastcgi_index index.php; | |
272 | include fastcgi.conf; | |
273 | } | |
274 | ||
275 | location ~ \.php$ { | |
276 | # deny access to all other PHP scripts | |
277 | # disable this if you host other PHP applications on the same virtualhost | |
278 | deny all; | |
279 | } | |
280 | ||
281 | location ~ /\. { | |
282 | # deny access to dotfiles | |
283 | deny all; | |
284 | } | |
285 | ||
286 | location ~ ~$ { | |
287 | # deny access to temp editor files, e.g. "script.php~" | |
288 | deny all; | |
289 | } | |
290 | ||
291 | location = /favicon.ico { | |
292 | # serve the Shaarli favicon from its custom location | |
293 | alias /var/www/shaarli/images/favicon.ico; | |
294 | } | |
295 | ||
296 | # allow client-side caching of static files | |
297 | location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { | |
298 | expires max; | |
299 | add_header Cache-Control "public, must-revalidate, proxy-revalidate"; | |
300 | # HTTP 1.0 compatibility | |
301 | add_header Pragma public; | |
302 | } | |
303 | ||
304 | } | |
305 | ``` | |
306 | ||
307 | ```bash | |
308 | # enable the configuration/virtualhost | |
309 | sudo ln -s /etc/nginx/sites-available/shaarli.mydomain.org /etc/nginx/sites-enabled/shaarli.mydomain.org | |
310 | # reload nginx configuration | |
311 | sudo systemctl reload nginx | |
312 | ``` | |
313 | ||
314 | ||
315 | ## Reverse proxies | |
316 | ||
317 | If Shaarli is hosted on a server behind a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) (i.e. there is a proxy server between clients and the web server hosting Shaarli), configure it accordingly. See [Reverse proxy](Reverse-proxy.md) configuration. | |
318 | ||
319 | ||
320 | ||
321 | ## Allow import of large browser bookmarks export | |
322 | ||
323 | Web browser bookmark exports can be large due to the presence of base64-encoded images and favicons/long subfolder names. Edit the PHP configuration file. | |
324 | ||
325 | - Apache: `/etc/php/<PHP_VERSION>/apache2/php.ini` | |
326 | - Nginx + PHP-FPM: `/etc/php/<PHP_VERSION>/fpm/php.ini` (in addition to `client_max_body_size` in the [Nginx configuration](#nginx)) | |
327 | ||
328 | ```ini | |
329 | [...] | |
330 | # (optional) increase the maximum file upload size: | |
331 | post_max_size = 100M | |
332 | [...] | |
333 | # (optional) increase the maximum file upload size: | |
334 | upload_max_filesize = 100M | |
335 | ``` | |
336 | ||
337 | To verify PHP settings currently set on the server, create a `phpinfo.php` in your webserver's document root | |
338 | ||
339 | ```bash | |
340 | # example | |
341 | echo '<?php phpinfo(); ?>' | sudo tee /var/www/shaarli.mydomain.org/phpinfo.php | |
342 | #give read-only access to this file to the webserver user | |
343 | sudo chown www-data:root /var/www/shaarli.mydomain.org/phpinfo.php | |
344 | sudo chmod 0400 /var/www/shaarli.mydomain.org/phpinfo.php | |
345 | ``` | |
346 | ||
347 | Access the file from a web browser (eg. <https://shaarli.mydomain.org/phpinfo.php> and look at the _Loaded Configuration File_ and _Scan this dir for additional .ini files_ entries | |
348 | ||
349 | It is recommended to remove the `phpinfo.php` when no longer needed as it publicly discloses details about your webserver configuration. | |
350 | ||
351 | ||
352 | ## Robots and crawlers | |
353 | ||
354 | To opt-out of indexing your Shaarli instance by search engines, create a `robots.txt` file at the root of your virtualhost: | |
355 | ||
356 | ``` | |
357 | User-agent: * | |
358 | Disallow: / | |
359 | ``` | |
360 | ||
361 | By default Shaarli already disallows indexing of your local copy of the documentation by default, using `<meta name="robots">` HTML tags. Your Shaarli instance may still be indexed by various robots on the public Internet, that do not respect this header or the robots standard. | |
362 | ||
363 | - [Robots exclusion standard](https://en.wikipedia.org/wiki/Robots_exclusion_standard) | |
364 | - [Introduction to robots.txt](https://support.google.com/webmasters/answer/6062608?hl=en) | |
365 | - [Robots meta tag, data-nosnippet, and X-Robots-Tag specifications](https://developers.google.com/search/reference/robots_meta_tag) | |
366 | - [About robots.txt](http://www.robotstxt.org) | |
367 | - [About the robots META tag](https://www.robotstxt.org/meta.html) | |
368 | ||
369 | ||
370 | ## Fail2ban | |
371 | ||
372 | [fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page) is an intrusion prevention framework that reads server (Apache, SSH, etc.) and uses `iptables` profiles to block brute-force attempts. You need to create a filter to detect shaarli login failures in logs, and a jail configuation to configure the behavior when failed login attempts are detected: | |
373 | ||
374 | ```ini | |
375 | # /etc/fail2ban/filter.d/shaarli-auth.conf | |
376 | [INCLUDES] | |
377 | before = common.conf | |
378 | [Definition] | |
379 | failregex = \s-\s<HOST>\s-\sLogin failed for user.*$ | |
380 | ignoreregex = | |
381 | ``` | |
382 | ||
383 | ```ini | |
384 | # /etc/fail2ban/jail.local | |
385 | [shaarli-auth] | |
386 | enabled = true | |
387 | port = https,http | |
388 | filter = shaarli-auth | |
389 | logpath = /var/www/shaarli.mydomain.org/data/log.txt | |
390 | # allow 3 login attempts per IP address | |
391 | # (over a period specified by findtime = in /etc/fail2ban/jail.conf) | |
392 | maxretry = 3 | |
393 | # permanently ban the IP address after reaching the limit | |
394 | bantime = -1 | |
395 | ``` | |
396 | ||
397 | #### References | |
398 | ||
399 | - [Apache/PHP - error log per VirtualHost - StackOverflow](http://stackoverflow.com/q/176) | |
400 | - [Apache - PHP: php_value vs php_admin_value and the use of php_flag explained](https://ma.ttias.be/php-php_value-vs-php_admin_value-and-the-use-of-php_flag-explained/) | |
401 | - [Server-side TLS (Apache) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#Apache) | |
402 | - [Nginx Beginner's guide](http://nginx.org/en/docs/beginners_guide.html) | |
403 | - [Nginx ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) | |
404 | - [Nginx Pitfalls](http://wiki.nginx.org/Pitfalls) | |
405 | - [Nginx PHP configuration examples - Karl Blessing](http://kbeezie.com/nginx-configuration-examples/) | |
406 | - [Apache 2.4 documentation](https://httpd.apache.org/docs/2.4/) | |
407 | - [Apache mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html) | |
408 | - [Apache Reverse Proxy Request Headers](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#x-headers) | |
409 | - [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/) | |
410 | - [Nginx documentation](https://nginx.org/en/docs/) | |
411 | - [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) | |
412 | - [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) | |
413 | - [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) | |
414 | - [Server-side TLS (Nginx) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) | |
415 | - [How to Create Self-Signed SSL Certificates with OpenSSL](http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php) | |
416 | - [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority) | |
417 | - [Travis configuration](https://github.com/shaarli/Shaarli/blob/master/.travis.yml) | |
418 | - [PHP: Supported versions](http://php.net/supported-versions.php) | |
419 | - [PHP: Unsupported versions (EOL/End-of-life)](http://php.net/eol.php) | |
420 | - [PHP 7 Changelog](http://php.net/ChangeLog-7.php) | |
421 | - [PHP 5 Changelog](http://php.net/ChangeLog-5.php) | |
422 | - [PHP: Bugs](https://bugs.php.net/) | |
423 | - [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) | |
424 | - Hosting providers: [DigitalOcean](https://www.digitalocean.com/) ([1](https://www.digitalocean.com/docs/droplets/overview/), [2](https://www.digitalocean.com/pricing/), [3](https://www.digitalocean.com/docs/droplets/how-to/create/), [How to Add SSH Keys to Droplets](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/), [4](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-debian-8), [5](https://www.digitalocean.com/community/tutorials/an-introduction-to-securing-your-linux-vps)), [Gandi](https://www.gandi.net/en), [OVH](https://www.ovh.co.uk/), [RackSpace](https://www.rackspace.com/), etc. | |
425 | ||
426 |