Skip to content


  1. Navaneetha krishnan
    October 20, 2018 @ 8:04 pm

    Thank you so much…

  2. ZZomo
    October 21, 2018 @ 8:37 am

    root@server:~# ./
    -bash: ./ Permission denied

  3. Tharindu Pramuditha
    October 21, 2018 @ 11:25 am

    You are being helpful as always. I was out of my patience to be honest. Can’t wait to test this in a working environment.

    Thanks Dave!

  4. Siêu
    October 22, 2018 @ 10:28 am

    I can’t install MySQL 8

    • Dave H.
      October 22, 2018 @ 2:40 pm

      What happens?

  5. mostafa
    October 23, 2018 @ 10:30 am

    Thank you so much, what about varnish ?!

    • Dave H.
      October 25, 2018 @ 8:30 pm

      No need for varnish when you’re using the Nginx fastcgi cache – it’s being used in this config instead of varnish, is AS fast, but most importantly is easier to configure and debug.

  6. Savvas Zinonos
    October 23, 2018 @ 3:20 pm

    Excellent article as always!!!
    I have tried the above setup on a digital ocean 1 gb ram. Every step works perfectly!
    The only issue i encountered is the ssl command: /opt/letsencrypt/letsencrypt-auto certonly -a webroot –webroot-path=/var/www/acme/ -d -d
    I get an error: certbot: error: unrecognized arguments: –webroot-path=/var/www/acme/

    Any workaround?

    • Dave H.
      October 25, 2018 @ 8:30 pm

      Hi – I’ve updated the article – you may find now the command stretches across on top of the sidebar, but now the — (double dash) will be properly represented instead of being turned into a single longdash.

  7. abc
    October 23, 2018 @ 7:37 pm

    root@server:~# dpkg -i mysql-apt-config_0.8.10-1_all.deb
    dpkg: regarding mysql-apt-config_0.8.10-1_all.deb containing mysql-apt-config, pre-dependency problem:
    mysql-apt-config pre-depends on gnupg
    gnupg is not installed.

    dpkg: error processing archive mysql-apt-config_0.8.10-1_all.deb (–install):
    pre-dependency problem – not installing mysql-apt-config
    Errors were encountered while processing:

    • Dave H.
      October 25, 2018 @ 8:28 pm

      It sounds like you might not be running Ubuntu 18.04? What OS are you running?

  8. Leon
    October 24, 2018 @ 6:18 am

    A few corrections I found for this excellent tutorial as i followed along:
    1. You did not show the command to actually create the database:
    CREATE DATABASE rocketstack;
    2. For the SSL creation there are several occasions where — was converted to a single dash on your code above

    I am working through it diligently and loving your work so far. Thanks

    • Dave H.
      October 25, 2018 @ 8:24 pm

      Oops – thanks for this – I’ve updated the guide to fix these issues.

  9. Chris
    October 24, 2018 @ 8:21 pm

    This is absolutely awesome! Have you considered adding http2 protocol implementation? That speeds up the server quite a lot.

    And with the asynchronous resource fetching we won’t even need to combine CSS/js files with plugins anymore.

    • Dave H.
      October 25, 2018 @ 8:24 pm

      Nice idea – it’ll include it in my stack-tests when I have my benchmarks ready which will be done after I’m finished two plugin upgrades.

      But this link looks useful for what you need:

      • Den
        February 15, 2019 @ 1:00 pm

        Thanks for the awesome guide! Works great!

        Are there any updates on http2 with this stack? I am farely new to this topic, therefore guidance would be highly appreciated.

        • Dave H.
          March 27, 2019 @ 2:02 pm

          See the answer someone else provided in a comment on this thread for adding http2

      • CatchLyrics
        April 28, 2020 @ 4:32 am

        Thanks for the guide. Great stuff!

  10. mostafa
    October 26, 2018 @ 3:00 pm

    i think you forget add gzip to nginx config

    • Chris
      October 27, 2018 @ 10:56 am

      No, It’s in the /snippets/ directory, and is included in the config.

  11. Hihi
    October 27, 2018 @ 6:43 am

    What about Gzip ?

    • Dave H.
      November 30, 2018 @ 10:31 am

      Either use Cloudflare to compress files or add this line to your rocketstack.conf file:

      include snippets/gzip.conf;

  12. Chris
    October 27, 2018 @ 11:00 am

    btw, does the nginx config force https redirection ? I was expecting to see something like “return 301$request_uri;” somewhere in the conf or snippets.

  13. John
    October 27, 2018 @ 8:11 pm

    I think no Gzip on this config.

    ” Enable gzip compression F (0) “

    • Dave H.
      November 30, 2018 @ 10:30 am

      You are correct. In the guide, I presume you will use Cloudflare to compress files but if you wish to add gzip using nginx, simply add this line to your rocketstack.conf file in the nginx/sites-enabled folder.

      include snippets/gzip.conf;

      You can put that after this line:

      include snippets/nginx-cloudflare.conf;

      There are other snippets in that folder that can be useful under various scenarios which I will cover in future guides.

  14. Cyril
    October 28, 2018 @ 9:10 am

    Any plan to use this stack in a high performance cluster set-up like the one you have created using percona cluster ?

    • Dave H.
      November 30, 2018 @ 10:32 am

      Not soon – I’m focusing on plugin upgrades over the coming months including Price Comparison Pro, Scalability Pro, External Images, Faster Woo Widgets and bug fixes for the others.

  15. Erik
    October 30, 2018 @ 2:07 pm

    Hi Dave, just stumbled on your webpage. Great content.

    Which kind of Digital Ocean droplet would you recommend for a Datafeedr site with around 80,000 products? Would the 2 GB, 2 vCPUs droplet be sufficient? Thanks in advance.

    • Dave H.
      November 15, 2018 @ 6:00 pm

      Hi – if you use our External Images plugin then the 2GB droplet will be big enough. It takes a while to import images and it also takes a lot of storage space.

  16. cory
    November 3, 2018 @ 12:42 am

    Unable to log into socket: /var/run/mysqld/mysqld.sock with primer ./

    does a different socket have to be used?

  17. Raymond
    November 7, 2018 @ 11:19 pm

    Any idea how to fix product page not loading when enabling redis object cache?

    • Dave H.
      November 15, 2018 @ 5:59 pm

      This sounds like something specific to your install. Some plugin has some broken code when trying to use the object cache.

      Enabled your debug.log file by editing wp-config.php and then load your product pages and check the log file to find out the culprit.

  18. Chris
    November 13, 2018 @ 10:53 am

    Another suggestion if I may:

    A more native approach to even more speed optimizations allowing us to use less plugins in the CMS. It has a LOT of nice filters:

    • stef
      February 5, 2019 @ 4:57 pm

      This is quite difficult to install I noticed 🙂

      • Dave H.
        February 5, 2019 @ 9:07 pm

        If you don’t follow the ‘defaults’ when securing mysql, then you’ll have to follow the troubleshooting.

        Yes it’s difficult, but you’ll learn a lot about managing and running your own server, which is ultimately the best way to have total control over your wordpress environment in the most cost-effective way.

        • stef
          February 6, 2019 @ 12:58 am

          Oh sorry, my reply was for Chris in order to install pagespeed.

          But I did succesfully followed your guide 🙂 thanks for that. Websites running well

          • Dave H.
            February 6, 2019 @ 7:57 am

            Oops – my bad – my fault for replying from back-end where you can’t see threads. Glad to hear it.

    • Dave H.
      March 31, 2020 @ 1:15 am

      This guide is next in the list. Please upvote this idea here to be notified when it’s released:

  19. Hugo
    November 14, 2018 @ 1:15 pm

    Nice! I got 84 on pingdom 🙂 🙂
    In case someone is curious, here are my details:

    Hosting: Digital Ocean
    Droplet: 4 GB Memory / 80 GB Disk / NYC3 – Ubuntu 18.04 x64

    P.S. I got F for “Compress components with gzip”. Above in the comments you mentioned “It’s in the /snippets/ directory, and is included in the config.” Got confused then why I got F (12points) for Gzip? It has to be tweaked or configured somehow?

    • Dave H.
      November 30, 2018 @ 10:32 am

      Hi – see my other responses here – you can either use Cloudflare to compress your files and set browser caching or you can add this line to rocketstack.conf:

      include snippets/gzip.conf;

  20. Hugo
    November 14, 2018 @ 1:22 pm

    I used > to check if GZIP is enabled, it is. > to check if HTTP 2 is enabled, it is.

    I don’t understand in the comments above, you said
    “… this link looks useful for what you need:

    But it is enabled, or am I missing something?

    • Dave H.
      November 30, 2018 @ 10:33 am

      Add this to rocketstack.conf:

      include snippets/gzip.conf;

      Or use Cloudflare for compressing files to save CPU on your server.

  21. albi
    November 18, 2018 @ 3:46 pm

    thank you! but if i try to access php files eg. installer.php (duplicator plugin) i get a 404, how can i fix that?

    • Dave H.
      November 30, 2018 @ 10:34 am

      Check permissions on the file – they should be owned by www-data:www-data.

  22. Jonas
    November 27, 2018 @ 12:09 pm

    Really simple to follow guide. And blazing fast result!
    Being a total newbie I wonder if it’s possible to add a second WP site to the same VPS? Since I don’t yet use the full potential of a single page..

    • Dave H.
      November 30, 2018 @ 10:25 am

      Yes it is – the easiest way is to create a copy of the nginx/sites-available/rocketstack.conf file for your 2nd domain. You will need to create a separate folder, separate database, separate SSL certificate etc but yes – just repeat the config steps but change rocketstack.conf to point to your other domain. You’ll need to change the server variable to refer to the domain you are adding.

      • Cory
        January 4, 2019 @ 5:34 am

        I don’t know what it is but for some reason trying to create a 2nd site always causes an error with nginx and the service won’t restart. Running the validation tool on the .conf file says that the fastcgi_cache_path directive is not allowed. Of course, running the tool on the original rocketstack.conf file produces the same error but the service will start. I have tried everything except giving each site it’s own cache folder.

        • Dave H.
          January 4, 2019 @ 11:01 am

          Sorry – you need to create a separate cache folder for each site and change the config to reflect that too.

          • Dirk
            January 31, 2019 @ 6:38 pm

            I’m also trying to have multiple (small) sites on one server. So far I’ve made seperate cache folders


            Made different configs.


            in the config file I replaced everything which contained ‘rocketstack’ to for excample ‘site1’

            But I run into an error. Removing default config doesn’t solve the problem

            nginx: [emerg] a duplicate default server for in /etc/nginx/sites-enabled/rocketstack.conf:75

            Am I missing something?

  23. Leon
    November 28, 2018 @ 1:33 am

    When running the tuning script it comes back with “No InnoDB Support Enabled!”

    Is that a tuning script bug or did I miss something?

    • Dave H.
      November 30, 2018 @ 10:41 am

      Sorry – I linked the wrong script.

      Use this instead:

      cd ~
      git clone

      • Si Parker
        April 17, 2019 @ 10:26 am

        This still doesnt seem to work.

        I always get

        Unable to log into socket: /var/run/mysqld/mysqld.sock

        thats the correct sock file in my.cnf but it never seems to be able to login.

        There is a issue open on the tuningprimer github to support mysql 8 but i assume as its in the tutorial that you can do thsi without any issues?

        • Dave H.
          April 19, 2019 @ 2:56 pm

          Hi – please check the database connection errors troubleshooting section on this page. It’s highly likely that you ran the command to secure mysql but then you chose the new authentication plugin. There’s a guide above to changing that back for your WordPress db user.

  24. Casey P.
    December 16, 2018 @ 10:16 am

    Amazing guide. I’m working on enabling WP Multisite to an install I did using this guide. I’m working through it, and I’ll probably figure it out eventually… but would you happen to have an nginx configuration you could share that enables Multisite (sub-directory option)?

    Right now, when I add an additional WP site, nginx does into redirect loop when I try to browse to it.

    Thanks in any case.

    • Dave H.
      December 27, 2018 @ 3:08 pm

      Yes – change the ‘server_name’ variable to reflect your site. That should stop these redirects. It may also be your cloudflare SSL flexible certificate (if you’re using one). If so, you should switch to FULL.

    • Sommie Njoku
      February 18, 2019 @ 8:32 pm

      Hey Casey,

      Experienced the same issue. To fix, add the multisite rewrite rule in the server block of your wordpress.rocketstack.conf file:

      # Rewrite multisite ‘…/wp-.*’ and ‘…/*.php’.
      if (!-e $request_filename) {
      rewrite /wp-admin$ $scheme://$host$uri/ permanent;
      rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
      rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;

      You may also need to specify the server_name with your domain too.


  25. Diego
    December 18, 2018 @ 1:52 pm

    Hello my friend, I really enjoyed the tutorial. I did the same thing as you said and it worked out fine. But I have some doubts:

    1) My site can be accessed by IP and domain. But I want it to be only for domination, is it?
    2) I want to use this setting for Woocommerce, should I add rules to checkout page or something?
    3) I want to use the same VPS for more than one site, how should I proceed?

    Thank you

    • Dave H.
      December 27, 2018 @ 3:04 pm

      1) Add your domain to the server_variable instead of just _ there.
      2) It includes rules for WooCommerce to bypass the nginx fastcgi_cache. You can test this by opening the network tab in chrome developer tools (F12) then reload the page and look at the ‘headers’ sub-tab and view if it was a cache HIT or BYPASS. You’ll notice a BYPASS as soon as products added to basket.
      3) Create additional files for each site in /sites-available/ and separate folders under /var/www/. Ensure you specify the server_name variable.

      • Diego Castro
        January 2, 2019 @ 9:49 pm

        Thanks, I did just that and had problems only with the cache. Nginx has an error saying: “the same path name” / var / www / cache ”
        I do not know how to adjust it, could you help me?

        • Dave H.
          January 4, 2019 @ 11:02 am

          Repeat the steps in the guide to create a new cache folder for the 2nd site and adjust the config accordingly.

  26. Terry
    December 20, 2018 @ 3:41 pm

    This system is rocking for me. A couple things I found:
    The gzip settings are in the snippets, but are not called in the rocketstack.conf (was easy for me to include)
    The corn tab line added should be corrected to fix thetwo dashes versus one (wbroot-path and renew-, both should have two dashes in front
    I find that Cloudflare May or may not be reducing total load time, but always increases TTFB. I have not used Cloudflare for this reason. What has been your experience?
    You have suggested max_execution_time of 6000. Do you mean 600s?
    Finally, the current configuration does not have TLSv1.3 (which requires the more recent OpenSSL, not yet standard with 18.0.4 any thoughts on upgrading? I know there’s at least one repository with the updated 18.0.4 and OpenSSL, but worry about security risks of pulling from another source. What are you planning to do?
    Thank you so much for this write up. It’s A fantastic foundation.

  27. Mike
    December 27, 2018 @ 6:53 am

    I dot one site to work but i’m trying to setup two sites using this process. I have two directories in var/www/site1 site2 and setup two directories for /etc/nginx/sites-available and enabled them. Updated host files to point to each IP that is assigned to me server but both sites direct to the default IP. What am I doing wrong?

    • Dave H.
      December 27, 2018 @ 3:02 pm

      Enter the server_name variable to match the domain you are matching.

      Also, you should delete the /sites-available/default file.

      • Diego
        January 2, 2019 @ 9:44 pm

        Could you write an example ? Cuz i had problem with cache folder. I received a nginx error about /var/www/cache, that was in use for two sites. Im little bit lost.

        • Diego Castro
          January 3, 2019 @ 12:48 pm

          I made several configuration attempts and the one that worked perfectly, was to create a new server block, inside the rocketstack.conf. Everything is ok now

          • Dave H.
            January 4, 2019 @ 11:02 am

            This will also work – I prefer to use separate config files per website, but you can have multiple inside the same file if you wish.

            Actually – I really prefer completely separate droplets per website.

          • harizing
            April 23, 2019 @ 6:08 pm

            I ran into the same issue. Can you share the code please.

        • Dave H.
          January 4, 2019 @ 10:58 am

          Create a separate folder for caching the second site – e.g. /var/www/cache/site2 and change the config file

  28. Terry
    December 27, 2018 @ 7:28 pm

    Dave (sorry the format on my earlier message got messed up)

    This system is rocking for me.

    A couple things I found:

    The gzip settings are in the snippets, but are not called in the rocketstack.conf (was easy for me to include). See you added instructions in comments line.

    The crontab -e addition should be corrected to fix the two dashes versus one (–webroot-path and –renew-, both should have two dashes in front.

    I find that Cloudflare May or may not be reducing total load time, but always increases TTFB. I have not used Cloudflare for this reason. What has been your experience?

    You have suggested max_execution_time of 6000. Do you mean 600s?

    Finally, the current configuration does not have TLSv1.3 (which requires the more recent OpenSSL, not yet standard with 18.0.4). Any thoughts on upgrading? I know there’s at least one repository with the updated 18.0.4 and OpenSSL, but worry about security risks of pulling from another source. What are you planning to do?

    Thank you so much for this write up. It’s a fantastic foundation.

  29. Mike Tack
    December 27, 2018 @ 11:36 pm

    Nice job guys! There are a few minor changes if you need to run virtual host with different ips but other then that this was great!

  30. Four11
    December 30, 2018 @ 7:52 pm

    Hi Dave,

    I want to try this on my live droplet. My current setup is as below. Can you recommend which parts should i do and which should ignore.

    Ubuntu 16.04.4 x64

    1 vCPUs
    2GB / 25GB Disk

  31. Jeff
    January 6, 2019 @ 10:18 pm

    Hi. This is an awesome setup. Really fast, I can seem to get sitemaps to work. It looks like I am having some rewrite issues with NGINX. Any suggestions on how I should enter these and in which particular file? Thanks again.

    • Dave H.
      January 22, 2019 @ 8:21 pm

      Hi – what error are you experiencing? Perhaps the plugin you are using needs some configuration? Typically this would involve copying a line into your nginx.conf file or to your sites-available/rocketstack.conf file.

    • cory
      January 24, 2019 @ 8:07 pm

      Did you get this sorted out? Also having the problem on two sites. Both sitemaps for the plugins yoast and google sitemaps don’t work. Added the recommended fix from plugin developer to conf file but still not writing.

      • Jeff
        January 26, 2019 @ 3:37 am

        finally got it sorted by adding a sitemap plugin and adding the suggested code to the rocketstack.conf file. I used XML Sitemap Generator for WordPress 4.1.0. Had to paste the code in both the http and https sections.

      • Jeff
        January 26, 2019 @ 3:39 am

        for some reason, all the other plugins and/or code suggested insertions. did not work. but the one i mentioned above did. works with Jetpack sitemap and SEO Framework sitemaps as well.

      • Dave H.
        March 31, 2020 @ 1:16 am

  32. David Attard
    January 14, 2019 @ 6:41 pm

    So MariaDB is no longer recommended? I’ve shifted my installation to MariaDB, should I shift back to MySQL 8, or is MariaDB still a good choice?

    • Dave H.
      January 22, 2019 @ 8:16 pm

      MariaDB is still a good choice, but MySQL 8 is as fast as MariaDB and there’ll be a lot more support around the internet for MySQL 8. Performance-wise, they’re very similar.

  33. Denniz
    January 15, 2019 @ 9:05 am

    Seems like FastCGI does some kind of redirect loop after a few days of running..
    When clearing /var/www/cache the problem seems to disapear, any idea?

    • Dave H.
      January 22, 2019 @ 8:20 pm

      Hi – it might be caching a redirect related to cloudflare? This is the most common reason for this. If it’s still happening to you, ping me in the chat so I can look at your config and figure this out.

    • harvey m.
      December 1, 2019 @ 4:35 pm

      Hi did you ever find a solution to this, as I am facing the same issue. I can’t seem to figure it out. Thanks!

  34. Jeff
    January 21, 2019 @ 9:46 am

    Hi. Great set up! Have a question. With this config, should the define(‘WP_CACHE’, true); option be used in the wp config file or not? thanks

    • Dave H.
      January 22, 2019 @ 8:08 pm

      Whatever caching plugin you use should change this setting for you, so no need to manually alter it.

      • Jeff
        January 26, 2019 @ 3:33 am

        ok gotcha. i am not using anything beside the config you posted. still, i saw some other articles online that suggested enabling the line in wp config file when using Redis. guess I will just leave it out.

  35. cory
    January 24, 2019 @ 8:19 pm

    We connect to an outside inventory system using webhooks. They don’t appear to fire with this configuration. Thought maybe it was a plugin but after disabling them all it still won’t fire. Set up a test site with same db on apache and they work. Would there be something stopping web hooks from working in this configuration?

    • Dave H.
      February 5, 2019 @ 2:18 am

      If they are inbound webhooks where the endpoints are on your server, then you’ll need to configure nginx to call the correct PHP scripts. If they are outbound webhooks then I see no reason for them not to work.

  36. Jeff
    January 26, 2019 @ 3:19 am

    On a different topic, what are using for the “Trending” and “Popular” Articles widget in the sidebar? I really like how simple and clean that is. Thanks

    • Dave H.
      February 5, 2019 @ 2:16 am

      It’s WordPress Popular Posts shortcodes inside Tabs Responsive with my own CSS to get it to stick once you scroll a little and my own CSS for the styling.

  37. dirk
    January 28, 2019 @ 7:31 pm

    Im not very known with manually installing this software on a vps. But I would really like to have phpmyadmin on the stack. Is that easy to achieve with mysql8?

    • Dave H.
      January 31, 2019 @ 8:45 am

      Yes – you can install it afterwards, or you can use phpminiadmin.

    • Jeff
      February 15, 2019 @ 12:42 pm

      did you figure out how to install phpmyadmin with this setup? I am having trouble. Always get 502 errors when trying to connect to phpmyadmin GUI. Thanks in advance.

      • Dave H.
        March 27, 2019 @ 2:01 pm

        The easiest to add is to add PHP MyAdmin using a subfolder. You can also add it as a subdomain if you wish, but a subfolder will not require any alterations to your nginx config.

        Or you can use PHP Miniadmin –

  38. stef
    January 28, 2019 @ 9:11 pm

    mmh, I can’t install WordPress. Get an error: Error establishing a database connection

    Don’t know how to resolve this. Followd every step in the guide

    • Dave H.
      January 31, 2019 @ 8:47 am

      When you ran the command to secure mysql, did you choose the defaults, or did you choose the new encryption algorithm for mysql user passwords?

      If you chose the new method, then you should edit /etc/mysql/mysql.conf.d/mysqld.cnf and add the following line at the end:

      default-authentication-plugin = mysql_native_password

  39. Terry
    February 2, 2019 @ 10:14 pm

    Keep having uploads blocked. The only solution I have found is to run this command: sudo chown -R www-data /home/

    Any ideas?

    • Dave H.
      February 5, 2019 @ 2:27 am

      Not sure why your uploads folder is changed from being owned by www-data:www-data. Is it possible you are uploading plugins or files using filezilla directly?

      Is it possible your uploads are blocked for another reason? e.g. max size?

      • Terry
        February 5, 2019 @ 7:03 am

        Not a max size issue, nor direct uploads. I’m stumped on what is changing. Running several configurations and have had to run the command on each.

        • Dave H.
          February 5, 2019 @ 7:26 am

          Can you confirm that your /var/www/rocketstack folder is ownder by user and group (separate things) called www-data?

          ls -l /var/www/

        • Dave H.
          February 5, 2019 @ 1:26 pm

          If you’re interested, ping me a message through our on-site chat, I’ll give you my public key, you can give me access, and I’ll figure it out and report back here with the solution.

          • Terry
            February 6, 2019 @ 11:22 pm

            Right now it seems to be working fine. I will ping you if it reoccurs. Thanks

  40. Faizan
    February 4, 2019 @ 6:53 pm

    Thanks for the great article. Do you think redis will help each and every type of WordPress site?

    • Dave H.
      February 5, 2019 @ 2:26 am

      Absolutely. 1) It moves transients into RAM only which is a major speed boost and 2) It gives you a lightning-fast object cache which is another major speed boost.

      There is no downside.

  41. chip
    February 5, 2019 @ 3:40 pm

    When trying to add a ssl certificate I get an error:

    “\n404 Not Found\n<body

    To fix these errors, please make sure that your domain name was
    entered correctly and the DNS A/AAAA record(s) for that domain
    contain(s) the right IP address.

    Should I use cloudflare before setting up the ssl certificate or afterwards?

    • Dave H.
      February 5, 2019 @ 9:08 pm

      If you have cloudflare on your site, ensure you have clicked the cloud icon in the DNS tab to bypass cloudflare until you have your SSL configured.

      If the SSL still doesn’t register, follow the troubleshooting section for the SSL – there’s an alternative way now to generate the SSL certs that seems to be a bit more reliable across different platforms.

  42. Saif
    February 9, 2019 @ 8:52 am

    Great tutorial and I am interested to try it on my VPS.

    However, I have just two questions, Could you also add how can I add multiple WordPress installations via this process?

    Also, could you add a file manager portion in the tutorial so that I can access the files via a GUI file manager from the web?

    Thanks in advance.

    • Dave H.
      February 13, 2019 @ 11:39 am

      Hi – for a file manager, you can use FileZilla. There are other web-based file managers you can use. I’ll cover these in my upcoming article.

      I’m also adding info about multiple websites on one install to this upcoming article.

  43. stef
    February 13, 2019 @ 1:33 am

    My access logs are flooded with 408 codes in my site_access.log : “POST /api HTTP/1.1” 408 0 “-” “Mozilla/5.0”. Almost every second. I haven’t done much different then following this guide. Do other also expierence

    • Dave H.
      February 13, 2019 @ 11:26 am

      Hi – please change your server_name _; inside your rocketstack.conf file in sites-available.

      Change it to reflect the domain name of your site.

      Then run:

      service nginx restart

      • stef
        February 13, 2019 @ 1:00 pm

        yes I already did 🙂 I copied rocketstack.conf and renamed it to mywebsite.conf. In the config file I changed every line with rocketstack to mywebsite and also changed the server_ name to

        • stef
          February 13, 2019 @ 11:36 pm

          moved to an other hostingcompany. Same installation and no log spamming

  44. wim
    February 15, 2019 @ 1:22 am

    In the modules folder I found a http image filter module. Is this one already enabled and if not would you recommend it to do?

    • Dave H.
      March 27, 2019 @ 2:03 pm

      You won’t need it for normal WordPress stuff, but if you want to enable it for other reasons you could do so. If you’re thinking to resize images on-the-fly, you may be better off using the service provided by Cloudflare to handle this as it’ll alleviate load from your server.

  45. Jeff
    February 15, 2019 @ 11:20 am

    Still the most awesome guide I have seen so far. Do you have any suggestions on installing phpmyadmin with this setup? Have a couple of sites where DDOS attacks are corrupting WP database and would like to be able to “hopefully” repair and optimize with phpmyadmin.

    • Diego Castro
      February 25, 2019 @ 1:30 pm

      I have the same problem. After I created my sites, and set everything up. I was hacked and my database was corrupted. I did the whole procedure to recover but it did not work. I’ll start from scratch. Unfortunately it will be a great job. But that’s what has to be done. If anyone knows of ways to protect the site, let me know. It’s a major inconvenience to get through this.

  46. Simon
    February 18, 2019 @ 9:46 pm

    Mysqld is taking up 40% of the memory from my 1gb digitaloceaan droplet. I’ve run but haven’t found any settings to tune this memory usage. Or is 40% by mysqld normal?

  47. Lawrence
    February 20, 2019 @ 12:04 am

    Thank you so so very much splendid the installation was flawless. Awesome.

  48. Hugo
    February 23, 2019 @ 3:54 pm

    I would like to Enable HTTP/2 Support. For that I need to tell Nginx to use HTTP/2 with supported browsers. Don’t really know where to add HTTP2. Based on what I learned from this article:

    I need to find this:

    listen [::]:443 ssl ipv6only=on;
    listen 443 ssl;

    and replace it with this:

    listen [::]:443 ssl http2 ipv6only=on;
    listen 443 ssl http2;

    I went ahead and nano etc/nginx/sites-available/rocketstack.conf I found only this. Should I just add http2 at the end or there are far more tweaks I have to do than just adding 2 words.
    server {
    listen 80;
    listen [::]:80;

    • Dave H.
      March 27, 2019 @ 2:00 pm

      Your changes look good. That’s if you haven’t enabled HTTPS. If you have enabled HTTPS and letsencrypt on your server, there should be a second block inside rocketstack.conf for 443 SSL traffic, but yes, those edits look good to me.

  49. Marc Gaumont
    February 25, 2019 @ 7:37 pm

    Hi there !

    Your PHP installation appears to be missing the MySQL extension which is required by WordPress.

    I don’t understand… I re-ran everything twice, MySql is well installed and the extensions for PHP as well ! Tried a few different guides, always comes back the same.

    php7.2-mysql is already the newest version (7.2.15-0ubuntu0.18.04.1).
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    Any ideas ?

    • Dave H.
      March 27, 2019 @ 1:58 pm

      I’m not sure how you’re getting this error. Please check the database troubleshooting section. Is it possible you have a different default authentication method for MySQL users than the one listed in this article?

  50. Marc Gaumont
    February 25, 2019 @ 7:38 pm

    Hi there !

    Your PHP installation appears to be missing the MySQL extension which is required by WordPress.

    I don’t understand… I re-ran everything twice, MySql is well installed and the extensions for PHP as well ! Tried a few different guides, always comes back the same.

    php7.2-mysql is already the newest version (7.2.15-0ubuntu0.18.04.1).
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    Any ideas ?

    • Dave H.
      February 25, 2019 @ 9:00 pm

      Hi – please check the database connection errors troubleshooting section on this page. It is highly likely that’s what you are experiencing and you need to change the mysql authentication type for the wordpress db user.

  51. Marc Gaumont
    February 25, 2019 @ 7:46 pm

    In the same line of thinking of mysql php package not seeming to be installed …
    mysql_connect() or mysql_query(). Those functions have been deprecated for a while now… using mysql now, will that not break everything ?

    • Dave H.
      February 25, 2019 @ 9:03 pm

      Plugins have all been using $wpdb->get_results for a while now, rather than constructing their own db connection. If you are integrating third-party php, rather than plugins, then you may have to rewrite older mysql_* functions to use the newer functions.

  52. jemmy
    March 6, 2019 @ 2:06 pm

    Hello Dave
    Can I use Debian9 instead ?

    • Dave H.
      March 8, 2019 @ 11:33 am

      Yes, should be fine, providing the update packages are available. Debian is normally slower at releasing stable updates than Ubuntu.

  53. Imran
    March 6, 2019 @ 3:08 pm

    Finally I got it running how do I enable ion cube loader I have a plugin which needs ion cube loader to work thank you

  54. Derrick R.
    March 6, 2019 @ 3:25 pm

    First off, I’d like to say thank you for an excellent well explained article.

    FYI, I found a gotcha whilst installing mysql, using the above commands:

    wget -c
    dpkg -i mysql-apt-config_0.8.10-1_all.deb
    apt-get update

    Which gave an error:

    Err:4 bionic InRelease
    The following signatures were invalid: EXPKEYSIG 8C718D3B5072E1F5 MySQL Release Engineering

    This meant I couldn’t proceed, at the time, but managed to resolve by adding the key:

    apt-key adv –keyserver –recv-keys 8C718D3B5072E1F5

    Which then allowed me to successfully:

    apt-get update
    apt-get upgrade

    So, I then had a working version of MySQL 8 on the machine.

    However, the thing I’m struggling with now is that I’m trying to install phpmyadmin, but keep getting the following error:

    mysql said: ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘IDENTIFIED BY ‘examplePassword’

    Do you have any ideas as to how I could resolve this?

    • Dave H.
      March 8, 2019 @ 11:37 am

      Hi – it sounds like phpmyadmin is not yet MySQL 8 compatible. Maybe it’ll be as simple as getting the very latest phpmyadmin. The part that has been deprecated has been deprecated for a while, specifically performing a GRANT PRIVILEGES and creating the user at the same time.

      See this stack overflow for more info:

      You could find the code inside the phpmyadmin that is performing this GRANTandCREATE and alter it to the new format, but presumably someone else has done this already.

      You may also run into issues relating to the new default authentication method in MySQL 8 – see this stackoverflow about that:

  55. Kavan Lyles
    March 6, 2019 @ 10:29 pm

    Hi, I updated the config files to use PHP 7.3, here is the link to the git repo.

    • Dave H.
      March 27, 2019 @ 1:56 pm

      Thank you for your help with this.

  56. Derrick R.
    March 8, 2019 @ 12:06 pm

    Hey @Dave H,

    Unfortunately, I’d already those articles and had no luck. Think I’ll therefore give phpmyadmin a miss until compatibility issues are resolved.

    Many thanks for a great article!

  57. Abdul Samad
    March 8, 2019 @ 8:15 pm

    Please update first two commands they are not working


    wget -c
    dpkg -i mysql-apt-config_0.8.12-1_all.deb

    • Dave H.
      March 27, 2019 @ 1:55 pm

      Which version of Ubuntu are you using and which hosting company?

  58. Surya
    March 9, 2019 @ 9:49 am

    Hey buddy, I have followed all step. but I’m facing an issue in sitemap. using Yoast plugin for seo. I able to access sitemap with this but while we call then throw 404 . I have update rule in /etc/nginx/sites-available/rocketstack.conf still facing issue . please help me

    • Dave H.
      March 27, 2019 @ 1:56 pm

      Please try visiting wp admin -> Settings -> Permalinks then hit ‘Save’.

  59. ihatelife
    March 9, 2019 @ 8:11 pm

    Hi, can you help me to make rewrite rules on rocketstack.conf for Yoast?

    I added this code below but my /sitemap_index.xml still not created or appear. Just 404 not found.
    What should I do?

    # Rewrites for Yoast SEO XML Sitemap
    rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
    rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;

    • Dave H.
      March 27, 2019 @ 1:54 pm

      Hi – sometimes permalinks get stuck – you’ll probably find that if you visit Settings -> Permalinks in wp-admin then click ‘Save’ (yes without changing anything) that it will start working

  60. DampAs
    March 17, 2019 @ 4:33 pm

    Dear everyone who writes about technical stuff about development in technology, web, mobile dev, should take this article as an example, cause it tells you about what you gonna install, what that stuff gonna do/affected to you.

    btw, thank you for the article dave, I know what I’m gonna do now.

    • Dave H.
      March 21, 2019 @ 12:16 pm

      Thank you for your kind words.

  61. Terry
    March 21, 2019 @ 2:57 pm

    Any advice on upgrading php to 7.3?

  62. Barry
    March 23, 2019 @ 1:27 am

    With this configuration, is it possible to use Cloudflare cache everything rule?

    • Dave H.
      March 27, 2019 @ 1:53 pm

      Yes it is

  63. Si Parker
    March 28, 2019 @ 3:50 pm

    Hi Dave, Thanks for this updated guide very good as always.

    Is there an accepted / particularly good way to control caches for things like woocommerce etc where the cart of sessions need to be maintained per user.

    Have you considered writing a deply script similar to that would manage this whole deployment. its particularly useful in its capability to setup pools for multile sites on the one server. and a command to include phpmyadmin via a symlink and then turn ot off again also.

    Finally when installing i had a long issue trying to figure out why i couldnt install the version of mysql you mention above. this was because the gpg key for that version expired in feb and apparently is still expired and cant be used without a big workaround. It worked fine when i did subversion 12 instead from command line

    thanks again for all your effort writing this up.

    • Dave H.
      April 11, 2019 @ 3:22 pm

      Hi – thank you – I will get the mysql thing updated ASAP.

      re: WooCommerce, the nginx config comes with configuration for WooCommerce. This detects the WooCommerce add-to-cart cookie and then prevents caching for that user from that point onwards.

  64. mikez
    March 28, 2019 @ 10:01 pm


    Your tutorial is great
    but I facing an issue with Yoast sitemap

    I try to refresh my permalink on wp-admin Settings -> Permalinks but nothing change

    Can you help me?


  65. estreetz
    April 6, 2019 @ 2:14 am


    I saw in the discussion, many people like me have an issue with Yoast Sitemap
    Can you help us to added rewrite rule on nginx conf?


    • Dave H.
      April 11, 2019 @ 3:05 pm

      Hi – yes – working on this guide for you now.

  66. Dave
    April 10, 2019 @ 5:39 pm

    Hi Dave, awesome tutorial! I am new to this so forgive me if this is stupid question… How can I get gzip to work?

    -Added the snippet include to config
    -Restarted nginx
    -Didn’t work so restarted my droplet
    -still showing that its not gzipping.

    How can I check if gzip is even installed? Should I just skip this and use cloudflare?

    • Dave H.
      April 12, 2019 @ 8:53 am

      There are a few possibilities here:

      1. Your own antivirus may be forcing content to be unzipped
      2. You may be looking at an already cached file (cached on your computer, on disk or RAM). In this case the gzip header probably won’t appear
      3. It may be because of the gzip vary header which chrome is then displaying instead of gzip

      You can check for compression using a variety of online tools, e.g.

      You can also see more background info here:

      • Dave
        April 16, 2019 @ 6:05 pm

        Ok great, I got it all worked out. Tested the site on a server pilot/digital ocean droplet vs this setup on DO, and this version loads almost twice as fast… in just over 1s. Phenomenal! And that’s without the CDN setup yet. Thank you!!!

  67. Leon Shivamber
    April 11, 2019 @ 6:11 pm

    These work for me regarding yoast:

    # Rewrites for 301
    include /home/;

    # Rewrites for Yoast SEO XML Sitemap
    rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
    rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;

    • Dave H.
      April 12, 2019 @ 8:41 am

      Great, thanks! I’m working through this on another site right now.

  68. mike agnassia
    April 11, 2019 @ 9:19 pm


    If you have a problem to install Mysql 8
    you can use this repository

    $ wget
    $ sudo dpkg -i mysql-apt-config_0.8.12-1_all.deb


    • Dave H.
      April 12, 2019 @ 8:40 am

      Thank you for this and for helping our readers. I’ll get the article updated once I’ve built a new stack. Should be today.

      • stan
        April 19, 2019 @ 12:38 am

        I love your blog! Just curious when the updated stack is going to be released? Should I bother installing the one on this page or wait for the new stack?


        • Dave H.
          April 19, 2019 @ 2:53 pm

          This is currently the newest one. You can follow some additional tips you’ll find in the comments to get the latest version of MySQL and PHP. Other than that, you can use these two commands to get everything to update:

          apt-get update
          apt-get upgrade

  69. estreetz
    April 12, 2019 @ 1:13 pm

    Thank Leon, Sitemap it’s good for me too with

    # Rewrites for 301 include /home/;

    # Rewrites for Yoast SEO XML Sitemap rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last; rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;

  70. harv
    April 17, 2019 @ 5:24 am

    Hi, thanks for the great guide! It was my first time configuring a stack myself and it wasn’t that hard.

    Everything seemed to work fine until I set up SSL. Right after I changed the WordPress address and Site address to https, the website would not load anymore. All I get is “This site can’t be reached”.

    I tried adding the https url to the wp-config file but that didn’t help.

    After this happened, I continued and configured cloudflare, because I thought it would help, but it did not.

    Any idea of what I should check next?

    • harv
      April 17, 2019 @ 2:52 pm

      I realized when I change Cloudflare to Flexible SSL, my website is back. Only when it I set it to Full or Full Strict does it break the website. Any ideas on how to fix this or what went wrong?

      Thank you!

      • Dave H.
        April 19, 2019 @ 2:55 pm

        Yes – if you want to use FULL on Cloudflare, you need to upload your own SSL certificate to Cloudflare. I believe they moved this feature into the premium plans however, so Flexible is what you should use unless you want to pay them.

        Given that you have an SSL on your site, you still have fully encrypted traffic, except with 2 different SSL certs – one by Cloudflare, and one by Letsencrypt.

    • Dave H.
      April 19, 2019 @ 2:56 pm

      Use Flexible SSL or upload your certificate to Cloudflare.

  71. Derrick R.
    April 18, 2019 @ 4:03 pm

    Hi Dave,

    I’d previously successfully implemented your guide above on two separate DigitalOcean Droplets (i.e. VPS) for two separate domains and saw a good performance improvement.

    However, I’m now in the process of migrating on to a single (larger) server but am finding that the second site doesn’t work as expected when I enable redis (in wp-config.php) and am seeing content from the first redis enabled site and/or content missing.

    I’ve found a number of articles via google (e.g. but this has a number of differently named config files and am not confident that it’d work on my latest patched 18.04 LTS Ubuntu server.

    Would you be able to provide any pointers?



    • Derrick R.
      April 19, 2019 @ 10:34 am

      After much trial & error, I managed to get multiple Redis servers running for my multiple WordPress instances on the same server, aided by this guide:

      Whilst not 100% fitting my exact use case, I managed to work out the differences and errors along the way. This also specifically helped:

      Finally, setting up my 2nd wp-config.php to suit for the 2nd Redis server, adding:

      /** Redis config parameters */
      define(‘WP_REDIS_CLIENT’, ‘predis’);
      define(‘WP_REDIS_HOST’, ‘’);
      define(‘WP_REDIS_PORT’, ‘6380’);
      define(‘WP_REDIS_DATABASE’, ‘1’);
      define(‘WP_REDIS_PASSWORD’, ‘veryLongSecretPasswordGoesHere!’);

      Just posting all the above, in the hope someone else finds it useful.

      Cheers, Derrick

      • Dave H.
        April 19, 2019 @ 2:59 pm

        Very cool – thank you for the info – others will definitely find it useful. I pretty much always only run one website per server, given how cheap droplets are these days.

  72. Ricardo
    April 21, 2019 @ 5:00 pm

    Hi Dave, thank you so much for such a great article. It helps me a lot!

    I wanted to ask you something.. Do you happen to have this dockerized? or, could you point me to a good docker file that might be pretty close to this?

    THanks so much,

    • Dave H.
      April 23, 2019 @ 3:02 pm

      I do not have it dockerized yet, but this is definitely something for the future.

      I am in talks with someone about recommending a great managed service that includes clustering options however. More to follow soon.

      • Ricardo
        April 24, 2019 @ 7:43 am

        Alright, thanks a lot!

      • Ricardo Martínez Trenado
        June 28, 2019 @ 5:58 pm

        Took me weeks, but I got it.

        I wanted to share with everybody. Please, feel free to fork, PR, or just throw any comments about this setup. I just learned Docker so there could be some mistakes, however, it is working great for me and I’m already using it to easily create new domains or testing ones.

      • Ricardo Martínez Trenado
        June 28, 2019 @ 5:58 pm

        Oh, I forgot to say.. The Readme is not updated. This project is a fork of this one:

  73. Si Parker
    April 30, 2019 @ 3:44 pm

    Hi, New query about the nginx cache plugin.

    We use Pools for php. which means one wordpress site will have a pool named after its user.

    So example user fred has a fred.conf in /etc/php/7.2/fpm/pool.d/

    ; pool name (‘www’ here)

    ; Unix user/group of processes
    ; Note: The user is mandatory. If the group is not set, the default user’s group
    ; will be used.
    user = tattoo
    group = tattoo

    my nginx config then specifies

    fastcgi_pass unix:/run/php/php7.2-fpm-fred.sock;

    And we can have different amounts of pm.servers etc and control the site usage properly while being able to have multiple sites on the one server.

    Except for the issue that the nginx cache at /var/www/cache/fred is owned by www-data and therefore cant be accessed by the Till Kruss Nginx plugin.

    I can add the user fred to the www-data group

    usermod -a -G www-data fred

    and then modify the folder

    chgrp www-data /var/www/cache/fred
    chmod g+rwxs /var/www/cache/fred

    and this allows my pool user to delete the cache correctly.

    My query is….

    is that an acceptable way to do things?

    does adding a user to the www-data group give them access to files they should not have access to.

    Can I have Nginx proxy cache have a different user for each cache? so do the above the other way round and add www-data to the Fred group and save the proxy data as owned by Fred:Fred .

    Or is there any better way to manage the cache on a per-user basis using pools so that the Nginx plugin will work and be able to purge the cache but the security and separation of the different sites and users is maintained.

    i realise thats a long post. Sorry.

    Your feedback is appreciated.

  74. harvey m.
    May 1, 2019 @ 6:54 pm

    Hi, when I got up to the “Securing MySQL” part, I got this error:

    “The user provided does not have enough permissions to continue. mysql_secure_installation is exiting.”

    I was logged into console with the main root account. How do I fix this?


    • harvey m.
      May 1, 2019 @ 9:15 pm

      Also, I modified the “/etc/php/7.2/fpm/php.ini” file and changed these entries:

      max_execution_time = 6000
      memory_limit = 512M
      upload_max_filesize = 50M

      but I still get a message on the wp media upload page stating: Maximum upload file size: 8 MB.

      I tried finding my .htaccess file to add the values, but it seems it doesn’t exist. Any clues?


      • Dave H.
        May 9, 2019 @ 4:27 pm

        You’ll need to restart the php service after changing these values using:

        server php7.2-fpm restart

        • harvey m.
          May 10, 2019 @ 8:37 pm

          Thanks. I tried “service php7.2-fpm restart” but it still shows max upload 8mb on the wordpress media upload page.

          • harvey m.
            June 20, 2019 @ 5:22 am

            I fixed this by changing this line in php.ini: post_max_size = 50m

          • Dave H.
            June 20, 2019 @ 1:51 pm

            Thank you – I’ll update the article to reflect this.

    • Dave H.
      May 9, 2019 @ 4:28 pm

      Use your root db user rather than the wordpress db user.

      • harv
        May 22, 2019 @ 7:55 pm

        Thanks for your response. Where should I use my root db user? In wp-config?

        Also, I am facing another problem and I am not sure if it is related. I tried updating a theme and I get this permissions related error:

        “An error occurred while updating Porto: The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.”

  75. Nitin
    May 4, 2019 @ 11:24 pm

    How can I further boost my page load speeds? Is it possible to install opcode caching and varnish caching additionally?

    Also, I do have WP Rocket plugin for wordpress, which they say works with NGinx out of the box. Should I install it (since I already have a subscription), or should I install W3 Total cache? Or should I just not consider any caching plugin (like you had suggested above)?

    • Dave H.
      May 9, 2019 @ 4:26 pm

      I don’t use WP Rocket. I just rely on: fastcgi_cache, autoptimize plugin and sometimes some cloudflare features.

  76. Nitin
    May 4, 2019 @ 11:40 pm

    Do you suggest installing the Google Pagespeed module with this configuration?

    • Dave H.
      May 9, 2019 @ 4:31 pm

      It’s up to you. Google Pagespeed or new relic are both decent, but I like using xDebug when there are any tricky issues. Less overall load on the server.

  77. Hugo
    May 10, 2019 @ 1:56 pm

    Something is wrong with WP 5.2 ??
    DigitalOcean > Ubuntu Droplet > WP 4.9.8 > OK
    DigitalOcean > Ubuntu Droplet > Latest WP > After installing let’s encrypt > I can’t access website anymore Frontend Backend don’t work. I’ve tested 2x times. Once I get to the “install SSL” section of your tutorial, website is crashing. Weird.

    • Dave H.
      May 21, 2019 @ 9:12 pm

      Nothing I’m aware of should break with WP 5.2.

      Did you use certbot to run letsencrypt and did it complete without errors?

      One key note: If you are using Cloudflare, when you are running the certbot you should have the Cloudflare bypass option on. (arrow going around the cloud rather than through the cloud in DNS settings)

  78. Lincoln
    May 13, 2019 @ 11:26 pm

    After installing SSL, site completely crashed, same problem like an above user. He mentioned this “Right after I changed the WordPress address and Site address to https, the website would not load anymore. All I get is “This site can’t be reached”. Me too!! Same problem, tested 5 times, everything works like a charm, once I get to the “install SSL” point, everything dies…. This is stupid.

    He was able to fix it by using Cloudflare and flexible SSL. In my case I’ll wait for Dave to fix this SSL problem. I hate cloudflare, don’t wanna use it, therefore skipping this tutorial for now.

    • Dave H.
      May 21, 2019 @ 9:07 pm

      If you use Cloudflare, you need to pay these days to use a strict SSL, otherwise use the Flexible SSL certificate option.

      If you don’t use Cloudflare, you shouldn’t see issues.

      Did you restart nginx? The certbot should restart it for you, but if not, try restarting nginx and take a look at your rocketstack.conf file and confirm the certbot added the SSL certificate lines.

  79. Jason
    May 15, 2019 @ 5:00 am

    Sorry for a stupid question, but why is apache2 being installed if nginx is going to be the webserver? Thanks

    • Dave H.
      May 15, 2019 @ 8:32 pm

      It’s on there by default. Removing it clears things up.

      • Jason
        May 17, 2019 @ 1:02 am

        My apologies Dave, but I did the whole glance look at the install list and misread the apache 2 was an apt purge not an apt install. Sorry to waste your time!

  80. Armando
    May 15, 2019 @ 5:05 pm

    Hi, great work. It’s a really amazing setup and I’m actually using it under Vagrant for local development/content updates, as it makes everything faster than my old XAMPP.

    However, to my understanding, you’re missing the nginx configuration for WordPress.
    .htaccess files don’t work with nginx, so all WordPress rewriting requires some special configs.

    • Dave H.
      May 15, 2019 @ 8:31 pm

      Hi – it really depends on what you’re using. If you’re using Yoast sitemaps for example, then yes you need to add some extra rewrites covered here:

      • Armando
        May 16, 2019 @ 4:35 pm

        No, sorry, my bad, your original setup works out of the box. My problem was that I was trying to make it work with several wordpress installations. Through trial and error I figured out that, in that case, you need to add some configurations for ngninx in /etc/nginx/sites-available/rocketstack.conf.
        I put all my sites in subdirectories mounted on /var/www/rocketstack. So, lets say I have a site I wanna see on rocketstack.local/site, then I’ll need to add these two location blocks within the server block (notice I haven’t tried with ssl yet because it’s still just for local development)

        # These 2 blocks go inside the first server block in rocketstack.conf
        location /site/ {
        root /home/;
        try_files $uri $uri/ /site/index.php$is_args$args;
        location /site/wp-admin/ {
        root /home/;
        try_files $uri $uri/ /site/wp-admin/index.php$is_args$args;

        After adding this, you might need to restart nginx a couple of times, perhaps after trying to open a page and getting a 404 (not so sure how all of this works, but after a few restarts it does).
        Thanks again and keep on the good work. Looking forward for your next awesome setup

  81. Kevin
    May 31, 2019 @ 10:36 am

    Hi Dave,
    Thank you for the share. Followed and worked perfectly.
    Would just have one question: How would you enable Brotli compression with this set up?
    Thank you.

  82. Ryan M.
    June 2, 2019 @ 9:50 am

    Thank You So Much
    Dave H.
    Finally, I have WordPress with PHP7.3 with MYSQL 8
    I was looking for this type of script to make the fastest wp website.

    I wanna say to all visitors who are trying to install this.
    Please read carefully the whole script
    There isn’t any mistake.

  83. Chris
    June 4, 2019 @ 11:25 am


    First: thx for this awesome tut! I set up an Ubuntu 18.04 LTS VM (2 CPUs, 4GB RAM, 120GB SSD VHDX) on a local domain. I followed every necessary step including the MySQL and PHP fine-tuning. I skipped SSL because I only need this site for local testing.

    WP 5.2.1 (DE Edition) worked fine. I can log in and make my desired settings. But when I log out and try to open the page WP throws an error (translated from German):

    “The file wp-config.php already exists. If you need to do the configuration again, please delete this file first and try a new one.”

    I already tried to insert


    in the wp-config.php but had no luck. Tried to reboot the VM, deleted browser cache, etc. No matter what I try I’m always redirected to http://myhost.mylocal.domain/wp-admin/setup-config.php

    Never encountered this before (on managed webservers, vms, vhosts, xampp, lamp, etc.).

    Any tips?

    Thx 😀

    • Dave H.
      June 4, 2019 @ 12:14 pm

      It sounds like you maybe migrated a site over the top of the fresh rocketstack installation. If so, you’ll need to update your wp-config.php file to reference the correct database and db name and db user.

      • Chris
        June 4, 2019 @ 7:50 pm

        Hi Dave.

        No, I didn’t migrate a site or installed a second one. I just followed your tutorial. Only difference is that I selected the German version of WP 5.2.1 but kept everything as described.

        Opened the URL, provided WP installation with all necessary credentials, clicked on install and logged in. No matter what I edit in the backend (permalinks, website title, theme or simply nothing) – after I log out I get this error message. Started over with a fresh install from my VM snapshot with no luck 🙁

        • Dave H.
          June 4, 2019 @ 10:11 pm

          That’s odd. So if it installed, you definitely had the DB creds correct. Maybe you didn’t set up the www-data:www-data permissions for the /var/www/rocketstack folder?

          • Chris
            June 5, 2019 @ 8:09 am

            I definitely set

            chown www-data:www-data /var/www/rocketstack -R

            during the installation. I followed the tut again on a fresh and clean Ubuntu install from top to bottom and the error remains. If I execute the chown command a second time after everything is installed it works… really strange…



          • Dave H.
            June 5, 2019 @ 6:54 pm

            Is it possible you migrated an existing site? If so, the file permissions would have been copied across when you copied over the previous files.

            I’ve written a full guide to migrating reliably here:


  84. Krzysztof T.
    June 5, 2019 @ 8:32 pm

    Could you please fix this bug: ? It’s over a month old.

    PS. Please delete this comment, just answer in the thread.

    • Krzysztof T.
      June 7, 2019 @ 2:12 pm


  85. Dillon P.
    June 6, 2019 @ 10:00 am

    Hi Dave,

    Do you recommend using PHP opcache in addition to the above?


    • Dave H.
      July 6, 2019 @ 9:16 am

      Yes – sorry for not including it originally – I’ve added it to the article now. I’m running benchmarks on the key problems my customers have – mostly around huge stores and large numbers of woocommerce product variations – and I’ll link to that benchmark article once it’s released.

  86. Dillon P.
    June 17, 2019 @ 1:28 pm


    After following this guide everything is working great, however I’m trying to setup a cron to curl a URL and I’m getting:

    curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to

    Is there a specific setting or update to resolve in this config?


    • Dave H.
      June 18, 2019 @ 7:45 pm

      I use wget for cron. Not sure why your cURL is not working. Maybe you don’t have letsencrypt set up and are using cloudflare instead? This may cause this I guess.

  87. harvey m.
    June 19, 2019 @ 12:54 am

    Hi, I want to thank you for your great stack! Together with your scalability plugin I bought, my website is super fast! However, I am still stuck with these issues:

    1. Securing MySQL: I get this error while trying to secure MySQL, even though I am logged in as root:“The user provided does not have enough permissions to continue. mysql_secure_installation is exiting.”

    2. I modified the “/etc/php/7.2/fpm/php.ini” file and changed these entries:

    max_execution_time = 6000 memory_limit = 512M upload_max_filesize = 50M

    but I still get a message on the wp media upload page stating: Maximum upload file size: 8 MB. I also Restarted MySQL after making these changes.

    Any Ideas where I could of gone wrong? Is there any way I can give you access to my install to check it out?

    Thank you

    • harvey m.
      June 19, 2019 @ 1:00 am

      *edit I meant I restarted PHP (not MySQL)

    • Dave H.
      June 20, 2019 @ 1:50 pm

      1. You’ll need to provide the root db password for this section, not the wordpress db user/password
      2. You’ll need to restart the php service for these entries to kick in. You can restart php using:

        service php7.2-fpm restart

  88. derrick
    June 20, 2019 @ 2:39 am

    Hi, I am going through your tutorial and got stuck at the step “Adding SSL using Letsencrypt”

    I succesfully installed Lets Encrypt, however Let’s Encrypt asked to select to add a redirect (option 2) to what I said yes, and now I can’t go on to the next step to change the site url in wordpress to https however I now can’t access wordpress anymore. I suspect it’s because I selected #2.

    I looked online to see how to revert this, but all I could find was that option 2 adds a few lines to a file called 000-default.conf, and that I have to comment out them out. I couldn’t find this file though (Is it an apache file?):

    RewriteEngine on
    RewriteCond %{SERVER_NAME} 25 [OR]
    RewriteCond %{SERVER_NAME} 3
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

    Is there a way to reinstall Lets Encrypt or fix this?

    Thank you!

    • Dave H.
      June 20, 2019 @ 1:48 pm

      The file will be inside /etc/nginx/sites-available for the redirect.

  89. Bjokib
    June 23, 2019 @ 12:57 pm

    Extremely good instructions, thank you. The site is extremely fast!

    Trying to upload a media file (WAV) that is around 65MB, getting this error in /var/log/nginx/rocketstack_error.log (A 12MB MP3 file worked fine.)

    2019/06/23 11:22:57 [error] 2623#2623: *91 client intended to send too large body: 71886902 bytes, client:, server:, request: “POST /wp-admin/async-upload.php HTTP/1.1”, host: “”, referrer: “”

    client_max_body_size 250M; in /etc/nginx/nginx.conf

    upload_max_filesize = 250M in /etc/php/7.3/fpm/php.ini
    post_max_size = 12M in /etc/php/7.3/fpm/php.ini

    WordPress media upload page also says, Maximum upload file size: 250 MB.

    All services are restarted, php-fpm, Nginx.

    But when I upload something, it throws a HTTP error. And the log file logs that error above.

    I believe I have increased the limits in all config files. What am I missing?

    • Bjokib
      June 23, 2019 @ 12:59 pm

      There was an error in posting the above comment.

      post_max_size = 250M in /etc/php/7.3/fpm/php.ini

      Not 12M!

    • Dave H.
      June 24, 2019 @ 3:36 pm

      In addition to PHP, Nginx has its own max upload configuration setting. That’s what the client_max_body_size refers to and what this error refers to.

      Did you add client_max_body_size 250M; inside the http {…} area?

  90. Bjokib
    June 24, 2019 @ 4:55 pm

    I did, it didnt work.

    I had to edit this file: /etc/nginx/snippets/limits.conf

    When I did that it worked!

  91. mikez
    June 30, 2019 @ 12:25 am

    Hi Dave,

    I got error 524 on Cloudflare
    when I try to install a database on my server

    Can you help to fix this issue?

    Thank You

    • Dave H.
      July 1, 2019 @ 9:08 am

      Keep cloudflare off – use the little cloud bypass icon – until you’ve completed full installation.

  92. Gigi
    June 30, 2019 @ 3:51 pm

    Hi Dave,

    Thanks for the great tutorial.

    I have one issue – http is not redirected to https. I installed Lets Encrypt and selected option 2 Redirect http to htpps and also forced redirect in wp-config. But when I go to it gives me ERR_EMPTY_RESPONSE.

    Any ideas how to fix this?

    • Dave H.
      July 1, 2019 @ 9:09 am

      Hmm – this sounds like you’ve somehow switched off port 80 completely. You should keep your site listening on port 80 and have that rule redirect to 443. Letsencrypt should automatically add this rule for you.

  93. drew
    June 30, 2019 @ 11:22 pm

    Hi, do you have a guide on getting this stack to work with multiple websites on one server?


    • Dave H.
      July 1, 2019 @ 9:11 am

      There are some comments in this article from others covering how they did it but generally you need:

      • create a new folder and new database per site
      • add a new file in /etc/nginx/sites-available/ for your new site
      • there are a few alterations you need to make in that file to point at the new folder for your new site

      That’s it really, it’s fairly simple, but droplets are so cheap these days I just do 1 site per server.

  94. Adam
    July 4, 2019 @ 8:30 pm

    Yes MySQL is best because supported by Ubuntu, same that SlickStack did. No reason to change to Percona or MariaDB cuz they have small team and less money. But PHP 7.3 I don’t think its faster much than 7.2 if using Fastcgi Cache already, and not supported by Ubuntu. Can you please tell me what you think about my opinion? And do you try SlickStack with Force HTTPS MU plugin?

    • Dave H.
      July 6, 2019 @ 9:07 am

      I’m not sure what support you rely on from Ubuntu, I’ve certainly never thought to contact them for anything. I have multiple sites using PHP 7.3 – the reason it’s in here is because it’s 10% faster than PHP 7.2.

      I have not tried SlickStack or HTTPS MU plugins – let us know here if you do.

  95. sacretim
    July 5, 2019 @ 8:52 am

    Thank you for this wonderful tutorial. It would be awesome to create an ansible playbook from this.

    • Dave H.
      July 6, 2019 @ 9:04 am

      I had created an ansible playbook in the past but I disliked it because really ansible is focused on deploying multiple droplets and then updating all of them across the board.

      I prefer the individual server-level granularity, but if you are up for creating an ansible playbook I would definitely link it here.

      You should maybe look at one of the other comments in here from someone who has created a docker deployment script – similar but probably better than ansible.

  96. Philippe
    July 8, 2019 @ 3:47 pm

    Hi there!

    Any update ? 🙂

    • Dave H.
      July 8, 2019 @ 4:01 pm

      Sorry, what’s this regarding?

  97. Kent
    July 10, 2019 @ 6:46 am

    Thank you so much for your tutorial, Dave.
    I have been done and my website is working. I use with woocommerce, i test with about 200 products. But my store is still slow, especially admin page, when I delete products. Can you give me some suggestions?
    Thank you so much.
    Best regards.

  98. David Gilfillan
    July 15, 2019 @ 5:06 pm

    Hi Dave, great setup! Couple of quick questions…

    you mention when debugging a failed install you look for NGINX: HIT rather than NGINX: BYPASS. I might be mistaken, but these headers don’t appear to be added anywhere in this setup?

    Did you mean one of the below?

    Including the ‘fastcgi-cache’ snippet returns a ‘fastcgi-cache’ header (HIT OR MISS) but only for html assets?
    Including the ‘static assets’ snippet means files such as css, js, etc. return a ‘Cache-Control’ header as “public” .

    I think I have mine setup OK, but might be helpful to others if you wouldn’t mind clarifying?

  99. David Gilfillan
    July 15, 2019 @ 5:36 pm

    The only snippet I couldn’t figure out it’s purpose or where/whether to include was: fastcgi-php.conf

    If you can shed any more light it would be appreciated.

    • Dave H.
      July 16, 2019 @ 1:32 am

      This script determines if the fastcgi_cache should be hit or bypassed. Based on things like cookie for items added to basket or user logged in etc.

  100. David Gilfillan
    July 15, 2019 @ 5:38 pm

    Also, I won’t be using Cloudflare as I plan to use AWS Cloudfront. I noticed the following lines in the conf file setting a proxy header? As these still needed do you know?

    #these lines should be the ones to allow Cloudflare Flexible SSL to be used, so the server does not need to decrypt SSL
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-NginX-Proxy true;

  101. derrik
    July 17, 2019 @ 2:24 am

    Hi, does this stack cover setting up a firewall, or is that not needed because it is using fail2ban? If I need to set up a firewall too, is there anything I should keep in mind in regards to open ports, etc?

    Thank you

    • Dave H.
      July 17, 2019 @ 10:02 am

      The firewall is included and fail2ban automatically adds rules to your firewall.

      Check out my stack maintenance guide for administering fail2ban etc, but you can also look up iptables. For example, the following command will list all firewall rules that have been created (e.g. by fail2ban or anything else):

      iptables -L

  102. Ben
    August 6, 2019 @ 6:49 pm

    Hi Dave,
    Thanks for sharing the great work! I had a few questions.
    — I’m hoping to spin mysql and redis up on their own servers. Do you have any tips or scripts for this?
    — Any thoughts on pros- v cons of supplementing this config with Nginx acting as reverse-proxy for Apache?

    • Dave H.
      August 13, 2019 @ 5:59 pm

      I avoid Apache just because it’s normally a memory hog, but yea you can put mysql and redis on their own servers easily enough and change the IP addresses instead of ‘localhost’. Make sure you use local network IP addresses for better performance. If using digital ocean, you can tick the box for ‘private networks’ when creating droplets and then your servers have two IP addresses – one public, one private and local.

  103. Ben
    August 6, 2019 @ 7:15 pm

    Also, is there a reason to install php-fpm or cgifast?
    (Sorry, I’m still learning a bunch about server configs)

    • Dave H.
      August 13, 2019 @ 6:06 pm

      I don’t think I understand the question – you need php-fpm to actually process PHP code.

  104. vicky
    August 10, 2019 @ 8:50 am

    Hi Dave,

    After installing wordpress, I still get the 404 nginx page when trying to visit my domain. The wordpress files are all in var/www/ DNS pointed service ip to Any thoughts on why is the case?


    • Dave H.
      August 10, 2019 @ 9:43 am

      Sounds like you need to change /home/ in the nginx sites-available file to point to /var/www/

  105. vicky
    August 12, 2019 @ 12:21 am

    Thank you, it worked!
    But after I install the ssl using certbot –nginx, nginx started giving the error:

    conflicting server name “” on, ignored

    I checked all .conf files under sites-available and there are no duplicating files or “listen 80”

    Any thoughts?

    • Ismail
      August 13, 2019 @ 12:29 pm

      Redis will be a droptemt server ? Or on same webserver can need to install radix?

      • Dave H.
        August 13, 2019 @ 5:53 pm

        You can install redis wherever you like, but typically you’ll install it on your web server.

      • Ismail
        August 22, 2019 @ 7:02 pm

        Cant config , how much you charge for stack config,?

        • Dave H.
          August 25, 2019 @ 10:38 am

          I don’t do custom stack builds for customers any more. Pretty much all of them expected me to then manage the site maintenance for them which I have no interest in doing.

          I can recommend Gridpane. It’s a little more technical minded than most managed services, but if you can handle that you get superb performance.

    • Dave H.
      August 13, 2019 @ 5:54 pm

      Maybe you have two default servers in your nginx files? Or maybe you have two sections in a single file for the same domain listening on port 80?

  106. Diego
    August 13, 2019 @ 11:06 pm

    Hi, I’ve been using your stack for a long time. I always liked it. It works excellently well. But only today did I realize that price filtering and other elements don’t work.

    There are no issues with woocommerce, the theme and plugins .. because I tested raw wordpress. And I have the same problem.
    Could you help me adjust this?

    wp-admin / edit.php? post_type = product & orderby = price & order = desc

    • Dave H.
      August 25, 2019 @ 10:40 am

      I have no issues with price filtering or anything else and this is the first report I’ve had about this.

      Can you provide access and a URL where I can see what you’re meaning? Then I’ll be able to debug. Contact me through [email protected].

  107. estreetz
    August 21, 2019 @ 4:32 pm

    Hi Dave,

    I try to optimize Mysql
    but when I try to use
    I got this message “authentication message”

    root@nova-deals:~/ ./

    Using login values from ~/.my.cnf
    Testing for stored webmin passwords:
    None Found
    Could not auto detect login info!
    Found potential sockets: /var/run/mysqld/mysqld.sock
    Using: /var/run/mysqld/mysqld.sock
    Would you like to provide a different socket?: [y/N]

    Can you help me?

    Thank You

    • Dave H.
      August 21, 2019 @ 6:33 pm

      If you choose N then it should ask you next if it should create a ~/.my.cnf file for you. Once it does, edit this file and enter your username and password creds then re-run the script.

      • Guest
        August 22, 2019 @ 12:55 pm

        What’s happening with WP Intense?

        Are you planning to:
        1. hire new developers
        2. fix the bugs
        3. add feature requests

        • Dave H.
          August 25, 2019 @ 10:07 am

          Yes to all of these. There are many changes coming, but the investment I need to hire devs has stalled. It should be here this month.

          Right as of this minute I’m working on some bug fixes for FWW, a paid feature request for external images and also I have an updated website coming soon which includes buddypress with the idea being that site-wide activity will be far more visible including bug fixes, additions to changelog, feature requests, forum posts etc.

          • Guest
            August 25, 2019 @ 11:32 am

            I highly recommend this developer:

            Maybe you can work together.

          • Dave H.
            September 15, 2019 @ 4:17 pm

            I’ve messaged him. Thanks. Got a few other interested parties. Hopefully have someone on board next week.

          • Guest
            September 28, 2019 @ 5:29 pm

            I don’t see any progress toward fixing bugs or adding new features.

          • Dave H.
            October 2, 2019 @ 12:41 pm

            There was a minor upgrade to FWW last week and our new developer is continuing with bug fixes on that plugin as he familiarises himself.

          • Guest
            October 3, 2019 @ 8:55 pm

            Come on, this is ridiculous. Little or nothing has been done in the last months. Small CSS changes and there is still a bug:

          • Dave H.
            October 21, 2019 @ 5:31 pm

            That’s fair, but onboarding the new dev is taking longer than anticipated. In any case, I am now freed up to develop again too this week, so you’ll see movement finally.

            It’d help me if you keep these comments to specific feature requests or in the forum rather than on this unrelated article.

          • Guest
            October 21, 2019 @ 8:34 pm

            Good to see you back! I think this is the most urgent FWW feature request:


            I’m aware of it but it’s hard to reach you. Please delete this comment after reading it.

          • Dave H.
            December 18, 2019 @ 8:58 am

            I know this is highly desired. I’ve implemented the basics of this but it comes with many bugs so I’ve removed it for now so I can release other FWW bug fixes and improvements, coming out this week hopefully.

          • Krzysztof T.
            November 22, 2019 @ 1:59 pm

            It’s hard to reach you. If you don’t mind, may I ask when are you coming back to work? I’m waiting for the FWW update. When finally comes the long-awaited update? I wait and wait and nothing comes.


  108. Vicky
    September 22, 2019 @ 10:49 am

    Hi Dave, I have the same issue as some others above, the website worked, until I ran certbot –nginx
    I got the “Congratulations! etc\” message but the website wasn\’t able to be connected.
    DNS is correct, cloud icon on Cloudflare is grey, I used \”flexible ssl\” on Cloudflare.
    Anything else I can troubleshoot?

    • Dave H.
      October 2, 2019 @ 12:40 pm

      If you use the ‘flexible SSL’ it will access your site through HTTP not HTTPS. You should use FULL but not FULL STRICT. Full will mean you use the Cloudflare SSL on front-end and then communication between Cloudflare and your server will be over your Letsencrypt SSL cert.

  109. Drop
    September 24, 2019 @ 8:43 am

    Hi Dave, I keep getting: ERR_CONNECTION_CLOSED after running certbot, cloudflare it’s deactivated acting only as a dns service.

    I also tried reissuing the certificate.

    Any idea why this might happen ?

    • Dave H.
      October 2, 2019 @ 12:41 pm

      Try switching to FULL (not STRICT) SSL with Cloudflare. Presumably you enabled the option to redirect non-HTTP to HTTPS with certbot.

  110. Denis
    October 1, 2019 @ 1:19 pm

    Hello! I’m using Centos 7, instead of Ubuntu, since it’s more stable.
    Also, there is some troubles with MySQL8 and WP, so MariaDB is more stable too.

    Please look for this stack and maybe you can make another guide for Centos?

    • Dave H.
      October 2, 2019 @ 12:43 pm

      Hi – I find CentOS a pain to be honest, and the argument about it being more stable doesn’t apply to this stack. Having said that, I have helped someone else install it all on CentOS and basically you’re swapping out apt-get for yum to install each component.

      Also – CentOS puts config files in different places, but if you use the find command then that will help, e.g. find . -name redis.conf

  111. Ronaldo
    October 4, 2019 @ 11:58 pm

    I love you. That’s all I have to say.

    • Dave H.
      October 21, 2019 @ 5:30 pm

      Thank you! I love you too 🙂

  112. Mostafa
    October 26, 2019 @ 2:09 pm

    Hi Dave, Thank you;

    I need to create a site in a subdirectory ( ). is a WordPress and site2 is a WordPress; how can I do that? we have one FastCGI cache path for 2 different sites, is it bad for my site? please help me at this situation;

  113. Pavel
    October 27, 2019 @ 10:24 am

    Hello Dave,

    Great WordPress stack!

    I was woundering if you any one else here have any experince with Litespeed? And if so whats your thoughts on it?

    It seams very interesting as it has a native cache plugin (LS cache) with many other wordpress optimisation options, for free. Their enterprise vertion (server with under 2gb ram is free) has a Quic (http/3) option. All the tests i have seen on the web show it to be faster than Nginx.

    So if you or any one else here have any experinse with Litespeed, please let mr know? What r your thoughts on it?

    P.S. Stay fast!

    Best regards,

    • Dave H.
      October 29, 2019 @ 5:43 pm

      If you’re looking for a managed service, Gridpane have the fastest managed service out there. You can deploy to loads of places – Digital Ocean, AWS etc.

  114. harvey m.
    November 11, 2019 @ 7:55 pm

    Hi, Dave, Great to see you are back!

    Just curious, is this stack really secure by itself, or is there anything else like firewalls etc that I should be implementing? This is my first linux stack build.. Thanks!

  115. Amir
    November 12, 2019 @ 11:18 pm

    Hi, Thanks Dave for this great stack,
    i followed the steps but i am stuck at “Now your web server is ready for traffic, so visit in your browser and check that you see the following:”
    I don’t see 404 not found, i see “This site can’t be reached”

    what i am doing wrong

    • Dave H.
      December 18, 2019 @ 8:53 am

      Make sure you have DNS pointing to the server and try restarting nginx.

  116. Ronaldo Scotti
    November 14, 2019 @ 12:54 pm

    Hi Dave! I’ve this setup working on a WP Multisite for the past month, but I’m running into a problem when adding a custom domain to a subsite. I cant log in after changing the domain. To be totally precise: I am being logged in (have debugged to be sure of this), but i’m being served a cached version of the website and cant access the wp-admin area.

    I’ve tried to empty cloudflare cache, tried to empty nginx cache, but with no luck. What can it be the problem? Thanks!

    • Dave H.
      December 18, 2019 @ 8:52 am

      I’m not sure with multisite – maybe try disabled the nginx cache completely and test that? In the file you can change this:

      # Don't skip by default
      set $skip_cache 0;


      # Don't skip by default
      set $skip_cache 1;

      Then check if it’s letting you log in. If it does, that’ll confirm it’s the nginx cache that’s the problem for multisite and probably then you’ll need to add a better cache key – currently:

      fastcgi_cache_key “$scheme$request_method$host$request_uri”;

      If you have a domain variable, you could add that to the key.

      • Ronaldo Scotti
        December 30, 2019 @ 2:36 pm

        Hi Dave!

        In the end it was a WordPress cookie issue. But thanks anyway!

  117. Joel
    November 29, 2019 @ 4:45 am

    Wouldn’t it be better to have a separate managed database engine from Digital Ocean? Or would the performance be the same? I’m thinking I need it for remote access. The db processes can be run on my local machine and I just update the remote db.

    • Dave H.
      December 18, 2019 @ 8:10 am

      I haven’t tested using a separate managed db engine yet from digital ocean but it’s on my list of things to test.

  118. kent
    December 15, 2019 @ 4:11 am

    Hi, I just stumbled across this guide, and was wondering if I can use it in conjunction with virtualmin? I want to host multiple WordPress sites on one server. Is this possible? I am a newb at this so not sure where to start…

    • Dave H.
      December 18, 2019 @ 7:58 am

      Yes it will work – you would still benefit from having MySQL 8, PHP 7.3, Redis and Nginx. Virtualmin would be used just to create databases & configure the website info in nginx.

      It looks like it’s compatible with Ubuntu 18 so just install it and try it out.

  119. Alan Tygel
    December 24, 2019 @ 2:31 pm


    First of all, thank you very much for this guide! Awesome work!

    I want to give a small contribution, on how to change nginx and php-fpm users. My website runs some git repos, and I need to manage them with my own user.

    I changed the following configurations:
    1) /etc/nginx/nginx.conf
    changed the line:
    user www-data;

    2) /etc/php/7.3/fpm/pool.d/www.conf
    changed the lines:
    user = www-data
    group = www-data

    listen.owner = www-data = www-data

    3) Change the permissions of the following folders:
    sudo chown myuser:mygroup -R /var/lib/nginx/fastcgi/*
    sudo chown myuser:mygroup -R /var/www/cache/mycache

    4) Restart nginx and php-fpm
    sudo service php7.3-fpm restart
    sudo service nginx restart

    thats it!


    • Dave H.
      January 15, 2020 @ 7:14 pm

      This is great! Thanks for helping out.

  120. kent
    December 26, 2019 @ 3:24 am

    Thanks! Are there any steps in this guide that I should leave out or change, if I am using Virtualmin? Also, I am only going to be hosting one website on the server. Do you recommend I use Virtualmin or just Webmin

    Thank you.

    • Dave H.
      January 15, 2020 @ 7:13 pm

      No keep everything in the guide. I don’t have recommendations though for virtualmin vs webmin because I don’t use either. Maybe one of my readers can help you.

  121. Dicko
    December 27, 2019 @ 12:35 pm

    Hi Dave, thank you so much for the guide.. Question though, on Firefox, when I opened the homepage of the site, the header says Fastcgi-Cache: BYPASS. While on Chrome, it says Fastcgi-Cache: HIT. Does this mean on Firefox, Fastcgi is not working? I tried on the homepage, because when I try to open a static asset like CSS, the Fastcgi-Cache header is not showing, not sure why.

    Thanks again.

    • Dave H.
      January 15, 2020 @ 7:12 pm

      Probably when you opened in firefox the first time it wasn’t cached yet – try refreshing in firefox and you should see the cache hit.

      • Dicko
        January 21, 2020 @ 4:55 pm

        I’ve refreshed the page several times, but it still says BYPASS. I noticed this line:

        Cache-Control: no-transform, no-cache, no-store, must-revalidate

        but I’m not sure where this is coming from. On Chrome, this line doesn’t exist. I didn’t modify anything from your guide, so I think this must be some kind of default settings that comes from somewhere.

      • Dicko
        January 27, 2020 @ 7:13 am

        Sorry Dave, my previous comment is inaccurate. Turned out it’s not because I’m using Firefox, but it’s because I’m “logged in” when using Firefox (doh!). I found this snippets in fastcgi-cache.conf:

        # Don’t use the cache for cookied logged in users or recent commenters
        if ($http_cookie ~* “comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|woocommerce_cart_hash|woocommerce_items_in_cart”)$
        set $skip_cache 1;

        I think this is the one causing Firefox to BYPASS cache. My question is, can this snippet modified to allow cache for “logged in” customers, except when they’re adding items to cart, checking out, or doing other woocommerce related functions? For admins, no problem, we’re good without cache.

        • Dave H.
          February 3, 2020 @ 6:14 pm

          If you remove wordpress_logged_in| from the line, it will not skip the cache for logged in users, unless one of the other cookies exists (comments, cart etc).

          If you want to disable the cache for admins only, you will need to add a function to the login hook. This function would check if the user is admin, then set one of the other cookies which would bypass the page cache – e.g. you could set wordpress_no_cache (doesn’t matter the value you give it, only that it exists)

          You should also delete the cookie on logout. There’s a stackoverflow with the two functions you’d need here – just change the cookie name:

          • Dicko
            March 9, 2020 @ 10:47 am

            Thanks Dave, all working fine now! Really appreciate the help.

  122. John C.
    December 29, 2019 @ 1:55 pm

    Dave, i success followed your tutorial installing the fastest wordpress stack. But unfortunately i found problem since my blog is dinamyc/news. It won’t show latest post in homepage, i think is because Nginx FastCGI Cache. I can’t purge cache. Please help!

    • Dave H.
      January 15, 2020 @ 7:11 pm

      You can change how long the the nginx fastcgi cache lasts for. Also, new posts *should* automatically wipe the nginx cache but alternatively you can install the nginx plugin to allow you to manually flush the cache.

  123. korng
    January 29, 2020 @ 1:12 pm


    It would be great if you can make a tutorial about how to install googlepage speed module with this wordpress stack,


  124. Ehtisham
    February 9, 2020 @ 12:08 pm

    i have installed the above stack all is fine but when working with post like update ,draft publish it takes too much time . help me out please . i am sending you screenshot of htop as well.

    • Dave H.
      February 13, 2020 @ 10:12 pm

      This will be caused by one of your plugins. I recommend you install query monitor and view queries by time and by component on the page after you update the post.

  125. Jay
    February 20, 2020 @ 7:36 pm

    Hi Dave, I hope you’re doing well. I’ve followed this guide and it’s working a treat. I want to explore this 1 million products in Woocommerce concept that you are championing. I also want to provide some advice to you, and have reached out to you through intercom and through skype. I read your dev-diary about wanting to move away from intercom, so please let me know if there is a better way to reach you. Thanks and looking forward to connecting with you.

    • Dave H.
      March 9, 2020 @ 11:28 am

      Thanks for getting in touch. There will be an update out shortly with better means of communication. If you’re an existing customer, you can raise a ticket here: If you’re a new customer, you can email [email protected]. I’ll be migrating away from intercom today probably, so these emails will be arriving directly at my gmail inbox instead.

  126. sayan
    February 23, 2020 @ 3:51 pm

    Hi. followed these steps to create my website, also created a subfolder by creating a separate mysql db. Last night, everything was working fine. Today I see if I open a blog suppose it redirects to the primary domain and shows post does not exist. While I can log in to the subfolder website, but only posts are being redirected to the primary domain. Can you help me out?

    • Dave H.
      March 9, 2020 @ 11:22 am

      You’ll need a separate nginx entry for your 2nd website.

  127. Brandon A
    March 30, 2020 @ 5:02 pm

    Great guide thanks.

    I have one issue so far. I moved some image files to new locations and redirected the old links. The redirect goes to an NGINX 404 instead of being redirected in WordPress. I feel like NGINX should hand these 404’s over to WordPress, like it does for all of our other redirects. I am using an SEO redirect plugin which works for page redirects, but isn’t for images.

    What am I missing, is it something in NGINX that I can add?


  128. uma saha
    April 6, 2020 @ 2:01 pm

    Hey i followed this tutorial, but i installed php7.4 instead of php 7.3 version. Now i see my website page loading time increased by 20-40% in the new server? is the php version causing any issues? shall i downgrade to php 7.3?

    • Dave H.
      April 6, 2020 @ 3:17 pm

      That sounds odd. I guess it’s possible that something got full deprecated in 7.4 and this has broken a speed plugin you have?

      Which speed/caching plugins are you using?

      • Matthew Clary
        April 6, 2020 @ 9:20 pm

        I wasted a lot of time trying to use MariaDB and php7.4 with the rest of your tutorial. I couldn’t figure it out. I gave up and used your recommended stack with 7.3. Not figuring it out is not sitting well with me and I think I will use a different droplet and ( try to ) figure it out a little later.

  129. Shawn
    April 7, 2020 @ 8:06 pm

    Hi, thanks for the tutorial. I have one question, and one comment.

    I’ve had my server running for awhile now (vultr 1vcore, 1gb ram) with a very low traffic site, and just revisited this tutorial for memory cleanup because apt-get was failing. I ended up setting php processes to ondemand, to try and fix the issue, because I’m a newb. 10 children were running @30mb ea, so my line of thinking was this would free up ~300mb of ram. Am I on the right track?

    Secondly, I noticed that /etc/nginx/sites-available/rocketstack.conf includes the snippet security.conf by default.
    When I checked out security.conf, these two lines jumped out at me:
    # uncomment out if you are ussing https/SSL
    # add_header Content-Security-Policy “default-src ‘self’ https: data: ‘unsafe-inline’ ‘unsafe-eval’ ;” always;

    I was wondering if I should uncomment this, and if so, if you wanted to mention it in the tutorial because you go over https/SSL in the tutorial?

    • Dave H.
      April 7, 2020 @ 9:58 pm

      Yeah ondemand is useful – particularly because it fixes any memory leaks you may have. Basically the worker threads are constantly getting killed and restarted fresh, as needed, so it will definitely save you memory.

      re: the security policy, I didn’t enable it by default because it could theoretically break some plugins. It will make your site more secure and less vulnerable to any malware that may try to install itself – more specifically, it’ll make your site more secure against the impacts of an infected. You’ll need to test adding it with your site.

      • Shawn
        April 9, 2020 @ 4:29 pm

        Understood. Thanks for the reply!

  130. Michael
    April 12, 2020 @ 7:04 pm


    What re your thoughts using this stack but swapping out certain areas with OpenLiteSpeed + LSCache? I have been benchmarking 20+ sites with different configurations and so far running LS+FastCGI, MariaDB, Redis, CDN with QUIC Cloud for most of the site, and CDN with Cloudinary (site pulls in countless images that need quick optimizing, then using s3 Offload into a bucket after x amount of weeks) with A.I meta needed. I’m getting close to as perfect as I can make it, and then want to rollout the stack with LXD containers for each client site, thoughts? I also been doing a lot of DNS testing and I know cloudflare has great DNS, however, I see many cases when im using Route 53 thats increasing speed (I know its not a major difference, but overall every little tweak adds up in the long run) just wanted your thoughts about this and LS and how things are different in 2020? Cheers mate.

    • Dave H.
      April 14, 2020 @ 9:57 pm

      I’ve yet to test with Litespeed – I’ve heard good things. I’ll be running my own comparisons once I get a bunch of plugin updates out the door.

      • Michael
        April 30, 2020 @ 6:20 pm

        thanks let me know when you do, so interested

  131. Timmy
    April 12, 2020 @ 9:30 pm

    Hi Dave, is it possible to use both the CDN KeyCDN and Cloudflare at the same time? I mean is it worth it or the Cloudflare is enough?

    • Dave H.
      April 14, 2020 @ 9:56 pm

      You should just use the one CDN really. If you like KeyCDN then use them, some people report issues sometimes with Cloudflare but to be honest given the size of them there will be issues for some users.

      • Timmy
        April 15, 2020 @ 10:02 am

        Thank you!
        Another question, do I need a cache plugin with server-side cache (FastCGI)?

        • Timmy
          April 15, 2020 @ 10:04 am

          I’m talking about caching by WP-Rocket only and trick Nginx to serve those cache without hitting PHP?

          • Dave H.
            April 24, 2020 @ 11:12 am

            If I were you, I’d disable the page caching in WP Rocket as it’s wasteful when you have Nginx handling it for you. The Nginx helper plugin can be useful to clear the page cache.

            Bear in mind, WP Rocket doesn’t include an object cache which is really the most critical cache in WordPress.

  132. harvey m.
    April 17, 2020 @ 6:20 am

    Hi Dave,

    What’s your take on Nginx vs OpenLiteSpeed for WordPress?

  133. Shawn
    April 24, 2020 @ 2:59 am

    I’ve been keeping the local php.ini version when upgrading packages. Should I be periodically checking version differences in the php.ini-production.cli and merging them manually? What is the best practice? Sorry for the noob question.

    • Dave H.
      April 24, 2020 @ 11:07 am

      You should keep the local php.ini version when upgrading so you retain all your changes from the default settings.

  134. Gowtham
    April 28, 2020 @ 9:37 am

    Awesome post this improved by site server speed a lot for my wp site.

  135. Jake Austwick
    April 30, 2020 @ 2:46 pm

    With this caching setup, will it be automatically cleared when it needs to be?

    New Page/Post (or edit)
    New Comment

    • Dave H.
      April 30, 2020 @ 3:27 pm

      For users logged in, or commenters, they will see the uncached page (i.e. they will see fresh comments) but for users logged out it will take until the nginx page cache expires before they see the new comments (if the page was in the cache before this extra user commented)

      For new pages, these have never been cached before, so the main issue here is that your archive will not show the new page in the archive for 60 minutes (if your archive page has been cached inside the last 60 minutes). You can decrease this if you wish in the nginx config file for your site. You can also flush the nginx cache manually using the WordPress Nginx plugin.

      You can also use ajax comments if you wish since ajax is never cached, so then users would see that being up to date.

      My next stack build will include a selective page caching system so that rather than flushing the entire cache, it will be possible to automatically flush your archive pages but leave everything else cached.

  136. Gowtham
    May 2, 2020 @ 11:51 am

    Does this work in 2020 with the latest ubuntu version and updates .Kindly let me know if there is an updated version of the post for 2020 ?

    • Shawn
      May 3, 2020 @ 10:36 am

      I’m just starting this process, so far I’ve needed to grab the latest mysql for compatibility: mysql-apt-config_0.8.15-1_all.deb

      • Shawn
        May 3, 2020 @ 1:09 pm

        Ubuntu 20.04: certbot is currently broken. Adding SSL Using LetsEncrypt is as far as I got. Nameservers are still moving so I’ll get back to it tomorrow.

        #apt-get install python-certbot-nginx

        Looks like there is a sketchy workaround, but that it should be fixed soon?

        Here’s some relevant reading…

        • Dave H.
          May 3, 2020 @ 4:09 pm

          Yeah Ubuntu 20 only got released a week ago, so it’ll probably be another few weeks before all the other software items are available.

          • Shawn
            May 4, 2020 @ 9:22 am

            I went with the sketchy workaround, and have the site up and running now after some SSL troubleshooting. Looking forward to a fresh guide!

          • Dave H.
            May 4, 2020 @ 11:48 am

            Great! How is it so far?

    • Dave H.
      May 3, 2020 @ 3:47 pm

      Not tested it yet. I’ll build a fresh guide soon. Main difference is PHP 7.4 is the default version.

  137. Abhi George
    May 5, 2020 @ 5:27 pm

    How to hide .user.ini on this stack. I’ve tried some methods. But nothing work all.

    • Dave H.
      May 6, 2020 @ 12:36 am

      I’m not sure where you’re .user.ini file is coming from, but you can add a rule to nginx server {} blocks like this:

      location ~ \.user\.ini$ {
      deny all;

  138. Shawn
    May 7, 2020 @ 5:03 am

    Hi Dave – responding to your comment here because our nested convo didn’t have a reply option.

    20.04 is running smoothly so far with just the certbot fix, and I’m now getting into hardening for wordpress. I’m very much a novice dev (no formal education, only made 3 sites so far) so I don’t have much to comment on about speed, reliability, etc as I don’t know what to look for or test for.

    Something I just came across in the ssl.conf snippet:

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    This appears to be out of date, will you be updating the snippets as well when you make the next guide?

  139. foguii
    May 10, 2020 @ 11:29 pm

    Hi there, fantastic stack and tutorial thank you!

    With the above all up and running (with gzip enabled, and proxied via Cloudflare), is there any point in having:
    1. Autoptimize to minify and aggregate CSS + JS (either/or?)
    2. WP-Optimize which has an option to preload the whole site and serve a cache version.

    Chrome’s lighthouse and seem to think the results are better… with the above, but these aren’t based on real user experience…

    • Dave H.
      May 14, 2020 @ 2:04 am

      1. Either Autoptimize or alternatively you can minify using Cloudflare – it works pretty well and has some good stuff for moving javascript further down the page to improve page speed.

      2. Sure – a cache primer is good, but having an extra page-caching system is mostly redundant as nginx will serve up the cached page before it hits WP-Optimize’s version.

  140. Shawn
    May 13, 2020 @ 8:58 pm

    Hi Dave, I’m trying to interpret the options for securing PHP requests. Would it be redundant to set cgi.fix_pathinfo=0 in my php.ini? Your rocketstack exclusions snippet already denies access to .php files in */uploads?


    • Dave H.
      May 14, 2020 @ 12:42 pm

      You should add it, I always advocate belt & braces but to be honest this should have been in the security part.

      The particular vulnerability here is quite complicated to reach – you need to have a vulnerable plugin which allows someone malicious to alter wp-config.php or similar, upload an image, then execute the image – the image actually contains PHP code. But it is a vulnerability so yes you should add it.

      I’ve added this info to the new DOC trello card for the next article:

      • Shawn
        May 14, 2020 @ 6:21 pm

        Thanks, I like the belt & braces phrase haha. Cool, I’ll check out the trello card!

        • Dave H.
          May 21, 2020 @ 10:15 pm

          Hah – I didn’t realise this was a British-specific phrase.

  141. Eric Chan
    May 15, 2020 @ 2:42 am

    Probably the best wordpress tutorial! The virtual host conf and all the snippets in your github is really organized, really appreciate about your work!

    Right now, I am trying to host mutiple wordpress sites into a vps, the redis server is caching the sites incorrectly, should be because I haven’t configured it properly, need some more time to study about how to set it up.

    • Dave H.
      May 21, 2020 @ 10:13 pm

      You can either change the wp_ database prefix in wp-config.php for each website but you’d have to change each table you already have in those databases.

      Alternatively, you can use different redis databases for each site and just choose the relevant database in the Till Krus Redis plugin – the default redis database is database(0), and by default Redis has 16 ‘databases’ already for you. If you need more databases for more than 16 sites, check this guide:

      To configure each website to use its own Redis database, you can add this to wp-config.php:


      (the default is 0, and the default max is 15 giving a total of 16 Redis databases available by default)

  142. Abhirup
    May 15, 2020 @ 3:32 am

    Which Php version should I use for my website currently using 7.3? should I upgrade to 7.4?

    • Dave H.
      May 21, 2020 @ 10:05 pm

      There’s really not much perf improvement in my experience – maybe 2 or 3% speed improvement which is very difficult to observe in practice. But yes, my future guide will use PHP 7.4 so feel free to install that instead of PHP 7.3.

  143. Alan Tygel
    May 16, 2020 @ 11:46 pm

    Hi Dave H.,

    First of all, thank you so much for the guide.

    Sometimes, when I deploy a server with several wordpress sites using this guide, I get a PR_END_OF_FILE_ERROR .

    I don’t know exactly when I comes, neither how I solved. I try to disable some sites, and then enable one by one, and finally somehow it works.

    Do you have any explanation for this?

    • Dave H.
      May 21, 2020 @ 10:04 pm

      That’s very odd. Never seen that before. Possibly your server is running out of RAM? From a Google search it seems this is related to Firefox addons – maybe try disabling them and trying again?

  144. Diego
    May 23, 2020 @ 12:25 am

    I used your configuration for a long time but it was overcome by the openlightspeed stack.
    I still believe in you and I wanted to see something new for 2020. Could you do that? It would be a great pleasure to implement your configuration. Thank you

    • Dave H.
      May 23, 2020 @ 2:05 am

      I’ll be running new benchmarks in june or july, comparing hosts along with a brand new fastest stack build for 2020.

      Litespeed will definitely be getting reviewed, primarily for the selective cache purge and the cached gzip of files.

      • Diego Castro
        May 24, 2020 @ 11:10 pm

        Hey, I can’t wait to see something new.
        I am disappointed with Litespeed, as it is consuming almost 100% of the CPU .. it is a faster option, but it requires a lot of resources.

        • Dave H.
          May 25, 2020 @ 8:40 pm

          If it’s consuming all your CPU, it may be ‘faster’ but it’s not more scalable. And technically, if nginx uses 5% CPU and litespeed uses 100%, then it’s not actually faster, it’s just better at using all the CPU.

          I’ll check all this in my future guide – if you can provide any more info about what litespeed is doing to consume 100% CPU that would be very useful – maybe it’s pre-preparing gzips of static files?

          • Diego Castro
            July 16, 2020 @ 5:59 pm

            looking for the new stack.

          • Dave H.
            July 22, 2020 @ 4:02 pm

            My current road map is: Faster Woo Widgets update, another Super Speedy Search update, then thorough docs and videos for everything, THEN I’m doing a new hosting stack alongside a hosting comparison of the best hosting options out there.

  145. Stephan Pire
    May 27, 2020 @ 1:59 pm

    Once again Dave, this whole Stack post is plain Gold. We’re happy to promote your work to our Clients.

    We would be interested to know also what’s your recommendation for the Media offload on S3. We are using, but it’s heavy.

  146. Stephan Pire
    May 27, 2020 @ 5:54 pm


    My main issue was with WP All Import, but your explanation on what to do on wp-config (define(‘WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY’, ‘../wpallimport’);) may be helping.

    I will try this on, which carries 150k products.

  147. simon
    June 27, 2020 @ 3:42 am

    Hi Dave,

    Looking forward to reading an Ubuntu 20.04 version of your rocketstack.

    In the meanwhile I just built a fresh one with Ubuntu 20.04, keeping this guide for general direction.

    I didn’t add mysql and ondrej repositories.

    I went with the MySQL 8 default, then run mysql_secure_installation.

    Changed root of mysql to native with

    >ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘password’;

    but I did add the file


    It wasn’t there by default, but I guess it won’t hurt.

    Went with the default php7.4


    When trying to start nginx there was an error, a very trivial one though:

    The server block is missing ssl_certificate and ssl_certificate_key statements.

    There are two commented lines with the future letsencrypt statements, which at that point of the procedure aren’t there yet.

    Apparently the nginx server would have started untli very recent versions even without valid ssl_certificate and ssl_certificate_key statements, then you would letsencrypt-auto it, so the problem would never come out. Now it spits an error when you try to start the server the first time.

    A temporary simple way out: comment out the whole ssl server block just to test the installation with http.

    After this long preamble, my question/request: I have a single public IP address, my firewall NATs tcp 80 and 443 to an internal reverse proxy based on nginx with letsencrypt and all the customizations needed to work with wordpress.

    This single reverse proxy points to several wordpress sites (something I couldn’t easily do with apache, which I am much more used to), each with its own dedicated stack on a dedicated server and sitting in my private LAN. I am content with running them all on http and let the single reverse proxy do all the SSL.

    In a way I am “decoupling” the nginx role, SSL reverse proxy and web server.

    Do you think it would be possible to let me know where your optimizations should be applied in this scenario? At the moment I will test them all in the internal wordpress stack and leave the reverse proxy alone, maybe just trying with caching enabled or caching disabled.

    Please let me know your thoughts when you have time.

    Keep up the good work, it’s really inspiring,



    • Dave H.
      June 30, 2020 @ 2:05 pm

      If each site has its own dedicated server and stack then apply the optimisations there. Nginx is really fast out of the box as a reverse proxy.

  148. Rick
    September 27, 2020 @ 2:40 pm

    Thanks for this amazing guide, this is by far the best wordpress setup I have ever tried !

    Lost 2 days trying to figure out why a woocommerce setup wouldn’t go any lower than 2.5 sec TTFB and tried everything without success !! Multiple cache plugins, Database tuning, CDN, running new relic and query monitor to try identify the issue but everything seemed to point out a bottleneck at php level .

    Then I came across this guide and decided to give it a try … I have to say I am very impressed with the results !

    I have a fairly heavy woocommerce website and I’m getting a wooping 130-150ms TTFB average, that’s even better than a fresh wordpress install usually gets with just cache + CDN optimization .

    Life saver ! 🙂

    • Dave H.
      October 2, 2020 @ 8:39 am

      Thank you! I’m glad you’re happy – I’m aware it’s quite daunting at first to build your own stack and I probably will at some point make an automated build for all this, but there’s a big benefit to going through the steps yourself so you understand your own stack a lot more.

      Remember to check out my plugins too once your store gets bigger as even with this stack WooCommerce will slow down once it gets bigger unless you use our plugins.

  149. Tony
    September 30, 2020 @ 4:36 pm

    Hi Dave,

    Thanks for the guide.

    I encountered a couple of issues:

    1) At the step of installing and running tuning primer it says:
    Using login values from ~/.my.cnf
    Testing for stored webmin passwords:
    None Found
    Could not auto detect login info!
    Found potential sockets: /var/run/mysqld/mysqlx.sock
    Using: /var/run/mysqld/mysqld.sock
    Would you like to provide a different socket?: [y/N] N
    Do you have your login handy ? [y/N] : y
    User: root
    Would you like me to create a ~/.my.cnf file for you? If you answer ‘N’,
    then I’ll create a secure, temporary one instead. [y/N] : y
    Unable to log into socket: /var/run/mysqld/mysqld.sock

    2) When I installed mysql tuner instead, it has a lot of these errors:

    [!!] FAIL Execute SQL / return code: 256
    [!!] failed to execute: SELECT CONCAT(user, ‘@’, host) FROM mysql.user WHERE password = PASSWORD(‘root-password’) OR password = PASSWORD(UPPER(‘root-password’)) OR password = PASSWORD(CONCAT(UPPER(LEFT(‘root-password’, 1)), SUBSTRING(‘root-password’, 2, LENGTH(‘root-password’))))
    [!!] FAIL Execute SQL / return code: 256

    Any suggestions please?

  150. Tony
    October 1, 2020 @ 10:28 am

    Hi Dave,

    Thanks for the guide.

    I had no major issues but now when I create a subdomain in nginx, it always redirects to the main domain?

    Any reason why?

    Been on the web for hours and following guides but it just does not work to create any subdomnain.


    • Dave H.
      October 2, 2020 @ 9:14 am

      1. Create a second file in /etc/nginx/sites-available/ and configure it for 2nd domain
      2. Ensure there is a symbolic link to this file in /etc/nginx/sites-enabled/
      3. Restart nginx

      To configure the 2nd domain:

      1. Change the server names server_name directive
      2. Change log path locations
      3. Change cache locations
      4. Generate fresh SSL

  151. Sommie
    October 8, 2020 @ 2:48 pm

    It’s been two years and this guide remains my bible for setting up new website/server instances.
    However, when my website receives heavy traffic, say over 20K users per day, I keep getting this error:
    502 Bad Gateway

    There isn’t much going on the website. Just two gravity forms that users fill.
    I can confirm that this is not a website software issue and I suspect that this is happening with NGINX/PHP-FPM.

    What would you recommend in this situation?

    • Dave H.
      October 15, 2020 @ 8:14 am

      You might want to check your RAM consumption on the server. If you run the topcommand through SSH, you’ll see your PHP processes.

      If you see some of them consuming a lot of RAM then you probably have a memory leak. Quickest and easiest way to fix that (other than finding the leak) is to recycle your PHP processes.

      You could switch your PHP config to this:

      pm = ondemand
      pm.max_children = 32
      pm.process_idle_timeout = 3s

      ondemand rather than static will ensure the PHP processes get recycled. You’ll probably see a slightly slower speed when your site hasn’t had visitors in a while, but you should see higher overall capacity.

  152. Andreas
    December 22, 2020 @ 10:48 pm

    Thank you for this wonderful guide, i implemented it on a couple of projects now and it’s working really well with wordpress and woocommerce. I also built your optimizations into my ansible playbooks, so deploying and maintaining my infrastructure is now a breeze. What I’m using also as an extra is Optimus Cache Prime which fills the cache via a cronjob, so the visitors get almost always the cached version of the page.

    So again, nice job and thank you

    • Dave H.
      December 30, 2020 @ 6:58 am

      Thank you – I’m sure some of my readers would appreciate it if you shared a github link to your ansible playbooks.

  153. Jonathan d.
    January 25, 2021 @ 11:54 pm

    Hi Dave,

    I see that Digital Ocean has a WordPress droplet out of the box – is that worth running to save time on some of the steps in this guide?


  154. Jonathan d.
    January 26, 2021 @ 8:37 am

    I’ve run the steps, and whilst doing the certbot (letsencrypt) part, it said that ppa was deprecated:

    #add-apt-repository ppa:certbot/certbot
    The PPA has been DEPRECATED.

    To get up to date instructions on how to get certbot for your systems, please see
    More info:

    It still worked, but I thought I’d mention it in case you need to update your guide.

    • Dave H.
      March 2, 2021 @ 4:03 pm

      Thanks – that’ll be very useful for others. I’ve got a fresh guide for Ubuntu 20.04 in the works, probably coming out in May.

  155. Armando Rivero
    March 19, 2021 @ 10:50 pm

    Hello Dave,

    I’ve been using your stack for a few years now and it’s just freaking genius.
    Recently I decided to integrate it with Bedrock and dockerize it.

    If you find it interesting here’s the description.

    Thanks for your great work!

  156. Thadeu Furtado Barros
    May 15, 2021 @ 11:47 pm

    Thanks for you time, very useful. I want to ask, do you think is possible have this level of power using vesta-cp? I manage a some sites and could be fine to have some automation. Today I use it on DO.

    • Dave H.
      May 17, 2021 @ 10:29 am

      Yeah I don’t see why not – it’s an open source control panel so I’m sure it could be modified to install and configure this stack. Would be very cool.