Blog

  • WordPress Cloud Image FAQ

    WordPress Cloud Image FAQ

    WordPress Cloud Image FAQ

    LiteSpeed cloud images allow you to spin up a high performance web server and applications in three minutes or less! These images are available from several providers, including DigitalOcean, Vultr, Google Cloud Platform, AWS, Azure and Alibaba Cloud, and they come with a variety of web applications, the most popular of which is WordPress.

    So let’s say that you’ve chosen a provider, and installed an OpenLiteSpeed and WordPress cloud image. You’re up and running, but maybe you have questions. Well, you are in the right place, because we have answers! Here are some of the common things that people like you want to know:

    Where are the WordPress files stored?

    After your cloud image installation is complete, the WordPress files can be found in the Document Root, which is set to /var/www/html.

    Can I complete the script later?

    Sure. If you don’t want to finish the setup script right now, you can press CTRL-C to exit the script. The next time you log in from the SSH console, the script will automatically pick up where you left off. You can CTRL-C as often as you need to. The script will prompt you at every future login until you complete the setup.

    How do I secure phpMyAdmin?

    There are three ways to secure phpMyAdmin: Change the URL, allow only specific IP addresses, and require a password. You can use any of these options, and you can use more than one of them, if you like.

    Change your phpMyAdmin URL

    In the WebAdmin Console:

    • Navigate to WebAdmin > Virtual Hosts > Context
    • Change URI from /phpmyadmin to the URI of your choice

    Only allow specific IP addresses

    In the WebAdmin Console:

    • Navigate to WebAdmin > Virtual Hosts > Context > phpmyadmin
    • Change Access Allowed from * to a comma-delimited list of allowed IP addresses and subnets
    • Set Access Denied to *

    Require a password

    Log into the SSH console and create a password file, like so:

    $ sudo touch /usr/local/lsws/conf/PASS
    $ sudo chown lsadm:lsadm /usr/local/lsws/conf/PASS
    

    In the WebAdmin Console:

    • Navigate to WebAdmin > Virtual Hosts > Security
    • Click + under Realm List then set Realm Name to example
    • Set User DB Location to /usr/local/lsws/conf/PASS
    • Click /usr/local/lsws/conf/PASS to create a user and password
    • Navigate to WebAdmin > Virtual Hosts > Context > phpmyadmin
    • Set Realm to example

    How do I create additional virtual hosts?

    OpenLiteSpeed comes with a single virtual host named example. There are two ways to create additional virtual hosts: with a script, and manually.

    With a script

    This method will automatically set up Listener, VirtualHost, Force SSL, Let’s Encrypt, and WordPress. You can run the script either in Interactive Mode, or from the CLI.

    Interactive Mode

    Use the following commands to download and run the script:

    wget https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/vhsetup.sh
    chmod +x vhsetup.sh
    bash vhsetup.sh
    

    Or just run the script without downloading it:

    /bin/bash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/vhsetup.sh )
    

    CLI Mode

    Use the following commands to download and run the script:

    wget https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/vhsetup.sh
    chmod +x vhsetup.sh
    bash vhsetup.sh -d www.example.com -le admin@example.com -f -w
    

    Or just run the script without downloading it:

    /bin/bash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/vhsetup.sh ) -d www.example.com -le admin@example.com -f -w
    

    Some tips:

    • In the example, we use -le admin@example.com. When you do this, be sure that your domain is already pointing to the server, and to substitute your own email address.
    • We also use -w. This requires that your environment has PHP, SQL service, and SQL root password.

    Manually

    Our OpenLiteSpeed knowledge base has full instructions for creating new virtual hosts manually. See Create Virtual Hosts on OpenLiteSpeed.

    Can I use LiteSpeed Enterprise with the Cloud Image?

    Sure. You can upgrade from OpenLiteSpeed to LiteSpeed Enterprise at any time. We have a script that will take care of this for you, though we do suggest that you try the script on a test server first. Also, you can get help by using the -H parameter when you run the script.

    Use this command:

    /bin/bash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/ols2ent-v2.sh )
    

    The script will:

    1. Generate a LiteSpeed Enterprise configuration file from your OpenLiteSpeed config file
    2. Ask you for a valid license key (enter the word Trial if you would like to start with a 15-day trial license)
    3. Back up the OpenLiteSpeed config file and uninstall OpenLiteSpeed
    4. Install LiteSpeed Enterprise and load the config file

    Conclusion

    We hope we’ve answered all of your burning questions, but if there’s anything else you want to know, take a look at our comprehensive documentation. Or drop by our Slack community (first timers, click here for an invitation) and ask your question in the #openlitespeed or #wpcache channel!

    Thanks to Eric Leu for his contributions to this post.

  • Install Sails.js on LiteSpeed Web Server

    Install Sails.js on LiteSpeed Web Server

    Sails.js is a realtime Model-View-Controller (MVC) framework for building Node.js applications. It is an open source framework that allows you to build JavaScript apps in a matter of weeks not months. And if paired with a LiteSpeed Web Server, it allows you to offer a high performance JS app that your users will love, by leveraging LiteSpeed’s caching and optimization features. As a developer, building on top of Sails means your app is written entirely in JavaScript, and there is no overhead of having to deal with multiple programming languages to deliver a great user experience. Let’s look at how to install Sails.js on LiteSpeed Web Server.

    Please note this tutorial does not work with control panel installations, nor does it work with OpenLiteSpeed.

    Here is what you will need to complete this setup:

    • Native LiteSpeed Web Server with a valid license key or trial license running on a VPS, or the AWS LiteSpeed Web Server instance deployed via these instructions.
    • Node.js and npm package manager
    • The Sails.js package for Linux distribution

    Install the Sails.js framework

    Install Node.js

    Before you install Sails.js, Node.js must be installed on the server. Run the following commands to install dependencies, add the Node.js repository to your server, and install Node.js:

    apt-get install curl wget gnupg2 -y
    curl -sL https://deb.nodesource.com/setup_14.x | bash -
    apt-get install nodejs -y
    

    Check and verify the version of Node.js that is now running on your server by running the command:

    node --version

    Install Sails.js

    Sails.js can be easily installed using the npm package manager for JavaScript. Run the following command to kick start the install:

    npm -g install sails
    

    Once the installation is complete, you can simply create a project folder by running the command:

    mkdir newproject
    

    This will create a new directory named newproject

    You now need to change into the directory and create a new Sails app. Run the following commands to do this:

    cd newproject
    sails new softwareproject
    

    You will be asked to choose a template for your Sails application:

    Type 2 and press Enter to start the Sails.js app installation process. Sails.js will now start to download dependencies and software components needed by your app.

    Once the Sails.js installation process is complete, an application directory will be created. The directory is given the name of the app that you specified in the sails new command. In this example, it’s softwareproject. Run the following commands to start the Sails application:

    cd softwareproject
    sails lift
    

    You should see the following output:

    Sails v1.5.3
    Server lifted in ‘/newproject/softwareproject’ 
    To shut down sails, press <CTRL> + C at any time. 
    Read more at https://sailsjs.com/support
    Environment: development
    Port: 1337
    

    Create a Systemd service file for the Sails.js app that you have created

    You now need to create a systemd configuration file that will help you to manage your Sails.js application. The systemd file will help to ensure that the Sails.js app can start up automatically at system reboot. You can start, stop, and restart the Sails.js app using systemctl.

    Run the following command to create the service file:

    nano /lib/systemd/system/sails.service
    

    Add the following configuration into this file:

    [Unit]
    After=network.target
    [Service]
    Type=simple
    User=root
    WorkingDirectory=/newproject/softwareproject
    ExecStart=/usr/bin/sails lift
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
    

    Save and close the file then reload the systemd daemon to apply the changes:

    systemctl daemon-reload
    

    You can now start the Sails.js service and enable it to start at system reboot:

    systemctl start sails
    systemctl enable sails
    

    If you have configured everything correctly, run the following command to check the status of the Sails.js service:

    systemctl status sails

    It should show that the service is active (running) as shown in the output below:

    Configure LitesSpeed Web Server as a reverse proxy for Sails.js

    The final step is to configure LiteSpeed Web Server as a reverse proxy for Sails.js. A reverse proxy is a server that sits in front of a web server and forwards client requests to that web server. LiteSpeed Web Server can also be implemented as a reverse proxy server for websites and web applications to help increase security, performance, and reliability.

    Open a new browser window and type in the following URL to log into the WebAdmin Console:

    https://YOUR_IP_OR_HOSTNAME:7080
    

    On the login page, type in your WebAdmin Console password, navigate to Configuration > Virtual Hosts, and click Add.

    Set the following values (being sure to replace yourdomain with your actual domain name) and click Save:

    • Virtual Host Name: yourdomain.com
    • Virtual Host Root: $SERVER_ROOT/yourdomain/
    • Config File: $SERVER_ROOT/conf/vhosts/yourdomain.xml

    Click on the newly created virtual host, click View/Edit, navigate to General > General, and click Edit. Set the following values and click Save:

    • Document Root: $VH_ROOT/html
    • Enable Compression: Yes

    In the Index Files section, click Edit. Set the following values and click Save:

    • Use Server Index Files: No
    • Index Files: index.html, index.php
    • Auto Index: No

    Navigate to External App and click Add. Set Type to Web Server and click Next. Set the following values and click Save:

    • Name: SAILSJS
    • Address: http://127.0.0.1:1337

    Navigate to Context and click Add. Set Type to Proxy and click Next. Set the following values and click Save:

    • URI: /
    • Web Server: [VHost level] SAILSJS

    To put everything into action, navigate to Configuration > Listeners > Virtual Host Mappings, and click Add. Select the virtual host that you created, set Domains to your domain name, and click Save.

    Click the Grateful Restart link at the top of the WebAdmin Console to apply the above changes.

    Test the access to the Sails.js web application

    Open a new browser window and type in your domain name. You should see the default Sails.js page as shown in the image below:

    And that’s it! You have successfully installed the Sails.js framework on a LiteSpeed Enterprise Web Server. From here you can now start building amazing and fast web JavaScript applications for your users. For more technical support details please visit our LiteSpeed Web Server documentation.

  • OpenLiteSpeed or LiteSpeed Enterprise?

    OpenLiteSpeed or LiteSpeed Enterprise?

    OpenLiteSpeed or LiteSpeed Enterprise

    Are you an OpenLiteSpeed user wondering if you should take the next step and upgrade to LiteSpeed Enterprise Web Server? Or maybe you’re new to LiteSpeed entirely, and not sure which server product is right for you. Either way, we can help.

    The open source OpenLiteSpeed (or OLS), and the Enterprise-level LiteSpeed Web Server (or LSWS) have many features in common: both are equipped with the powerful LSCache engine, cutting edge HTTP/3 support, unlimited IP-based and name-based virtual hosting, compression with GZIP and Brotli, and so much more.

    To help in your decision-making, let’s look at some of the main differences between OLS and LSWS.

    Main Differences

    .htaccess

    .htaccess files are configuration files used by Apache web server to define rules for the server’s behavior on a per directory basis. OLS and LSWS differ in the extent to which they each support .htaccess.

    • LSWS supports Apache rewrite rules and the majority of Apache directives. It will automatically detect any changes to .htaccess files, and will adjust as necessary without any need for a server restart.
    • OLS supports Apache rewrite rules, but does not support Apache directives. You will need to restart the server to load any changes to .htaccess.

    ModSecurity Engine

    ModSecurity is an open-source web application firewall, which provides server protection by filtering web traffic through a series of rules. Both OLS and LSWS support ModSecurity rules, but there are differences.

    • LSWS boasts a proprietary ModSecurity engine that was built by the LiteSpeed team to deliver superior performance. It processes Apache ModSecurity rules using a highly optimized asynchronous approach.
    • OLS also supports Apache ModSecurity rules through a standard ModSecurity v3 engine, using the same library as open source nginx uses.

    ESI

    ESI, which stands for Edge Side Includes, is a markup language that allows web developers to designate parts of a web page as fragments that the server will process separately from the rest of the page. With ESI, a web page can be broken into different fragments, processed separately, and then re-assembled before being delivered to the browser. It is especially useful in ecommerce applications where there may be a mix of public and private information on a single page. When combined with LSCache, ESI creates a powerful cache solution.

    • LSWS supports ESI.
    • OLS does not support ESI.

    Asynchronous SSL Handshake

    The private key handshake of SSL can put a strain on server resources. Asynchronous SSL handshake relieves that strain by moving handshake operations to separate worker threads instead of handling it in the main event-handling thread. This improves SSL performance and reduces congestion in I/O event handling.

    • LSWS supports Asynchronous SSL Handshake
    • OLS does not support Asynchronous SSL Handshake

    WordPress Brute Force Protection

    During a WordPress Brute Force Attack, attackers repeatedly access the login page in an attempt to guess a valid user ID and password, and gain entry to the system. Besides the obvious security risks that brute force attacks pose, they also consume considerable server resources.

    • LSWS comes with built-in protection against WordPress Brute Force Attack.
    • OLS does not have native protection against WordPress Brute Force Attack

    Control Panel Support

    Web hosting control panels are a popular way for system administrators to handle server management tasks. Many popular control panels were written specifically for Apache servers.

    • LSWS is a drop-in Apache replacement, which means that any control panel that supports Apache also supports LSWS. Popular LSWS-friendly control panels include cPanel, Plesk, DirectAdmin, and more.
    • OLS is not a direct replacement for Apache, so it cannot automatically use the same control panels as Apache. However, there is a growing number of control panels that support OpenLiteSpeed, including CyberPanel, DirectAdmin, CloudPages, RunCloud, and GridPane. Additionally, pre-built OpenLiteSpeed cloud images are available on every major platform for simple installation.

    Licensing

    Licensing requirements are also different between the two servers.

    • LSWS requires a license. There’s a LiteSpeed license to fit any situation, from the Free Starter license for single domains on small servers, to the unlimited license for large web hosts, and everything in between.
    • OLS is 100% free and open source. It may be used by anyone with any number of domains, and any size server, under a GPLv3 License.

    Learn More

    OpenLiteSpeed or LiteSpeed Enterprise: which should you choose?

    OpenLiteSpeed and LiteSpeed Enterprise Web Server are both feature rich, and this comparison is just the beginning. We’ve only covered the big differences here. You can explore the full list of features of both servers side by side on our LiteSpeed Web Server Editions page if you’d like to continue your research.

    Already know what you want? Choose your own adventure: get OpenLiteSpeed or get LiteSpeed Enterprise today!

  • Gateway API Power for LiteSpeed Ingress Controller

    Gateway API Power for LiteSpeed Ingress Controller

    Gateway API Power for LiteSpeed Ingress Controller

    The LiteSpeed Ingress Controller expands the very powerful LiteSpeed WebADC engine into the Kubernetes cluster space for load-balancing. Introducing new Gateway API power for LiteSpeed Ingress Controller.

    The LiteSpeed documentation introduces the features available in the Gateway API. The Gateway API introduction focuses on the role-oriented nature of the new features and these are very useful. This blog will go further and show you some of the advanced features available using the Gateway API which were previously available but only as proprietary extensions.

    The Gateway API now standardizes some of the more complex needs many customers have in their Kubernetes environments. In particular red-blue and canary deployments. These features have been available using the LiteSpeed Ingress Controller for some time and this blog will show you a new way to implement them.

    Red-Blue and Canary Deployments

    As described in the Advanced Deployments section of the LiteSpeed documentation, when you have a new image of software and want to try it out on a subset of users. Say, give it to 10% of your user population and see if there are problems. This is typically described as a “canary deployment.” You might want to increase the percentage until most of the population is using it, and then pass over control completely to the new group.

    Or you may want to set up the deployment, and swap it over knowing you can swap it back quickly. That’s a “red-blue deployment.”

    Also supported by Gateway is 100% header-based routing for the safest of canary deployments.

    Red-blue deployment

    Red-Blue Deployment with Gateway via LiteSpeed

    Our first example will be to modify the Gateway example described in our documentation for olsup-gw.sh and we’ll create a red-blue deployment where you can switch between the old and new software quickly and easily. The modifications we’ll make below can be applied to the running pods and will take effect when executed.

    The first step would be to download and extract the samples. Note that the version number is in the file and we’d recommend taking the newest version. For the version 0.2.0:

    $ wget https://github.com/litespeedtech/helm-chart/raw/main/helm-chart-sources/ls-k8s-webadc/samples/ls-k8s-webadc-0.2.0.tgz
    $ tar xf ls-k8s-webadc-0.2.0.tgz
    $ cd ls-k8s-webadc

    And then bring up the sample gateway. We’ll be using it as a test base here.

    $ ./olsup-gw.sh

    In that example you have a Deployment, Service, Gateway and HTTPRoute. For the new version you wish to deploy, you’ll need a new Deployment and Service to make your new software available. Modeled on the examples/ols-backend.yaml, the new Deployment definition is named new-backend.yaml and looks like this:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: new-backend
    spec:
      selector:
        matchLabels:
          app: new-backend
      replicas: 2
      template:
        metadata:
          labels:
            app: new-backend
        spec:
          containers:
          - name: new-backend
            image: k8s.gcr.io/echoserver:1.10
            imagePullPolicy: Always
            ports:
            - containerPort: 8080
    

    The only differences are the names which must change and the image itself, which would always change for a new version. For this example, we’re using an image which is completely different so that we can see when it uses the new image.

    For the Service definition, create a new file named new-backend-svc.yaml modeled after ols-backend-svc.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      name: new-backend-svc
    spec:
      selector:
        app: new-backend
      ports:
      - port: 80
        targetPort: 8080
        name: new-backend-http
    

    All that is changed are the names. Apply them so they’ll be available:

    $ kubectl apply -f new-backend.yaml -n sandbox
    $ kubectl apply -f new-backend-svc.yaml -n sandbox

    Surprisingly, the Gateway definition does not have to change at all. Only the HTTPRoute needs to change. From the original definition, modify it to add a single line, weight: 100 and save it as httproute-red-weight-old.yaml:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: ols-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: ols-backend-svc
          port: 80
          weight: 100
    

    You can then immediately apply it. It will have no affect because weight is not based on a percentage or any other numbering system and defaults to 1. However, most examples use the percentage based assumption for simplicity and compatability.

    $ kubectl apply -f httproute-red-weight-old.yaml -n sandbox

    As described in the gateway doc, you can test it using curl. kubectl get gateway -n sandbox ols-gateway.com will return the address. You can then use it with curl:

    $ curl https://ADDRESS/ -H 'Host: ols-gateway.com' -k

    This should return the LiteSpeed server default screen’s HTML.

    To begin the new “blue” deployment, create a new definition and save it as httproute-blue-weight-new.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: new-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: new-backend-svc
          port: 80
          weight: 100
    

    Because it uses the existing gateway parentRefs name, we use the existing name and the existing hostname. However, we use the service name we created and assign a weight of 100 to represent that it gets 100% of the traffic. When you are ready to give it a try, you can apply it:

    $ kubectl apply -f httproute-blue-weight-new.yaml -n sandbox

    For the moment, both the old and new software will see traffic. To turn traffic off on the old site, copy the httproute-red-weight-old.yaml file to httproute-blue-weight-old.yaml and edit it, changing the weight to 0:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: ols-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: ols-backend-svc
          port: 80
          weight: 0
    

    And apply it:

    $ kubectl apply -f httproute-blue-weight-old.yaml -n sandbox

    If you again run the same curl you ran above, you can see the change in the output to a listing of the HTTP header. Keeping the files around gives you a quick and easy way to switch between old and new software.

    To remove all that you did you can reverse the entire process, with the final step being to take down the sample gateway:

    $ kubectl delete -f httproute-blue-weight-old.yaml -n sandbox
    $ kubectl delete -f httproute-blue-weight-new.yaml -n sandbox
    $ kubectl delete -f new-backend-svc.yaml -n sandbox
    $ kubectl delete -f new-backend.yaml -n sandbox
    $ ./olsdown-gw.sh

    Canary testing with headers

    Canary Deployments with Gateway via LiteSpeed

    The HTTP protocol includes easily modified request headers which allow a tester to reach the new software without giving the regular browser user access to it. Gateway allows you to match on received headers and query strings which gives you a choice of which method to test with. Query strings can be modified in a brower and thus make some sense for testing there, but since many applications count on the contents of a query string to be specifically defined, this example will use headers which are easily manipulated with curl. Note that using query strings is no more complicated than the method using headers here.

    Either method gives developers and testers a way to deploy into a live environment without worrying about affecting production users since users will not generally have access to these mechanisms. As a last step in development before final deployment, it can be important as it gives you assurance that you can survive live internet attacks, access to real databases, performance verification, load testing and everything that the real environment provides.

    We’ll be using the LiteSpeed Gateway samples and the deployment and service we created above.

    As above, start by running the olsup-gw.sh script and apply the deployment and service we created above.

    $ ./olsup-gw.sh
    $ kubectl apply -f new-backend.yaml -n sandbox
    $ kubectl apply -f new-backend-svc.yaml -n sandbox

    Also as above, the Gateway definition does not have to change at all. Even the HTTPRoute does not need to change as the absence of the new header will not affect traffic to the old backend.

    To begin a canary deployment, create a new canary definition and save it as httproute-canary-hdr.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: new-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - headers:
          - name: canary
            value: new
          path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: new-backend-svc
          port: 80
    

    Because it uses the existing gateway parentRefs name, we use the existing name and the existing hostname. However, we use the service name we created and assign a header canary:new. When you are ready to give it a try, you can apply it:

    $ kubectl apply -f httproute-canary-hdr.yaml -n sandbox

    Test access to the old software using the old access technique with curl:

    $ curl https://ADDRESS/ -H 'Host: ols-gateway.com' -k

    Test access to the new software by adding the required header:

    $ curl https://ADDRESS/ -H 'Host: ols-gateway.com' -k -H 'canary:new'

    To remove all that you did you can reverse the entire process, with the final step being to take down the sample gateway:

    $ kubectl delete -f httproute-canary-hdr.yaml -n sandbox
    $ kubectl delete -f new-backend-svc.yaml -n sandbox
    $ kubectl delete -f new-backend.yaml -n sandbox
    $ ./olsdown-gw.sh

    Canary deployment 90%-10%

    Our final example will be to modify the Gateway example described in our documentation for olsup-gw.sh and we’ll create a canary deployment where 90% of the traffic goes to the old software and 10% to the new. We’ll be using the LiteSpeed Gateway samples and the deployment and service we created above.

    As above start by running the olsup-gw.sh script and apply the deployment and service we created above.

    $ ./olsup-gw.sh
    $ kubectl apply -f new-backend.yaml -n sandbox
    $ kubectl apply -f new-backend-svc.yaml -n sandbox

    As above, the Gateway definition does not have to change at all. Only the HTTPRoute needs to change. From the original definition, modify it to add a single line, weight: 90 and save it as httproute-canary-weight-old.yaml:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: ols-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: ols-backend-svc
          port: 80
          weight: 90
    

    You can then immediately apply it. It will have no affect because weight is not based on a percentage or any other numbering system and defaults to 1. However, most examples use the percentage based assumption for simplicity and compatability.

    $ kubectl apply -f httproute-canary-weight-old.yaml

    As described in the gateway doc, you can test it using curl. kubectl get gateway -n sandbox ols-gateway.com will return the address. You can then use it with curl:

    $ curl http://ADDRESS/ -H 'Host: ols-gateway.com'

    This should return the LiteSpeed server default header.

    To begin a canary deployment, create a new canary definition and save it as httproute-canary-weight-new.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: new-gateway.com
    spec:
      parentRefs:
      - name: ols-gateway.com
      hostnames:
      - ols-gateway.com
      rules:
      - matches:
        - path:
            value: /
            type: PathPrefix
        backendRefs:
        - name: new-backend-svc
          port: 80
          weight: 10
    

    Because it uses the existing gateway parentRefs name, we use the existing name and the existing hostname. However, we use the service name we created and assign a weight of 10 to represent that it gets 10% of the traffic. When you are ready to give it a try, you can apply it:

    kubectl apply -f httproute-canary-weight-new.yaml -n sandbox
    

    Because of caching there’s no good way to test it. When a curl is done from the same machine, you’ll get the same entry you get the first time. Take our word for the fact that 10% of the traffic will be sent to the canary backend.

    To remove all that you did you can reverse the entire process, with the final step being to take down the sample gateway:

    $ kubectl delete -f httproute-canary-weight-old.yaml -n sandbox
    $ kubectl delete -f httproute-canary-weight-new.yaml -n sandbox
    $ kubectl delete -f new-backend-svc.yaml -n sandbox
    $ kubectl delete -f new-backend.yaml -n sandbox
    $ ./olsdown-gw.sh

    Just scratching the surface

    All of these techniques just scratch the surface of what you can do with gateway. We’ve demonstrated switching between old and new dynamically, using a header and using weights. As mentioned above you can also use query strings. You can also select on host name using wildcards (better than those for Ingress), and multiple levels of path, headers and query strings. You can add, set or delete headers to allow control of your backends. There are a whole set of role features. Gateway adds a whole new world to Kubernetes.

  • Presets in LSCWP v5.3

    Presets in LSCWP v5.3

    Presets in LSCWP v5.3

    Introducing LSCache Presets for WordPress: the easiest way to optimize your WordPress site using the Litespeed Cache plugin.

    Litespeed Cache Presets are a pre-tuned set of options, which can be used for optimizing any WordPress site using Litespeed Cache. You can configure your ideal level of optimization with just a few clicks!

    How to use a LiteSpeed Cache preset

    LSCache Presets for WordPress

    In the WordPress Dashboard, you can find Presets under the LiteSpeed Cache menu. If you don’t see it, make sure you’re using v5.3 or higher of the plugin.

    To use a preset, press the appropriate Apply Preset button on the Standar Presets tab, and answer OK when prompted to continue. Your old settings will be backed up, and the new preset settings will be applied.

    Be sure to test your site and make sure everything is working as expected. This is especially important if you’ve chosen one of the more aggressive presets. If the settings in the preset causes a problem for your site, you can revert back to your previous settings via the History section at the bottom of the tab.

    How to revert back

    The History section appears on the Standard Presets tab if you have previously applied a preset. Every time you apply a preset, a new entry is added to the history, along with a link that will allow you to revert back to the previous settings.

    Simply click the link, and everything will return to the way it once was.

    How to Manage Presets from the CLI

    Coming soon, if you’re using the WordPress CLI, you will be able to apply presets and restore backups using the litespeed-presets command and its three options: apply, get_backups, and restore.

    Examples

    Apply the “Basic” preset:

    $ wp litespeed-presets apply basic
    

    Get a list of available backups:

    $ wp litespeed-presets get_backups
    

    The backups displayed via get_backups all have numerical references. Restore the backup that has reference number 1667485245:

    $ wp litespeed-presets restore 1667485245
    

    Look for CLI Preset support in an upcoming version of LiteSpeed’s WordPress plugin.

    How to choose a preset

    Presets are listed in order of risk and skill level. If you are new to caching, and you prefer to “set it and forget it” then stick with Essentials or Basic. On the other hand, if you are a seasoned pro, or you’re an adventurous tinkerer, you might want to try one of the presets at the end of the list.

    Here is a basic overview of the official LiteSpeed preset collection. (You can take a look at our presets documentation, if you’d like the full details for each preset.)

    Essentials

    This preset enables caching, sets a higher default TTL (time to live) , and enables browser cache. These are easy, low-risk ways to improve your site’s loading time.

    Essentials will never break your site’s formatting, and will not require any tweaking whatsoever. Even if (or, maybe especially if) you have no experience with caching, you can apply this preset with confidence.

    Basic

    Basic enables everything that Essentials does, but it adds image optimization to speed up image loading time, and mobile cache to allow you to cache a mobile version of your website that may be different than the desktop version.

    This preset is appropriate for enthusiastic beginners who want to ease into a basic level of optimization. You shouldn’t have to make any adjustments to your settings in order to make this work. Image optimization is a QUIC.cloud service, so you will need a domain key in order to make this work. If you don’t have one, the plugin will prompt you and show you how to get one. The domain key and the image optimization service are both free.

    Advanced

    Here’s where things start to get more complicated. Advanced enables everything in Basic, and then adds a large number of page optimization features. While this plugin potentially requires some maintenance from you, it has the potential to greatly improve your site’s page speed score.

    Page optimization features sometimes highlight incompatibilities among CSS or Javascript used on your site. The incompatible files need to be excluded from optimization. If you enable this preset, you should be comfortable setting up CSS or JS exclusions via the plugin admin.

    A domain key is required.

    Aggressive

    Added to the Advanced features are CSS and JS Combine, Critical CSS, Unique CSS and more. CCSS and UCSS are both QUIC.cloud services which may incur fees, and domain key is required.

    These features are excellent for page speed scores, and they really speed up your site. But they also have considerable potential to require intervention. Only use this preset if you are comfortable looking for conflicts and excluding files from optimization.

    Extreme

    As you might expect from a preset called Extreme, this one enables the maximum level of optimization possible. Page speed sites love sites with all of these optimizations.

    As with previous presets, a domain key is required, as is some expertise. These settings are likely to introduce CSS or JS conflicts, especially if you have a lot of plugins or a complicated theme.

    Frequently Asked Questions

    I am new to Litespeed Cache, which preset should I apply?

    We suggest trying the Advanced preset because it takes a balanced approach to optimization and speed. You shouldn’t need to manually tweak many settings, but if you do experience difficulty, you can always revert to your previous settings, or try the Basic preset.

    Can I modify Litespeed Cache settings after setting up this preset?

    Yes, it is absolutely possible to edit any options after applying a preset. Presets are just an easy way to get started. They give you a good base optimization to start with, but many complex websites will need more fine-tuning to achieve their best possible page score or user experience.

    If I don’t like a preset I’ve applied, can I undo it?

    Yes! Please see How to revert back above.

    How can I get more fine-tuning specifically for my website?

    Presets are a simple way to get started, but if your site design is complicated, or you just don’t want to get your hands dirty with WordPress admin, LiteSpeed offers a Paid Support Service. We’ll be happy to do the optimization for you.

    Video

    Prefer to see how it’s done? We’ve demonstrated all of the steps in this video:

    Conclusion

    These Standard Presets, which were developed by our LiteSpeed team, provide a simple way to apply preconfigured optimization settings for every comfort level. But this is just a start!

    Eventually, we hope to include Presets that have been submitted by members of our community to cover a wide variety of site styles and needs.

    In the meantime, give our Standard Presets a try, and let us know what you think!

  • Full Disclosure of CVE-2022-0072, CVE-2022-0073, and CVE-2022-0074 and What You Should Do

    Full Disclosure of CVE-2022-0072, CVE-2022-0073, and CVE-2022-0074 and What You Should Do

    CVE-2022-0072 CVE-2022-0073 CVE-2022-0074

    Security has always been at the forefront of our development process at LiteSpeed Technologies. So when a vulnerability is discovered, we act quickly. Our priority is to empower our customers to better protect their systems, but we also take such situations as learning opportunities.

    Today, as a part of that commitment, we want to share details of certain bugs reported in OpenLiteSpeed (OLS) and LiteSpeed Enterprise (LSWS) web servers.

    Summary

    • Three vulnerabilities were reported to LiteSpeed. These were fixed in OpenLiteSpeed v1.7.16 Build 1 and LiteSpeed Enterprise v6.0.12 Build 10.
    • These vulnerabilities don’t impact the majority of our clients. One is within the Docker system, and the other two cannot be exploited without WebAdmin access.
    • You should upgrade to the latest version and build of OpenLiteSpeed or LiteSpeed Enterprise, as appropriate.
    • Future security updates will be released with incremented version numbers, and will no longer be released as new builds of existing version numbers.

    About the Vulnerabilities

    We would like to thank the Unit 42 Team at Palo Alto Networks for responsibly disclosing security issues in our OpenLiteSpeed and LiteSpeed Enterprise web servers on October 4th, and maintaining good communication throughout.

    LiteSpeed’s Team acted swiftly and informed Unit 42 that the issues were under remediation.

    On October 8th, we internally remediated these bugs and put them into testing. During this period we monitored the changes and ensured they were not affecting anything else.

    On October 12th, we pushed the related updates to LiteSpeed Enterprise v6.0.12 as Build 10

    On October 18th, we pushed the related updates to OpenLiteSpeed v1.7.16 as Build 1

    On October 20th, our Docker Images for both OLS and LSWS were updated.

    The reported vulnerabilities have the following CVE numbers: CVE-2022-0072CVE-2022-0073 and CVE-2022-0074.

    Palo Alto Networks has already released information about these CVEs, but we would like to expand on this, below.

    CVE-2022-0072

    Directory Traversal (CVE-2022-0072) rated Medium severity (CVSS 5.8)

    [This issue] was a directory traversal vulnerability that could allow an attacker to bypass security measures and access forbidden files. An attacker that compromised the server could create a secret backdoor and exploit the vulnerability to access it.

    This vulnerability applies to OpenLiteSpeed and LiteSpeed Enterprise WebAdmin Console, and is only exploitable after WebAdmin Authentication has been achieved.

    Additionally, you must have root privileges in order to upload a custom exploit under /usr/local/lsws/admin/html.

    CVE-2022-0073

    Remote Code Execution (CVE-2022-0073) rated High severity (CVSS 8.8)

    At the first stage of the attack, we tried to gain remote code execution and found that the OpenLiteSpeed Web Server admin dashboard is vulnerable to a command injection vulnerability. A threat actor who managed to gain the credentials to the dashboard, whether by brute force attacks or social engineering, could exploit the vulnerability in order to execute code on the server.

    This also applies only to the OLS and LSWS WebAdmin Console for an authenticated user.

    CVE-2022-0074

    Privilege Escalation (CVE-2022-0074) rated High severity (CVSS 8.8)

    While exploring the OpenLiteSpeed Docker image as nobody, we found a misconfiguration in the PATH environment variable that could be exploited into a privilege escalation using the CWE untrusted search path.

    This is another vulnerability that requires OpenLiteSpeed WebAdmin access in order to exploit. LiteSpeed Enterprise is not affected.

    We were unable to reproduce this scenario in our tests with a standard real-world Docker installation. It seems that the environment used by the reporting team differs from the default Docker configuration. The reporting team’s /usr/local/bin folder was owned by the nobody user, which allowed the vulnerability to operate.

    We tried to reproduce this bug on an Ubuntu 22 system with the default Docker host environment and the vulnerable build of our Docker image. We found that the /usr/local/bin directory was owned by root, and any attempt to change the files in the reported directory failed.

    CVE-2022-0074 Screenshot

    We don’t expect this vulnerability to impact standard Docker installations, however, we are in touch with the PaloAlto Networks Team to get more details on their Docker environment. We’d like to understand how it was customized to make this vulnerability possible.

    Regardless, this is not a privilege escalation from within any LiteSpeed products.

    What You Should Do

    For Docker users, if you’re able to change the contents of /usr/local/bin in your environment, please update to our latest Docker image. An additional security layer which corrects the environment path will be added to your image, effectively patching any side-effects of this vulnerability.

    We also recommend any manual web server installations to be updated by using the $LSWS_PATH/admin/misc/lsup.sh script. Installations installed via any RPM/package managers(yum/apt) will be updated automatically.

    We always recommend, for your general security, that you do not share LiteSpeed WebAdmin authentication details with more than the necessary system administrators. We also suggest you set a strong password and take advantage of the available Brute Force protection available for WebAdmin.

    For best-case scenarios, use a firewall to mask LiteSpeed WebAdmin Console from any public access.

    We would like to once again thank the Unit 42 Team, for their help in making our products secure.

  • OpenLiteSpeed + Go + Gin

    OpenLiteSpeed + Go + Gin

    OpenLiteSpeed + Go + Gin

    In this blog we will talk about how to deploy Gin – a web framework written in Go – by using OpenLiteSpeed on Ubuntu 22.04.

    By using OpenLiteSpeed Web Server as a reverse proxy, we can easily serve multiple apps in the backend via the same port. Rewrite is supported in the .htaccess file in case we need to redirect. Also, once we set up SSL, the HTTP/3 protocol will be ready instantly. In this blog, we use Gin as an example because it allows us to build web applications and microservices in Go. It contains a set of commonly used functionalities, like routing, and the performance is pretty good.

    We will walk though the following processes on our server:

    Installing Go

    Install Go using snap on Ubuntu:

    $ snap install go --classic
    

    Console output:

    go 1.18.5 from Michael Hudson-Doyle (mwhudson) installed
    

    Enable the Go Modules feature, which will allow us to use modules regardless of whether they are in the GOPATH default:

    $ go env -w GO111MODULE=on
    

    Verify the settings with the following command:

    $ go env
    

    Console output:

    GO111MODULE="on"
    GOARCH="amd64"
    ...
    

    Setting up the Gin package

    Create an example project directory named gin-project and access the directory:

    $ mkdir -p /var/www/html/gin-project
    $ cd /var/www/html/gin-project
    

    Create a go.mod file to track our code’s dependencies. Run the command from within the project directory:

    $ go mod init gin-project
    

    Check the content of the go.mod file:

    $ cat go.mod
    

    Console output:

    module gin-project
    
    go 1.18
    

    To get the gin-gonic/gin package from GitHub, we will need to add the following content to the file:

    module gin-project
    
    go 1.18
    
    require github.com/gin-gonic/gin v1.8.1
    

    (Note we are using v1.8.1 in this example. Check for other versions here).

    Run the following command, and the required package will be installed under the GOPATH/pkg/mod directory. A go.sum file will be generated. It’s a record file for the package and version:

    $ go mod download
    

    Now, we are going to download the gin package:

    $ go get github.com/gin-gonic/gin
    

    Console Output:

    go: downloading github.com/gin-contrib/sse v0.1.0
    go: downloading github.com/mattn/go-isatty v0.0.14
    go: downloading golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
    go: downloading github.com/go-playground/validator/v10 v10.10.0
    go: downloading github.com/pelletier/go-toml/v2 v2.0.1
    go: downloading github.com/ugorji/go/codec v1.2.7
    go: downloading google.golang.org/protobuf v1.28.0
    go: downloading gopkg.in/yaml.v2 v2.4.0
    go: downloading github.com/goccy/go-json v0.9.7
    go: downloading github.com/json-iterator/go v1.1.12
    go: downloading golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069
    go: downloading github.com/go-playground/universal-translator v0.18.0
    go: downloading github.com/leodido/go-urn v1.2.1
    go: downloading golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
    go: downloading golang.org/x/text v0.3.6
    go: downloading github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
    go: downloading github.com/modern-go/reflect2 v1.0.2
    go: downloading github.com/go-playground/locales v0.14.0
    
    

    Using any text editor, create a file named main.go, and add the following example contents:

    package main
    
    import "github.com/gin-gonic/gin"
    
    func main() {
        r := gin.Default()
        r.GET("/ping", func(c *gin.Context) {
            c.JSON(200, gin.H{
                "message": "pong",
            })
        })
        r.Run(":8080") // Listen and Serving HTTP on 0.0.0.0:8080
    }
    

    We might also want to run the following command to remove any unused dependencies:

     $ go mod tidy
    

    Output:

    go: downloading github.com/stretchr/testify v1.7.1
    go: downloading github.com/davecgh/go-spew v1.1.1
    go: downloading github.com/pmezard/go-difflib v1.0.0
    go: downloading gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
    go: downloading github.com/google/go-cmp v0.5.5
    go: downloading github.com/go-playground/assert/v2 v2.0.1
    go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
    go: downloading github.com/kr/pretty v0.3.0
    go: downloading golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
    go: downloading github.com/kr/text v0.2.0
    go: downloading github.com/rogpeppe/go-internal v1.8.0
    

    Manually run the main.go file and test it:

    $ go run main.go
    

    Visit the site or curl the http://127.0.0.1:8080/ping URl. We should get the following response:

    {"message":"pong"}
    

    Setting up the Gin service

    In order to run the service with systemd service, we will need to build main.go, so we can get a binary file from it:

    $ go build main.go
    

    Create a gin service file at /etc/systemd/system/gin.service with the following content:

    [Unit]
    Description=gin
    
    [Service]
    Type=simple
    Restart=always
    RestartSec=3s
    ExecStart=/var/www/html/gin-project/main
    
    [Install]
    WantedBy=multi-user.target
    

    Start the service and check the status:

    $ systemctl start gin
    $ systemctl status gin
    

    Console Output:

    ● gin.service - gin
         Loaded: loaded (/etc/systemd/system/bin.service; disabled; vendor preset: enabled)
         Active: active (running) since Tue 2022-10-04 07:14:09 UTC; 45s ago
       Main PID: 25971 (main)
          Tasks: 5 (limit: 1119)
         Memory: 5.4M
            CPU: 23ms
         CGroup: /system.slice/gin.service
                 └─25971 /var/www/html/gin-project/main
    

    Setting up OpenLiteSpeed as a Reverse proxy

    The fastest way to set up the OpenLiteSpeed web server with proxy settings is to rely on the ols1clk script with the proxy setup option --proxy-c. It will set up an External Applications – Web Server with default value http://127.0.0.1:8080 and a Proxy Context in the Example virtual host:

    $ bash <( curl -k https://raw.githubusercontent.com/litespeedtech/ols1clk/master/ols1clk.sh) --proxy-c
    

    After the installation, we can visit http://example.com/ping in the browser (replacing example.com with our actual domain):
    OpenLiteSpeed Reverse Proxy Pin

    If we want to modify the default value or add more proxy content for more backend services, we can access the LiteSpeed Web Admin at port 7080 to configure it further.

    Setting up SSL (Optional)

    Setting up an SSL certificate enables HTTPS on the web server, which secures the traffic between the server and the clients connecting to it. Certbot is a free and automated way to set up SSL certificates on a server.

    The first thing is to install the Certbot package to the system:

    $ apt-get install certbot -y
    

    To use Certbot, we’ll need a registered domain name and DNS records:

    • An A record from the domain (e.g., example.com) to the server’s IP address
    • An A record from the domain prefaced with www (e.g., www.example.com) to the server’s IP address.

    Once the DNS records are set up, we can generate the SSL certificate by following the instructions in the OpenLiteSpeed KB.

    After setting up SSL on OpenLiteSpeed, we can test our site, or any site on the Internet, with the free HTTP/3 Check tool. Enter a URL, and HTTP/3 Check will tell us whether QUIC or HTTP/3 is supported by that site.

    The HTTP/3 Check Tool

    Configuring Security (Optional)

    There are several built-in security features that we could implement, for example reCAPTCHA, Per-Client Throttling, WAF, etc.

    reCAPTCHA

    OpenLiteSpeed features reCAPTCHA as a method of defense against DDoS attack. When a visitor accesses the website, they will need to go though reCAPTCHA validation. After passing the reCAPTCHA validation, the visitor is temporarily allowlisted as long as they continue to browse the site. Once the visitor has become inactive, reCAPTCHA is once again enabled for that visitor’s next request. We can follow the reCAPTCHA Security Guide to enable the feature.

    Per-Client Throttling

    OpenLiteSpeed includes a built-in Per-Client Throttling feature which allows you to block bad IPs, as well as limit the request, bandwidth, and connection rate per remote IP address. We can follow the Per-Client Throttling Security Guide to enable the feature.

  • Horizontally Auto-scale LiteSpeed Ingress Controller

    Horizontally Auto-scale LiteSpeed Ingress Controller

    Horizontally Auto-scale LiteSpeed Ingress Controller

    One of the many cool features about Kubernetes is its ability to scale when load increases. And the LiteSpeed Ingress Controller has several built-in features which helps enable horizonal scaling of itself:

    • Prometheus style metrics, which can be exported to Prometheus or Grafana and help you visually or programmatically determine the load level.
    • Auto-scaling helm options, which will detect when load is high and automatically scale up and scale back down when load abates.

    This blog will walk you though the following processes on your Kubernetes Cluster:

    This blog assumes little prior experience with Kubernetes, but does expect you to have kubectl and helm installed. You should have access to your cluster available to the console user and familiarity with text editing

    Installing a simple application

    This step uses a small application named PodInfo which simply returns some static text. The text is resolved into a browser image, if run in a browser. However, if run by a load generator, it returns a minimal amount of text.

    To install it, use the text editor of your choice and create the file named 1-podinfo.yaml with the following contents:

    apiVersion: apps/v1 
    kind: Deployment 
    metadata: 
      name: podinfo 
    spec: 
      selector: 
        matchLabels: 
          app: podinfo 
      template: 
        metadata: 
          labels: 
            app: podinfo 
        spec: 
          containers: 
          - name: podinfo 
            image: stefanprodan/podinfo 
            ports: 
            - containerPort: 9898 
    --- 
    apiVersion: v1 
    kind: Service 
    metadata: 
      name: podinfo 
    spec: 
      ports: 
        - port: 80 
          targetPort: 9898 
          nodePort: 30001 
      selector: 
        app: podinfo 
      type: NodePort 
    ---
    apiVersion: networking.k8s.io/v1 
    kind: Ingress 
    metadata: 
      name: podinfo 
    spec: 
      ingressClassName: lslbd
      rules: 
        - host: "example.com" 
          http: 
            paths: 
              - backend: 
                  service: 
                    name: podinfo 
                    port: 
                      number: 80 
                path: / 
                pathType: Prefix 
    

    Once saved, apply it with kubectl:

    $ kubectl apply -f 1-podinfo.yaml

    Accessing an exposed application in a Kubernetes cluster

    To verify it was installed, find the external IP address of the exposed node it’s running on. In Kubernetes, images are deployed to pods which run on these nodes. To get the node it was run in:

    $ kubectl get pods -o=wide|grep podinfo

    In my environment, it returned a single line:

    podinfo-7dc5f49b9b-s4spd                          1/1     Running   0          26h     10.244.2.93      pool-e85y5p9p2-7jkcs   <none>           <none>
    

    In column 7, it reports the node that it was run in; for me that is pool-e85y5p9p2-7jkcs. Remember that name. Then get the list of external IP addresses for your nodes:

    $ kubectl get nodes -o=wide

    Which displays on my system:

    NAME                   STATUS   ROLES    AGE   VERSION    INTERNAL-IP      EXTERNAL-IP       OS-IMAGE                       KERNEL-VERSION          CONTAINER-RUNTIME
    pool-e85y5p9p2-7jkc5   Ready    <none>   5d    v1.21.14   10.136.121.238   159.223.189.158   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkck   Ready    <none>   5d    v1.21.14   10.136.121.235   147.182.135.113   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkcs   Ready    <none>   5d    v1.21.14   10.136.121.237   137.184.105.17    Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    

    And I can see that the pool pool-e85y5p9p2-7jkcs has external IP address of 137.184.105.17. Since the sample exports the application on port 30001 on that IP, you can bring up a browser and enter in the url: http://[YOUR IP ADDRESS]:30001, which for me is: http://137.184.105.17:30001:

    Scaling Demonstration Application

    Installing the LiteSpeed Ingress Controller

    To install the LiteSpeed Ingress Controller you’ll need to follow the basic instructions here. For this excercise you can skip the section Making HTTPS Work. The important change is in Installing the Chart. The helm install line should look like this (assuming that you’re using the namespace ls-k8s-webadc:

    $ helm install ls-k8s-webadc ls-k8s-webadc/ls-k8s-webadc -n ls-k8s-webadc --set service.metrics.enabled="true",autoscaling.enabled="true"

    This is the normal helm install, but also includes the LiteSpeed helm options to enable metrics and autoscaling.

    Installing Prometheus

    This is an optional step, as it just allows you to see the impact that autoscaling has in your environment. By setting the LiteSpeed Ingress Controller helm option of service.metrics.enabled="true" you are enabling metric exporting from the LiteSpeed Ingress Controller automatically into a Prometheus installed on the cluster. This is generally a low-overhead operation and is quite useful for monitoring LiteSpeed’s operations. To install Prometheus:

    $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    $ helm install prometheus prometheus-community/prometheus --set server.service.type=NodePort --set server.service.nodePort=30010

    Accessing Prometheus in a Kubernetes cluster

    To then access Prometheus from a web browser, use the trick above:

    $ kubectl get pods -o=wide|grep prometheus-server

    In my environment, it returned a single line:

    prometheus-server-57f4946cdb-x54rh                2/2     Running   0          40h     10.244.3.17      pool-e85y5p9p2-7jkc5   <none>           <none>
    

    In column 7, it reports the node that it was run in; for me that is pool-e85y5p9p2-7jkc5. Remember that name. Then get the list of external IP addresses for your nodes:

    $ kubectl get nodes -o=wide

    Which displays on my system:

    NAME                   STATUS   ROLES    AGE   VERSION    INTERNAL-IP      EXTERNAL-IP       OS-IMAGE                       KERNEL-VERSION          CONTAINER-RUNTIME
    pool-e85y5p9p2-7jkc5   Ready    <none>   5d    v1.21.14   10.136.121.238   159.223.189.158   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkck   Ready    <none>   5d    v1.21.14   10.136.121.235   147.182.135.113   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkcs   Ready    <none>   5d    v1.21.14   10.136.121.237   137.184.105.17    Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    

    And I can see that the pool pool-e85y5p9p2-7jkc5 has external IP address of 159.223.189.158. Since the helm install command line exports the application on port 30010 on that IP, you can bring up a browser and enter in the url: http://[YOUR IP ADDRESS]:30010, which for me is: http://159.223.189.158:30010:

    Entering Prometheus

    To keep an eye on the LiteSpeed Ingress Controller, enter into the search bar litespeed_current_http_connections, press the Execute button and the Graph tab and you should see any http traffic on your cluster. There may be some random traffic:

     

    Monitoring LiteSpeed Ingress Controller

    If you do not see a graph, you may need to verify that you used the correct helm parameters when you [installed the LiteSpeed Ingress Controller](#Installing the LiteSpeed Ingress Controller) and check the Troubleshooting documentation.

    Installing a load generator

    To simulate load, install Locust. Using your text editor create the file 2-locust.yaml using the following contents:

    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: locust-script 
    data: 
      locustfile.py: |- 
        from locust import HttpUser, task, between 
    
        class QuickstartUser(HttpUser): 
            wait_time = between(0.7, 1.3) 
    
            @task 
            def hello_world(self): 
                self.client.get("/", headers={"Host": "example.com"}) 
    --- 
    apiVersion: apps/v1 
    kind: Deployment 
    metadata: 
      name: locust 
    spec: 
      selector: 
        matchLabels: 
          app: locust 
      template: 
        metadata: 
          labels: 
            app: locust 
        spec: 
          containers: 
            - name: locust 
              image: locustio/locust 
              ports: 
                - containerPort: 8089 
              volumeMounts: 
                - mountPath: /home/locust 
                  name: locust-script 
          volumes: 
            - name: locust-script 
              configMap: 
                name: locust-script 
    --- 
    apiVersion: v1 
    kind: Service 
    metadata: 
      name: locust 
    spec: 
      ports: 
        - port: 8089 
          targetPort: 8089 
          nodePort: 30015 
      selector: 
        app: locust 
      type: NodePort
    

    Deploy Locust:

    $ kubectl apply -f  2-locust.yaml 

    Accessing Locust

    To then access Locust from a web browser, use the trick above:

    $ kubectl get pods -o=wide|grep locust

    In my environment, it returned a single line:

    locust-7885f7b458-hvchm                           1/1     Running   0          23h     10.244.3.30      pool-e85y5p9p2-7jkc5   <none>           <none>
    

    In column 7, it reports the node that it was run in; for me that is pool-e85y5p9p2-7jkc5. Remember that name. Then get the list of external IP addresses for your nodes:

    $ kubectl get nodes -o=wide

    Which displays on my system:

    NAME                   STATUS   ROLES    AGE   VERSION    INTERNAL-IP      EXTERNAL-IP       OS-IMAGE                       KERNEL-VERSION          CONTAINER-RUNTIME
    pool-e85y5p9p2-7jkc5   Ready    <none>   5d    v1.21.14   10.136.121.238   159.223.189.158   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkck   Ready    <none>   5d    v1.21.14   10.136.121.235   147.182.135.113   Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    pool-e85y5p9p2-7jkcs   Ready    <none>   5d    v1.21.14   10.136.121.237   137.184.105.17    Debian GNU/Linux 10 (buster)   5.10.0-0.bpo.15-amd64   containerd://1.4.13
    

    And I can see that the pool pool-e85y5p9p2-7jkc5 has external IP address of 159.223.189.158. Since the yaml exports the application on port 30015 on that IP, you can bring up a browser and enter in the url: http://[YOUR IP ADDRESS]:30015, which for me is: http://159.223.189.158:30015:

    Locust Entry

    LiteSpeed’s IP Address

    To be able to put load on LiteSpeed, you’ll need to know its exported IP address. Get the list of all exported services.

    $ kubectl get svc -A

    Which for me returns:

    NAMESPACE        NAME                             TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)                      AGE
    cert-manager     cert-manager                     ClusterIP      10.245.152.216   <none>            9402/TCP                     323d
    cert-manager     cert-manager-webhook             ClusterIP      10.245.60.0      <none>            443/TCP                      323d
    default          kubernetes                       ClusterIP      10.245.0.1       <none>            443/TCP                      340d
    gateway-system   gateway-api-admission-server     ClusterIP      10.245.91.141    <none>            443/TCP                      43d
    kube-system      dashboard-kubernetes-dashboard   ClusterIP      10.245.7.158     <none>            443/TCP                      339d
    kube-system      external-dns                     ClusterIP      10.245.107.183   <none>            7979/TCP                     9d
    kube-system      kube-dns                         ClusterIP      10.245.0.10      <none>            53/UDP,53/TCP,9153/TCP       340d
    kube-system      locust                           NodePort       10.245.43.158    <none>            8089:30015/TCP               3m31s
    kube-system      ls-k8s-webadc                    LoadBalancer   10.245.28.197    157.230.201.138   80:31743/TCP,443:30932/TCP   20h
    kube-system      metrics-server                   ClusterIP      10.245.83.231    <none>            443/TCP                      41h
    kube-system      podinfo                          NodePort       10.245.197.197   <none>            80:30001/TCP                 44h
    kube-system      prometheus-alertmanager          ClusterIP      10.245.0.72      <none>            80/TCP                       42h
    kube-system      prometheus-kube-state-metrics    ClusterIP      10.245.222.254   <none>            8080/TCP                     42h
    kube-system      prometheus-node-exporter         ClusterIP      10.245.200.251   <none>            9100/TCP                     42h
    kube-system      prometheus-pushgateway           ClusterIP      10.245.35.25     <none>            9091/TCP                     42h
    kube-system      prometheus-server                NodePort       10.245.254.164   <none>            80:30010/TCP                 42h
    

    Look at the NAME column and look for the name ls-k8s-webadc. In that row should be an EXTERNAL-IP address. That will be the address we will be putting load on. In my case it is 157.230.201.138

    Simulating Load

    Enter the following values in the Locust Start new load test panel:

    • Number of users: 100
    • Spawn rate: 10
    • Host: http://[YOUR IP ADDRESS] which for me would be http://157.230.201.138
      to
      …and press the Start swarming button.

    Monitoring Results

    Go back into Prometheus in your browser. You may need to press the Execute button several times and the + or - buttons to adjust the update frequency, and it may take up to 5 minutes for the results to show, but soon you’ll see a single line change into two or more lines.

    Prometheus Loaded

    You can also see the results from the Hotizontal Pod Autoscaler:

    $ kubectl describe hpa
    Name:                                                  ls-k8s-webadc
    Namespace:                                             kube-system
    Labels:                                                app.kubernetes.io/component=controller
                                                           app.kubernetes.io/instance=ls-k8s-webadc
                                                           app.kubernetes.io/managed-by=Helm
                                                           app.kubernetes.io/name=ls-k8s-webadc
                                                           helm.sh/chart=ls-k8s-webadc-0.1.28
    Annotations:                                           meta.helm.sh/release-name: ls-k8s-webadc
                                                           meta.helm.sh/release-namespace: kube-system
    CreationTimestamp:                                     Thu, 15 Sep 2022 13:31:46 -0400
    Reference:                                             Deployment/ls-k8s-webadc
    Metrics:                                               ( current / target )
      resource cpu on pods  (as a percentage of request):  70% (140m) / 50%
    Min replicas:                                          1
    Max replicas:                                          11
    Deployment pods:                                       5 current / 5 desired
    Conditions:
      Type            Status  Reason              Message
      ----            ------  ------              -------
      AbleToScale     True    ReadyForNewScale    recommended size matches current size
      ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
      ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
    Events:
      Type    Reason             Age                  From                       Message
      ----    ------             ----                 ----                       -------
      Normal  SuccessfulRescale  11m (x2 over 20h)    horizontal-pod-autoscaler  New size: 2; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  7m33s (x2 over 20h)  horizontal-pod-autoscaler  New size: 3; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  7m18s (x2 over 20h)  horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  2m2s (x2 over 20h)   horizontal-pod-autoscaler  New size: 5; reason: cpu resource utilization (percentage of request) above target
    

    In my case it wanted to increase the number of pods quite high, but was limited in resources to do so:

    $ kubectl get pods -A | grep ls-k8s-webadc-
    kube-system      ls-k8s-webadc-66d78d6755-6nw5w                    1/1     Running   0          11m
    kube-system      ls-k8s-webadc-66d78d6755-j9mmt                    0/1     Pending   0          5m29s
    kube-system      ls-k8s-webadc-66d78d6755-nmfkc                    1/1     Running   0          21h
    kube-system      ls-k8s-webadc-66d78d6755-q8fnj                    1/1     Running   0          15m
    kube-system      ls-k8s-webadc-66d78d6755-xp944                    0/1     Pending   0          10m
    

    Note that the status is Pending on a lot of the pods. A detailed description of one of the pending pods will show:

    $ kubectl describe pod ls-k8s-webadc-66d78d6755-xp944
    Name:           ls-k8s-webadc-66d78d6755-xp944
    Namespace:      kube-system
    Priority:       0
    Node:           <none>
    Labels:         app.kubernetes.io/component=controller
                    app.kubernetes.io/instance=ls-k8s-webadc
                    app.kubernetes.io/managed-by=Helm
                    app.kubernetes.io/name=ls-k8s-webadc
                    helm.sh/chart=ls-k8s-webadc-0.1.28
                    pod-template-hash=66d78d6755
    Annotations:    <none>
    Status:         Pending
    IP:             
    IPs:            <none>
    Controlled By:  ReplicaSet/ls-k8s-webadc-66d78d6755
    Containers:
      controller:
        Image:       docker.io/litespeedtech/ls-k8-staging:latest
        Ports:       80/TCP, 443/TCP
        Host Ports:  80/TCP, 443/TCP
        Args:
          /ls-k8s-up.sh
          --v=4
          --allow-internal-ip=true
          --healthz-port=11972
          --lslb-debug=false
          --lslb-enable-ocsp-stapling=false
          --lslb-http-port=80
          --lslb-https-port=443
          --enable-metrics=true
          --metrics-service-port=0
        Limits:
          cpu:  200m
        Requests:
          cpu:      200m
        Liveness:   http-get http://:11972/healthz delay=60s timeout=30s period=30s #success=1 #failure=3
        Readiness:  http-get http://:11972/healthz delay=60s timeout=30s period=30s #success=1 #failure=3
        Environment:
          POD_NAME:       ls-k8s-webadc-66d78d6755-xp944 (v1:metadata.name)
          POD_NAMESPACE:  kube-system (v1:metadata.namespace)
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nwspm (ro)
    Conditions:
      Type           Status
      PodScheduled   False 
    Volumes:
      kube-api-access-nwspm:
        Type:                    Projected (a volume that contains injected data from multiple sources)
        TokenExpirationSeconds:  3607
        ConfigMapName:           kube-root-ca.crt
        ConfigMapOptional:       <nil>
        DownwardAPI:             true
    QoS Class:                   Burstable
    Node-Selectors:              <none>
    Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
    Events:
      Type     Reason             Age                  From                Message
      ----     ------             ----                 ----                -------
      Normal   NotTriggerScaleUp  2m6s (x11 over 12m)  cluster-autoscaler  pod didn't trigger scale-up:
      Warning  FailedScheduling   55s (x14 over 13m)   default-scheduler   0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.
    

    The warning message at the bottom basically said that it was unable to scale the pod because there was not a free node to schedule it on. If there was, Prometheus would show additional lines. This is normal and expected.

    Removing Load

    When you remove load, the number of pods should be reduced. In the Locust browser screen press the Stop button. In Prometheus you’ll be able to see the load decrease. However, the number of pods will not go down for a while. To smooth the impact of scaling down, there is typically 5 minutes of reduced load per pod before it begins to scale down. This may mean up to 25 minutes before the number of pods is back to 1. You can watch the process with:

    $ kubectl describe hpa
    Name:                                                  ls-k8s-webadc
    Namespace:                                             kube-system
    Labels:                                                app.kubernetes.io/component=controller
                                                           app.kubernetes.io/instance=ls-k8s-webadc
                                                           app.kubernetes.io/managed-by=Helm
                                                           app.kubernetes.io/name=ls-k8s-webadc
                                                           helm.sh/chart=ls-k8s-webadc-0.1.28
    Annotations:                                           meta.helm.sh/release-name: ls-k8s-webadc
                                                           meta.helm.sh/release-namespace: kube-system
    CreationTimestamp:                                     Thu, 15 Sep 2022 13:31:46 -0400
    Reference:                                             Deployment/ls-k8s-webadc
    Metrics:                                               ( current / target )
      resource cpu on pods  (as a percentage of request):  4% (8m) / 50%
    Min replicas:                                          1
    Max replicas:                                          11
    Deployment pods:                                       1 current / 1 desired
    Conditions:
      Type            Status  Reason              Message
      ----            ------  ------              -------
      AbleToScale     True    ReadyForNewScale    recommended size matches current size
      ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
      ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
    Events:
      Type    Reason             Age                  From                       Message
      ----    ------             ----                 ----                       -------
      Normal  SuccessfulRescale  29m (x2 over 20h)    horizontal-pod-autoscaler  New size: 2; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  25m (x2 over 20h)    horizontal-pod-autoscaler  New size: 3; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  24m (x2 over 20h)    horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  19m (x2 over 20h)    horizontal-pod-autoscaler  New size: 5; reason: cpu resource utilization (percentage of request) above target
      Normal  SuccessfulRescale  2m59s (x2 over 20h)  horizontal-pod-autoscaler  New size: 1; reason: All metrics below target
    

    Cleaning Up

    You will want to remove the exposed services and pods, perhaps keeping Prometheus and the LiteSpeed Ingress Controller.

    To remove locust

    $ kubectl delete -f 2-locust.yaml

    To remove the simple application:

    $ kubectl delete -f 1-podinfo.yaml

    If you wish to remove Prometheus:

    $ helm delete prometheus

    If you wish to remove the LiteSpeed Ingress Controller:

    $ helm delete ls-k8s-webadc

    Fullfilling the Promise

    LiteSpeed’s WebADC Load Balancer already has a number of tools to scale to meet demand including:

    • Smart Botnet Detection
    • WordPress Protection from WordPress brute force attacks
    • Server-level reCAPTCHA
    • Multiple load balancing techniques
    • …and more…

    Taking advantage of the Kubernetes AutoScaler combined with its independent, stateless mode of operation allows your organization to expose the full value of all of the services that you’ve worked so hard to build.

  • WordPress, WooCommerce, and Kubernetes with LiteSpeed Ingress Controller

    WordPress, WooCommerce, and Kubernetes with LiteSpeed Ingress Controller

    WordPress, WooCommerce, and Kubernetes with LiteSpeed Ingress Controller

    In this post, you will learn to deploy WordPress, WooCommerce, and Kubernetes with LiteSpeed Ingress Controller. We’ll install the LiteSpeed Cache plugin, and load balance your environment using the LiteSpeed Ingress Controller. This real-world example, in a DigitalOcean environment, will use Kubernetes cert-manager to manage your certificate.

    Preparation

    This blog assumes little prior experience with Kubernetes, but does expect you to have kubectl and helm installed. You should have access to your cluster available to the console user and familiarity with text editing

    We’ll be using Digital Ocean for the example environment.

    • You will need kubectl working in your environment. See here for complete instructions.
    • You will need the LiteSpeed Ingress Controller installed and operational. See here for complete instructions. You can skip the Making HTTPS Work step for now as we will be doing that later.
    • You will need cert-manager installed and operational. See here for complete instructions. Perform the steps up to and including Creating a ClusterIssuer. The steps below that will define the Ingress.
    • You will need a real domain name that is available on the internet, and you will need to configure your environment to publish it. For Digital Ocean this is published using ExternalDNS described here.

    Create some sample definitions

    In addition to the previously mentioned preparation, we recommend the following sample definitions for simplicity:

    • Create a namespace to deploy the pod/service/ingress into. Our sample uses the namespace woo. Note that if you change this you will need to change the YAML file’s namespace parameter to match the changed name:
    kubectl create ns woo
    

    Create a number of secrets to hold some useful definitions. You can change these and just note to change their YAML references below:

    • The database name which we’ll name multitenant-wp
    • The admin database password which we’ll name mysqlpwd
    • The database user which we’ll name userwp
    • The database user password which we’ll name pwdwp
    kubectl create -n woo secret generic mysql-database --from-literal=database=multitenant_wp
    kubectl create -n woo secret generic mysql-password --from-literal=password=mysqlpwd
    kubectl create -n woo secret generic mysql-user --from-literal=username=userwp
    kubectl create -n woo secret generic mysql-user-password --from-literal=password=pwdwp
    

    Create the persistent volumes

    You will need persistent volume definitions. To create them use the text editor of your choice and create the file named 1-pv.yaml:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: mysql-pv
      namespace: woo
    spec:
      storageClassName: do-block-storage
      capacity:
        storage: 20Gi
      accessModes:
        - ReadWriteOnce
      hostPath:
        path: "/var/lib/mysql"
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mysql-pv-claim
      namespace: woo
    spec:
      storageClassName: do-block-storage
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: wordpress-pv
      namespace: woo
    spec:
      storageClassName: do-block-storage
      capacity: 
        storage: 30Gi
      accessModes:
        - ReadWriteOnce
      hostPath:
        path: "/var/www"
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: wordpress-pv-claim
      namespace: woo
    spec:
      storageClassName: do-block-storage
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 30Gi
    ---
    

    If you changed your namespace you’ll need to update the namespace definitions above.
    To create the volumes, apply the 1-pv.yaml file:

    kubectl apply -f 1-pv.yaml
    

    Install MySQL for WordPress

    To install WordPress, you’ll need to install MySQL first and use the persistent volumes you created above. Create the file named: 2-mysql.yaml:

    apiVersion: v1
    kind: Service
    metadata: 
      name: mysql-wp
      namespace: woo
    spec:
      ports:
        - port: 3306
      selector:
        app: wordpress
        tier: mysql
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mysql-wp
      namespace: woo
    spec:
      selector:
        matchLabels:
          app: wordpress
          tier: mysql
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: wordpress
            tier: mysql
        spec:
          containers:
          - image: mysql:latest
            name: mysql
            env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-password
                  key: password
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-user
                  key: username
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-user-password
                  key: password
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: mysql-database
                  key: database
            ports:
            - containerPort: 3306
              name: mysql
            volumeMounts:
            - name: persistent-storage
              mountPath: /var/lib/mysql
          volumes:
          - name: persistent-storage
            persistentVolumeClaim:
              claimName: mysql-pv-claim
    ---
    

    If you changed the namespace or the MySQL user or passwords secret titles you’ll need to update the definitions above.

    To install MySQL apply the 2-mysql.yaml file:

    kubectl apply -f 2-mysql.yaml
    

    Install WordPress

    To install WordPress itself, create the file named 3-wordpress.yaml:

    apiVersion: v1
    kind: Service
    metadata: 
      name: wordpress
      namespace: woo
    spec:
      ports:
        - port: 80
      selector:
        app: wordpress
        tier: web
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wordpress
      namespace: woo
    spec:
      selector:
        matchLabels:
          app: wordpress
          tier: web
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: wordpress
            tier: web
        spec:
          containers:
          - image: wordpress:php8.1-apache
            name: wordpress
            env:
            - name: WORDPRESS_DB_HOST
              value: mysql-wp:3306
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-user-password
                  key: password
            - name: WORDPRESS_DB_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-user
                  key: username
            - name: WORDPRESS_DB_NAME
              valueFrom:
                secretKeyRef:
                  name: mysql-database
                  key: database
            ports:
            - containerPort: 80
              name: wordpress
            volumeMounts:
            - name: persistent-storage
              mountPath: /var/www/html
          volumes:
          - name: persistent-storage
            persistentVolumeClaim:
              claimName: wordpress-pv-claim
    

    If you changed the namespace or the MySQL user or passwords secret titles you’ll need to update the definitions above.

    To install WordPress apply the 3.mysql.yaml file:

    kubectl apply -f 3-wordpress.yaml
    

    Expose WordPress

    Once you install WordPress you’ll want to make it available to the internet, and you do that with a Kubernetes Ingress definition. We strongly recommend that you use a real internet DNS name for your environment. This will let you use Let’s Encrypt as described in LiteSpeed’s Using Cert-manager documentation, and access it via the DNS name.

    To create the Ingress, you’ll need to have created the DNS name, which is typically done by purchasing the DNS name from a vendor. After it’s available, replace the reference to YOUR DNS NAME with the actual DNS name in the example below, and save as the file 4-ingress.yaml:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: wordpress
      namespace: woo
      annotations:
        kubernetes.io/ingress.class: litespeedtech.com/lslbd
        cert-manager.io/cluster-issuer: letsencrypt-production
    spec:
      rules:
      - host: YOUR DNS NAME
        http:
         paths:
         - path: "/"
           pathType: Prefix
           backend:
             service:
               name: wordpress
               port:
                 number: 80
      tls:
      - hosts:
        - YOUR DNS NAME
        secretName: YOUR DNS NAME
    

    To install it:

    kubectl apply -f 4-ingress.yaml
    

    You know if you have everything right if you can go to your website via http://YOUR_DNS_NAME/

    Configure WordPress

    When you go to your website you will see the WordPress initial screen prompting you for your language:

    WordPress Language

    Select your language and press Continue:

    WordPress Configuration

    Fill in the required fields and press Install WordPress. You should get a message indicating that it was successfully installed, and you will be asked to login using the credentials you just entered. Reenter the credentials and enter WordPress.

    Install LiteSpeed Cache

    To install the LiteSpeed Cache plugin follow the instructions here

    Install WooCommerce

    To install the WooCommerce plugIn follow the instructions here

    You can now configure WooCommerce with the needs of your store in mind.

    You have a store

    While there is still a bit of work to do in populating your store, the framework for the store is now complete. It is accessible via HTTPS. It is extremely extensible:

    • By using Kubernetes now, you can add other applications, stores, web sites and more by adding more deployment/services/ingresses.
    • Kubernetes Ingress lets you use the same HTTPS definition with different directory names to reference different backends, allowing you to have documention backends, additional stores, third-party sellers and more.
    • Because you used cert-manager, your HTTPS certificate will be kept up to date automatically.
    • If you have performance issues, there are metrics that can be used to help you identify bottlenecks. If the load balancer needs to be scaled, it’s easy to do.
    • Kubernetes will monitor the health of all deployed applications. If something goes down it’s automatically restarted.

    Deleting everything and putting it all back

    If you need to delete everything to start over or simply to clean it up after testing, you should delete the entities in the reverse order you created them:

    kubectl delete -f 4-ingress.yaml
    kubectl delete -f 3-wordpress.yaml
    kubectl delete -f 2-mssql.yaml
    kubectl delete -f 1-pv.yaml
    

    Delete the secrets:

    kubectl delete -n woo secret mysql-database
    kubectl delete -n woo secret mysql-password
    kubectl delete -n woo secret mysql-user
    kubectl delete -n woo secret mysql-user-password
    

    We do not recommend that you delete the namespace as it may enter a Terminating condition it may not be able to get out of.

    What a way to start!

    When you need a production quality store, Kubernetes with the LiteSpeed Ingress Controller gives you the full power of all of the tools you need to get going.

  • LSCWP 5.0: Auto CDN Setup

    LSCWP 5.0: Auto CDN Setup

    Automatic QUIC.cloud Setup in LiteSpeed Cache v5.0 for WordPress

    Version 5.0 of the LiteSpeed Cache for WordPress plugin has arrived, and it provides a simple automated process to get you started with QUIC.cloud CDN!

    Whether you prefer to stay in the driver’s seat and follow our existing manual onboarding procedure, or you’d like to let the plugin take the wheel, the end result is the same: your WordPress site powered by LiteSpeed Cache and QUIC.cloud CDN!

    Please Note: As of March, 2025, and Version 7.0 of the LiteSpeed Cache plugin, the CDN setup process has been simplified and completely changed. As such, we’ve rewritten the instructions below to reflect the new way of getting started with QUIC.cloud CDN.

    Enable QUIC.cloud services

    Enable QUIC.cloud services

    We’re going to assume that this domain isn’t connected to QUIC.cloud yet, and that you are seeing an Enable QUIC.cloud services button. If this is not the case, and you have already connected your domain, you can skip a lot of what is in this blog post. You might prefer to check out the documentation, starting at the Enable QUIC.cloud CDN section.

    Press the Enable QUIC.cloud services button. QUIC.cloud will attempt to detect your server type and IP. Wait a few moments for this to complete.

    Create a QUIC.cloud Account

    Next, you’ll be prompted to create a QUIC.cloud account to link to your WordPress site.

    (If you already have a QUIC.cloud account for another domain, there is no need to create a new account. You can have multiple domains in your QUIC.cloud account. Log in to your existing account, and this domain will be added.)

    Create a QUIC.cloud account

    Enter your email address, choose a password, agree to the QUIC.cloud terms and conditions, and click Register. Check your email for a validation message from QUIC.cloud, and confirm your account by clicking the activation link within.

    Your QUIC.cloud-WordPress connection is complete!

    Set up the CDN

    Next, you’ll be prompted to choose whether to enable the CDN or finish linking without the CDN.

    Set up the CDN

    Click the Enable the CDN button.

    Point your DNS to QUIC.cloud

    If you plan to use QUIC.cloud CDN, you must point your domain’s DNS in our direction. You can either do this by updating CNAME records, or by switching to our own QUIC.cloud DNS service.

    For the purposes of this blog post we are going to assume you wish to use QUIC.cloud DNS. If this is not the case, please see QUIC.cloud’s DNS documentation for other options.

    Point your DNS to QUIC.cloud

    Select I want to use QUIC.cloud DNS and press Continue.

    Import existing DNS records to QUIC.cloud

    QUIC.cloud will attempt to detect your domain’s DNS records and import them. Please be patient while it works, and don’t close the window during this time.

    Import existing DNS records to QUIC.cloud

    Once detection is complete, you will be asked to confirm that your DNS information is correct. Accept all of the detected records, or uncheck any that you no longer need, and click the Add DNS Zone button.

    Update your nameservers

    Once your DNS records have been imported into QUIC.cloud, you will need to instruct your domain registrar where to find your DNS records.

    QUIC.cloud will attempt to verify that your nameservers are correctly set up at your domain registrar.

    Your domain registrar is the provider you purchased your domain name from. Sometimes this is the same as your hosting provider, but that is not always the case. Make sure that you are in the right place before you change anything!

    Log in to your domain registrar. Look for the area of their site which allows you to manage Nameservers. It may be called “DNS Zone” or “Manage DNS” or something similar. Your previous DNS provider’s nameservers should still be on file. You’ll see them listed under NS1, NS2, and possibly NS3 and NS4 as well.

    Update your Nameservers

    Change the NS1 and NS2 records, to match those displayed in the dialog box under Nameservers assigned to your domain. In this example, that would be jon.quicns.com and kevin.quicns.com. If your domain registrar has additional records (NS3, NS4, etc.) erase those values. You should now only have QUIC.cloud-provided NS records at your domain registrar.

    Click the Finish Link Setup and go back to WordPress button.

    Verify DNS

    After the above steps are complete, you can check the status of your domain’s DNS with a tool like DNSChecker.org. There are typically delays due to DNS caching, but if your DNS has still not propagated after 24 hours, please open a support ticket and we’ll look into it.

    Allowlist QUIC.cloud IPs

    You’re almost finished! In order for QUIC.cloud to perform its services, it needs to be able to communicate with your origin server. Some server-level and application-level firewalls may interfere with this communication. If you have one of these firewalls in place, you will need to make sure it is allowing QUIC.cloud IP addresses.

    Please see Adding QUIC.cloud IPs to Allowlist for more information.

    All Done!

    Congratulations! You are now using QUIC.cloud CDN!

    You can use the HTTP/3 Check tool to verify that your site is being served by QUIC.cloud and supports the latest cutting edge Internet protocols. Look for the x-qc-pop header to locate the QUIC.cloud node that served the request, and the x-qc-cache header to determine whether the page was cached at the node.

    You can keep an eye on your bandwidth usage and tweak your CDN settings in your QUIC.cloud Dashboard.

    This content was last verified and updated in April of 2025. If you find an inaccuracy, please let us know! In the meantime, see our documentation site for the most up-to-date information.