├── .gitignore ├── .vimrc ├── README.md └── nginx ├── basic.conf └── with-ssl.conf /.gitignore: -------------------------------------------------------------------------------- 1 | NOTES.md -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | " Don't try to be vi compatible 2 | set nocompatible 3 | 4 | " Turn on syntax highlighting 5 | syntax on 6 | 7 | " Show line numbers 8 | set number 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 1. SSH onto the droplet 2 | ssh root@[ip of the droplet] 3 | 4 | ## 2. Upgrade the new instance 5 | Since most new instances are created from an image, the software in the image is likely behind so the first thing to do is to update it all. 6 | `$ apt-get update` 7 | 8 | `$ apt-get upgrade` (confirm if asked) 9 | 10 | ## 3. Create swap 11 | This step is important so that if any of our programs runs out of memory, it can use swap. Not creating it might lead to all kinds of problems with system instability. Although [DigitalOcean tutorials](https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04) recommends _not_ using swap on SSD, it is still useful as a protection. It should be always empty, so if it is not, strongly consider increasing the Droplet size. 12 | 13 | ``` 14 | $ fallocate -l 1G /swapfile 15 | $ chmod 0600 /swapfile 16 | $ mkswap /swapfile 17 | $ swapon /swapfile 18 | $ echo "/swapfile none swap sw 0 0" >> /etc/fstab 19 | $ cat /proc/meminfo 20 | ``` 21 | (last command optional, to see whether swap is active) 22 | 23 | ## 4. Install basic components the system will need 24 | `$ apt-get install -y git zsh curl apt-transport-https` 25 | 26 | ## 5. Install Oh-my-zsh (optional step) 27 | Oh-my-zsh (and z-shell in general) come with a few niceties that Bash doesn't provide. 28 | `$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"` 29 | 30 | `$ vim ~/.zshrc` and change the `theme` line to what you want, _blinks_ is nice. 31 | Reload the shell: 32 | `$ source ~/.zshrc` 33 | 34 | If you want a nicer Vim experience, copy `.vimrc` in this repo to the root's home directory. 35 | 36 | ## 6. Install Nginx 37 | First, let's check what version is the latest in the _apt_ repository: 38 | `$ apt-cache show nginx` (it is most likely behind) 39 | Visit [http://nginx.org/en/linux_packages.html](Nginx repositories page) to see how to add the repository to our apt. 40 | 41 | ``` 42 | $ cat /etc/*-release 43 | $ echo "deb https://nginx.org/packages/debian/ stretch nginx" > \ 44 | /etc/apt/sources.list.d/nginx.list 45 | $ curl -vs https://nginx.org/keys/nginx_signing.key | apt-key add - 46 | $ apt-get update && apt-get install -y nginx 47 | $ service nginx start 48 | $ ifconfig 49 | ``` 50 | The last command will give you the ip for the interface _eth0_ 51 | Open it in browser, and voila! 52 | 53 | ## 7. Install PHP 54 | Just like with Nginx, we need to create two files: the _apt_ source file, which points to the repository and key file, which is used to verify the integrity of the repository: 55 | 56 | ``` 57 | $ echo "deb https://packages.sury.org/php/ stretch main" > \ 58 | /etc/apt/sources.list.d/php.list 59 | $ curl -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg 60 | ``` 61 | 62 | ``` 63 | Now we can install PHP and all the dependencies WordPress needs to run: 64 | $ apt-get update && apt-get install -y \ 65 | imagemagick \ 66 | php7.1-fpm php7.1-mysqli php7.1-curl php7.1-gd php7.1-geoip php7.1-xml \ 67 | php7.1-xmlrpc php7.1-imagick php7.1-mbstring php7.1-ssh2 php7.1-redis 68 | ``` 69 | 70 | ## 8. Update Nginx to work with PHP 71 | First, edit the default configuration: 72 | `$ vim /etc/nginx/nginx.conf` 73 | 74 | Here, change `user www-data;` and `worker_processes auto;` 75 | 76 | `$ vim /etc/nginx/conf.d/default.conf` 77 | 78 | Here, change `server_name _;`, then in `location /` block, add `index.php` so that the PHP files are read by Nginx. Then uncomment the `location ~ \.php$` block and change `fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;` 79 | 80 | Also, in this block, change the `root /usr/share/nginx/html`. 81 | 82 | First check whether Nginx configuration is in order, then reload it: 83 | ``` 84 | $ service nginx configtest 85 | $ service nginx reload 86 | ``` 87 | 88 | To test whether PHP works, make an `index.php` in `/usr/share/nginx/html` 89 | 90 | And run the following command to put `phpinfo()` into it: 91 | `$ echo "> /usr/share/nginx/html/index.php` 92 | 93 | Visit the IP in the browser, only to encounter an error. 94 | 95 | `$ cat /var/log/nginx/error.log` to see what the error is. Expectedly, it can't connect to PHP-FPM, so we need to configure it properly. 96 | 97 | ``` 98 | $ cd /etc/php/7.1/fpm 99 | $ grep -r "listen" . 100 | $ vim ./pool.d/www.conf 101 | ``` 102 | 103 | Around line 36, there should be a `listen` directive, which we need to replace with `listen = [::]:9000`. 104 | 105 | Now reload PHP-FPM: `$ service php7.1-fpm reload` 106 | 107 | Visit your browser again, and the `phpinfo();` should be revealed. 108 | Afterwards, **remove it!!!** 109 | 110 | ## 9. Set up outgoing emails 111 | Make sure exim4 is installed: 112 | `$ apt-get install -y exim4` 113 | 114 | Now, you need to set up an account with one of the mail providers, such as SendGrid, Mailgun or Mandrill. What you need is an API key. 115 | 116 | `$ vim /etc/exim4/passwd.client` and put it in in the format shown in the file 117 | 118 | `$ vim /etc/exim4/update-exim4.conf.conf` and put the following snippet in (your configuration for _dc_smarthost_ might be different, depending on the provider): 119 | 120 | ``` 121 | dc_eximconfig_configtype='smarthost' 122 | dc_other_hostnames='' 123 | dc_local_interfaces='127.0.0.1' 124 | dc_readhost='example.com' 125 | dc_relay_domains='' 126 | dc_minimaldns='false' 127 | dc_relay_nets='' 128 | dc_smarthost='smtp.sendgrid.net::2525' 129 | CFILEMODE='644' 130 | dc_use_split_config='false' 131 | dc_hide_mailname='true' 132 | dc_mailname_in_oh='true' 133 | ``` 134 | 135 | `$ /usr/sbin/update-exim4.conf` to update EXIM4 configuration 136 | 137 | To test whether it's working correctly, run 138 | `$ echo "This is message body" | mail -s "This is Subject" your-email@example.com` 139 | 140 | ## 10. Set up Redis 141 | `$ apt-get install -y redis-server` 142 | This will install the default Redis from the Debian repository, which usually doesn't have the latest version, so alternatively, you might want to visit [DigitalOcean's Redis tutorial](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-redis-on-ubuntu-16-04) and follow it. 143 | 144 | ## 11. Set up MySQL 145 | Install Percona MySQL as per instructions on [their page](https://www.percona.com/doc/percona-server/LATEST/installation/apt_repo.html) 146 | 147 | ``` 148 | $ wget https://repo.percona.com/apt/percona-release_0.1-4.$(lsb_release -sc)_all.deb 149 | $ dpkg -i percona-release_0.1-4.$(lsb_release -sc)_all.deb 150 | $ cat /etc/apt/sources.list.d/percona-release.list 151 | $ apt-get update 152 | $ apt-get install -y percona-server-server-5.7 153 | Choose a secure password! 154 | $ service mysql status to verify our MySQL server is up and running 155 | $ mysql -u root mysql -p 156 | Inside MySQL command line, create the database and a corresponding user: 157 | > CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 158 | > GRANT ALL ON wordpress.* TO wordpress_user@'%' IDENTIFIED BY 'wordpress'; 159 | > exit; 160 | ``` 161 | 162 | With all the dependencies installed and configured, it's time to... 163 | 164 | ## 12. Install WordPress 165 | First create a directory that will hold the WordPress core for your domain: 166 | `$ mkdir -p /var/www/example.com` (change with your domain) 167 | 168 | Then, navigate to the [Release archive](https://wordpress.org/download/release-archive/) and right click latest _tar.gz_ and choose _copy link address_. 169 | 170 | ``` 171 | $ cd /var/www/example.com 172 | $ wget https://wordpress.org/wordpress-4.8.1.tar.gz 173 | $ tar -zxf wordpress-4.8.1.tar.gz 174 | $ mv wordpress/* . 175 | $ rm -rf wordpress wordpress-4.8.1.tar.gz 176 | ``` 177 | 178 | Add a user which will be the owner of WordPress files 179 | `$ adduser --ingroup www-data webmaster` 180 | 181 | Visit the [WordPress Codex](https://codex.wordpress.org/Hardening_WordPress) to check recommended permissions on directories and files 182 | ``` 183 | $ find . -type d -exec chmod 755 {} \; 184 | $ find . -type f -exec chmod 644 {} \; 185 | $ cp wp-config-sample.php wp-config.php 186 | $ chmod 660 wp-config.php 187 | $ chown -R webmaster:www-data . 188 | ``` 189 | 190 | Next, disable cron: 191 | ``` 192 | $ su webmaster 193 | $ crontab -e 194 | ``` 195 | 196 | and put the following code at the end of the file: 197 | 198 | `*/15 * * * * cd /var/www/example.com; php wp-cron.php > /dev/null 2>&1` 199 | 200 | Save and close the file, then: 201 | 202 | `$ exit` to return back to _root_ 203 | `$ vim wp-config.php` to add `define('DISABLE_WP_CRON', true);` and configure database credentials and [salts](https://api.wordpress.org/secret-key/1.1/salt/) 204 | 205 | Next, configure, Nginx to serve WordPress correctly, on our chosen domain 206 | ``` 207 | $ cd /etc/nginx/conf.d 208 | $ vim example.com.conf 209 | ``` 210 | (virtual hosts need `.conf` extension to be loaded) 211 | 212 | Paste the the contents of the [basic Nginx config](nginx/basic.conf) into this file, changes lines [2](nginx/basic.conf#L2) and [7](nginx/basic.conf#L7) to reflect your own domain and reload Nginx: 213 | `$ service nginx reload` 214 | 215 | Visit the domain in your browser to start the WordPress wizard. 216 | Create a new account and log into WordPress to start installing. 217 | 218 | Visit the plugins page and search for "redis cache" and try to install "Redis Object Cache". It will fail, so we need to configure access. 219 | 220 | In console/terminal, do the following: 221 | 222 | ``` 223 | $ su webmaster 224 | $ cd 225 | $ ssh-keygen -t rsa -b 4096 (name it wp_rsa) 226 | $ chmod 0640 wp_rsa* 227 | $ mkdir .ssh 228 | $ cp wp_rsa.pub .ssh/authorized_keys 229 | $ chmod 0644 .ssh/authorized_keys 230 | ``` 231 | 232 | `$ vim .ssh/authorized_keys` and prepend `from="127.0.0.1"` 233 | 234 | Finally: 235 | ``` 236 | $ chmod 0700 .ssh 237 | $ exit 238 | ``` 239 | 240 | Next, add the following lines to `wp-config.php`: 241 | 242 | ``` 243 | define('FTP_PUBKEY','/home/webmaster/wp_rsa.pub'); 244 | define('FTP_PRIKEY','/home/webmaster/wp_rsa'); 245 | define('FTP_USER','webmaster'); 246 | define('FTP_PASS',''); 247 | define('FTP_HOST','127.0.0.1:22'); 248 | define('FS_METHOD', 'ssh2'); 249 | ``` 250 | 251 | Now go back to WordPress and install "Redis Object Cache", and activate it. 252 | 253 | --- 254 | 255 | Before continuing, create a `dhparam.pem` file, which will be needed at a later stage, but it takes a while to complete, so we might as well do it now: 256 | First, create a new _screen_: 257 | 258 | ``` 259 | $ screen -R dhparam 260 | $ cd /etc/nginx 261 | $ openssl dhparam -out dhparam.pem 4096 262 | ``` 263 | 264 | then and press CTRL+A+D to move this screen into background, while we continue with optimizing WordPress. 265 | To check screen: 266 | 267 | ``` 268 | $ screen -ls 269 | $ screen -r dhparam // to go back to the screen 270 | $ exit 271 | ``` 272 | --- 273 | 274 | Next, create the uploads directory: 275 | 276 | ``` 277 | $ cd /var/www/example.com/wp-content 278 | $ mkdir uploads 279 | $ chown webmaster:www-data uploads 280 | $ chmod -R 775 ./uploads 281 | ``` 282 | 283 | Now it's time to install WP-Rocket, one of the best caching plugins on the market. Navigate to [WP-Rocket](https://wp-rocket.me/), make an account, buy the plugin and download it. When you try to install it by uploading the file to WordPress, you will most likely get an error `413 Request Entity Too Large`, so fix that next. Go back to the terminal and run the following commands: 284 | 285 | `$ vim /etc/php/7.1/fpm/php.ini` and locate the following three directives and set them to whatever you want your max upload size to be: 286 | ``` 287 | upload_max_filesize = 20M 288 | post_max_size = 20M 289 | memory_limit = 256M 290 | ``` 291 | (the last is not for uploads, but let's increase it while we're at it) 292 | 293 | Reload PHP-FPM with `$ service php7.1-fpm reload` and return to WordPress to try installing WP-Rocket again. Upon activation it will complain about a couple of files not being in place and it's unable to write to them, due to our limited permissions. That's why we need to manually create those files. 294 | 295 | Run these: 296 | 297 | ``` 298 | $ cd /var/www/example.com/wp-content 299 | $ vim advanced-cache.php // paste the WP-Rocket config in 300 | $ mkdir -p wp-rocket-config cache/wp-rocket cache/min cache/busting 301 | $ chown -R webmaster:www-data wp-rocket-config cache/wp-rocket cache/min cache/busting 302 | $ chmod -R g+w wp-rocket-config cache/wp-rocket cache/min cache/busting 303 | ``` 304 | 305 | Reload WP-Rocket config page, and the errors should go away. Open a new incognito browser with your website and inspect the source of the page to verify WP-Rocket it installed (there should be a comment at the very bottom). 306 | 307 | ## 13. Advanced Nginx + WP-Rocket configuration 308 | 309 | We could have stopped here, and would still have a pretty fast WordPress website, but let's go the extra mile. 310 | 311 | We will use [this repository](https://github.com/maximejobin/rocket-nginx) to help us configure our Nginx. Let's follow its instructions: 312 | 313 | ``` 314 | $ cd /etc/nginx 315 | $ git clone https://github.com/maximejobin/rocket-nginx.git 316 | $ cd rocket-nginx 317 | $ vim rocket-nginx.ini 318 | $ vim ../conf.d/example.com.conf // (replace with your domain) 319 | Add include rocket-nginx/default.conf; in the server block 320 | $ service nginx configtest 321 | $ service nginx reload 322 | ``` 323 | 324 | If you want to test that it's indeed working, edit `rocket-nginx.ini` and turn debug on (on line 13). 325 | 326 | ## 14. Set up HTTPS 327 | 328 | We will use Letsencrypt, so we need an _acme_ client, for which we will use [Dehydrated](https://github.com/lukas2511/dehydrated). 329 | 330 | ``` 331 | $ mkdir -p /var/www/acme-challenge/ /etc/dehydrated 332 | $ cd /usr/src 333 | $ git clone https://github.com/lukas2511/dehydrated 334 | $ cd dehydrated 335 | ``` 336 | 337 | Now we need to check what our $PATH directories are (so we don't need to call the full path every time) 338 | 339 | ``` 340 | echo $PATH 341 | $ ln -s /usr/src/dehydrated/dehydrated /usr/local/bin/dehydrated 342 | ``` 343 | 344 | Copy all the needed files into the proper location (`/etc/`): 345 | ``` 346 | $ cd ./docs/examples 347 | $ cp * /etc/dehydrated 348 | $ cd /etc/dehydrated 349 | 350 | $ vim hook.sh // line 55: service nginx reload 351 | $ vim domains.txt // line 1: your-domain.com 352 | $ vim config 353 | ``` 354 | 355 | Visit the [staging documentation](https://letsencrypt.org/docs/staging-environment/) to first try out our certificate registration process there. 356 | 357 | Fill out the relevant lines like this: 358 | 359 | ``` 360 | 20: CA="https://acme-staging.api.letsencrypt.org/directory" 361 | 23: CA_TERMS="https://acme-staging.api.letsencrypt.org/terms" 362 | 50: WELLKNOWN="/var/www/acme-challenge" 363 | 92: CONTACT_EMAIL="your-email@example.com" 364 | ``` 365 | 366 | Now try the registration: 367 | 368 | `$ dehydrated` and then `$ dehydrated -c`, which will return a warning to accept the terms: 369 | 370 | `$ dehydrated --register --accept-terms` 371 | 372 | `$ dehydrated -c` which will now succeed, so it's time to switch to production values. Open `/etc/dehydrated/config` and replace the staging URLs with production ones. Then run: 373 | 374 | `$ dehydrated --register --accept-terms` 375 | 376 | `$ dehydrated -c -x` (`-x` means _force_ because we have our staging certificates in place, and they need to be overriden. You only have to do this once). 377 | 378 | Finally, configure cron to run the certificate renewal script once a week: 379 | `$ crontab -e` (as root!) 380 | 381 | Put the following at the end of the file: 382 | `0 0 * * 0 /usr/local/bin/dehydrated -c` 383 | 384 | Now with our certificates in place, replace the `example.com.conf` with `with-ssl.conf` and modify the values to reflect your domain, enable `rocket-nginx` and restart Nginx: 385 | `$ service nginx reload` 386 | 387 | (If you want different SSL/TLS configuration, Mozilla has [a wizard](https://mozilla.github.io/server-side-tls/ssl-config-generator/) to generate it for you) 388 | 389 | Finally, go to WordPress dashboard, general settings, and fix the domains to use HTTPS, rather than just HTTP. 390 | 391 | All done! -------------------------------------------------------------------------------- /nginx/basic.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name example.com; 3 | 4 | listen 80; 5 | listen [::]:80; 6 | 7 | root /var/www/example.com; 8 | index index.php index.html; 9 | 10 | error_page 500 502 503 504 /50x.html; 11 | location = /50x.html { 12 | root /usr/share/nginx/html; 13 | } 14 | 15 | client_max_body_size 20M; 16 | 17 | location ~* ^/wp-content/uploads/.*\.php$ { 18 | return 403; 19 | } 20 | 21 | location = /favicon.ico { 22 | log_not_found off; 23 | access_log off; 24 | } 25 | 26 | location = /robots.txt { 27 | allow all; 28 | log_not_found off; 29 | access_log off; 30 | } 31 | 32 | # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac). 33 | # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) 34 | location ~ /\. { 35 | deny all; 36 | } 37 | 38 | # Deny access to any files with a .php extension in the uploads directory 39 | # Works in sub-directory installs and also in multisite network 40 | # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) 41 | location ~* /(?:uploads|files)/.*\.php$ { 42 | deny all; 43 | } 44 | 45 | # Prettier sitemap URLs 46 | rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last; 47 | rewrite ^/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last; 48 | 49 | # Rocket-Nginx configuration 50 | # Uncomment once you have Rocket-Nginx installed and configured 51 | # include rocket-nginx/default.conf; 52 | 53 | # Prepared for Letsencrypt challenge 54 | location ^~ /.well-known/acme-challenge/ { 55 | alias /var/www/acme-challenge/; 56 | } 57 | 58 | ############################################################################# 59 | # Gzip 60 | 61 | gzip on; 62 | gzip_buffers 16 8k; 63 | gzip_comp_level 9; 64 | gzip_http_version 1.0; 65 | gzip_min_length 0; 66 | gzip_types text/plain text/css image/x-icon image/svg+xml image/png image/jpg image/jpeg text/js text/php application/javascript application/x-javascript; 67 | gzip_vary on; 68 | gzip_proxied expired no-cache no-store private auth; 69 | gzip_disable "MSIE [1-6]\."; 70 | 71 | ############################################################################# 72 | # Location blocks 73 | location / { 74 | try_files $uri $uri/ /index.php?$args; 75 | } 76 | 77 | location ~ \.php$ { 78 | fastcgi_pass 127.0.0.1:9000; 79 | fastcgi_index index.php; 80 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 81 | include fastcgi_params; 82 | 83 | add_header X-XSS-Protection "1; mode=block"; 84 | add_header X-Content-Type-Options nosniff; 85 | add_header X-Frame-Options SAMEORIGIN; 86 | } 87 | 88 | location ~* \.(?:rss|atom)$ { 89 | expires 1h; 90 | add_header Cache-Control "public"; 91 | } 92 | 93 | location ~* \.(eot|ttf|woff|woff2)$ { 94 | expires 1M; 95 | add_header Access-Control-Allow-Origin *; 96 | } 97 | 98 | location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { 99 | expires 1M; 100 | access_log off; 101 | add_header Cache-Control "public"; 102 | } 103 | 104 | location ~* \.(?:css|js)$ { 105 | expires max; 106 | access_log off; 107 | add_header Cache-Control "public"; 108 | } 109 | } -------------------------------------------------------------------------------- /nginx/with-ssl.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name example.com; 3 | 4 | listen 80; 5 | listen [::]:80; 6 | 7 | location / { 8 | return 301 https://$host$request_uri; 9 | } 10 | 11 | location ^~ /.well-known/acme-challenge/ { 12 | alias /var/www/acme-challenge/; 13 | } 14 | } 15 | 16 | server { 17 | server_name example.com; 18 | 19 | listen 443 ssl http2; 20 | listen [::]:443 ssl http2; 21 | 22 | root /var/www/example.com; 23 | index index.php index.html; 24 | 25 | error_page 500 502 503 504 /50x.html; 26 | location = /50x.html { 27 | root /usr/share/nginx/html; 28 | } 29 | 30 | client_max_body_size 20M; 31 | 32 | location ~* ^/wp-content/uploads/.*\.php$ { 33 | return 403; 34 | } 35 | 36 | location = /favicon.ico { 37 | log_not_found off; 38 | access_log off; 39 | } 40 | 41 | location = /robots.txt { 42 | allow all; 43 | log_not_found off; 44 | access_log off; 45 | } 46 | 47 | # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac). 48 | # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) 49 | location ~ /\. { 50 | deny all; 51 | } 52 | 53 | # Deny access to any files with a .php extension in the uploads directory 54 | # Works in sub-directory installs and also in multisite network 55 | # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) 56 | location ~* /(?:uploads|files)/.*\.php$ { 57 | deny all; 58 | } 59 | 60 | # Prettier sitemap URLs 61 | rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last; 62 | rewrite ^/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last; 63 | 64 | # Rocket-Nginx configuration, uncomment if you use it 65 | # include rocket-nginx/default.conf; 66 | 67 | ############################################################################# 68 | # SSL configuration 69 | 70 | ssl_certificate /etc/dehydrated/certs/example.com/fullchain.pem; 71 | ssl_certificate_key /etc/dehydrated/certs/example.com/privkey.pem; 72 | ssl_trusted_certificate /etc/dehydrated/certs/example.com/chain.pem; 73 | ssl_session_timeout 1d; 74 | ssl_session_cache shared:SSL:50m; 75 | ssl_session_tickets off; 76 | 77 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 78 | ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; 79 | ssl_prefer_server_ciphers on; 80 | 81 | ssl_stapling on; 82 | ssl_stapling_verify on; 83 | ssl_dhparam /etc/nginx/dhparam.pem; 84 | resolver 8.8.8.8 8.8.4.4; 85 | 86 | ############################################################################# 87 | # Gzip 88 | 89 | gzip on; 90 | gzip_buffers 16 8k; 91 | gzip_comp_level 9; 92 | gzip_http_version 1.0; 93 | gzip_min_length 0; 94 | gzip_types text/plain text/css image/x-icon image/svg+xml image/png image/jpg image/jpeg text/js text/php application/javascript application/x-javascript; 95 | gzip_vary on; 96 | gzip_proxied expired no-cache no-store private auth; 97 | gzip_disable "MSIE [1-6]\."; 98 | 99 | location / { 100 | try_files $uri $uri/ /index.php?$args; 101 | } 102 | 103 | location ~ \.php$ { 104 | fastcgi_pass 127.0.0.1:9000; 105 | fastcgi_index index.php; 106 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 107 | include fastcgi_params; 108 | 109 | add_header X-XSS-Protection "1; mode=block"; 110 | add_header X-Content-Type-Options nosniff; 111 | add_header X-Frame-Options SAMEORIGIN; 112 | } 113 | 114 | location ~* \.(?:rss|atom)$ { 115 | expires 1h; 116 | add_header Cache-Control "public"; 117 | } 118 | 119 | location ~* \.(eot|ttf|woff|woff2)$ { 120 | expires 1M; 121 | add_header Access-Control-Allow-Origin *; 122 | } 123 | 124 | location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { 125 | expires 1M; 126 | access_log off; 127 | add_header Cache-Control "public"; 128 | } 129 | 130 | location ~* \.(?:css|js)$ { 131 | expires max; 132 | access_log off; 133 | add_header Cache-Control "public"; 134 | } 135 | } --------------------------------------------------------------------------------