Blog

  • How to Block WordPress Spam Comment Bots With Fail2ban Rate Limiting

    How to Block WordPress Spam Comment Bots With Fail2ban Rate Limiting

    Is your website drowning in WordPress comment spam? If you’re battling endless waves of bot-generated junk, you’ve likely tried the usual suspects…

    • Perhaps you’ve implemented CAPTCHAs, only to find they frustrate legitimate users, can still be bypassed by sophisticated bots, and potentially slow down page loads.
    • Maybe you’ve installed anti-spam plugins but worry about their impact on site performance, potential conflicts they introduce, or recurring subscription fees.

    Do you ever wish there was a different, more fundamental way to tackle this?

    Fortunately, there is.

    This guide will walk you through the process of setting up Fail2Ban on your server (specifically tailored for a RunCloud environment, but it is easily adaptable on any other server) to automatically block the IP addresses of bots or individuals who attempt to post comments too frequently on your WordPress sites.

    Instead of analyzing the content of the comment, which can be complex and resource-intensive, this method focuses purely on the frequency of comment submission attempts.

    We will configure Fail2Ban to monitor your web server’s access logs for POST requests to the wp-comments-post.php file. If any single IP address makes more than five such requests within a one-hour period, Fail2Ban will automatically block that IP address at the firewall level for an initial period, with subsequent blocks increasing in duration for repeat offenders.

    Why Use Fail2Ban for Blocking Spam Comments

    We have already written a detailed guide on how to protect your WordPress login page using Fail2Ban. However, you can also use Fail2Ban to reduce spam comments on your site.

    The core idea here is simple: legitimate users rarely post multiple comments in rapid succession across different posts within a short timeframe. Automated bots, however, often hit the wp-comments-post.php endpoint repeatedly as they crawl sites looking for comment forms.

    By setting maxretry = 5 and findtime = 1h, we are telling Fail2Ban: “If you see the same IP address making a sixth attempt (or more) to post a comment via wp-comments-post.php within any 60-minute window, block that IP address.” The first five attempts are allowed, but the sixth triggers the ban.

    Benefits of Using Fail2Ban for Rate Limiting WordPress Comments

    • Server-Wide Protection: This single Fail2Ban rule protects all WordPress sites hosted on the same server that log to the specified NGINX log directory, without needing configuration on each site. If a bot attempts to spam comments across multiple websites hosted on your server simultaneously, its IP address will be quickly blocked based on the cumulative activity seen in the logs. 
    • Protection across the entire website: It doesn’t just stop users from posting comments, it completely blocks the user from even opening the site or accessing it via API for the defined duration. This is much stronger than blocking a spam comment.
    • More Robust Than User/Email Blocking: Spammers frequently cycle through fake or stolen usernames and email addresses, making blocks based on that data less effective; however, obtaining and rotating unique IP addresses at scale is significantly harder and more expensive for them.
    • Protects from Trusted user accounts: Even if a normally trusted (moderated) user account is compromised or a bot inadvertently slips through initial approval, this Fail2Ban rate limit ensures that the user can only submit a handful of comments before their excessive posting frequency triggers an automatic IP block.
    • No Plugin Bloat: This method avoids installing additional WordPress plugins, keeping your site’s codebase leaner and reducing potential third-party code conflicts or vulnerabilities.
    • Firewall-Level Efficiency: The IP blocking is handled by the server’s firewall (like iptables or nftables), which is highly efficient and prevents the spam traffic from even reaching WordPress or PHP, reducing server load compared to application-level filtering.
    • Adjustable Thresholds: You can easily modify the maxretry (attempts allowed) and findtime (time window) parameters in the Fail2Ban jail configuration to make the blocking more or less aggressive based on your observations.

    Drawbacks of Using Fail2Ban for Rate Limiting WordPress Comments

    • Doesn’t Stop Initial Spam: This method is reactive based on frequency. It will not prevent the first one or two spam comments from a new IP address from being submitted; the block only occurs after the threshold (maxretry) is exceeded within the findtime. You still need WordPress-level tools (like Akismet, moderation queues, or disabling comments) to handle those initial attempts.

    📖 Suggested read: 11 Alternatives to reCAPTCHA to Protect Your Site from Spam

    Step-by-Step Instructions for Rate Limiting WordPress Comments Without CAPTCHA

    This section will walk you through the steps for configuring your Fail2Ban client to block spam comments automatically. But before we go ahead, make sure you satisfy the following requirements:

    Prerequisites

    • You will need SSH access to your server with sudo privileges.
    • You need to ensure that Fail2Ban is installed and running on your server. If you are using RunCloud, you don’t need to do anything, as RunCloud includes Fail2Ban out of the box.

    📖 Suggested read: DKIM – What Is It & Why Your Emails Need It

    Step 1: Locate Web Server Logs

    Fail2Ban monitors server logs to block and restrict server access. Therefore, the first step is to identify the location of the NGINX access log files that record incoming requests to your WordPress sites, as Fail2Ban needs to monitor these files for comment submission attempts.

    On servers managed by RunCloud, NGINX stores separate access logs for each web application you’ve created within the /home/<username>/logs/nginx/ directory, named following a pattern like your-app-name_access.log.

    Since you might have multiple WordPress sites (web applications) on the same server and want Fail2Ban to protect all of them with this rule, you need to ensure the logpath directive we configure later correctly points to all relevant access logs.

    Viewing logs for fail2ban access

    📖 Suggested read: 10 Security Tips to Secure a VPS Server in 2025 [Ultimate Guide]

    Step 2: Create the Fail2Ban Filter Definition

    After locating the log files, we need to tell Fail2Ban what pattern to look for in the log files. We’ll create a filter configuration file specifically for WordPress comment posts.

    Open or create the filter file using a text editor like nano:

    sudo nano /etc/fail2ban/filter.d/wordpress-comment.conf

    Paste the following content into the file:

    # Fail2Ban filter for WordPress comment posting attempts
    # This filter looks for POST requests to wp-comments-post.php
    [Definition]
    failregex = ^<HOST> .* "POST /wp-comments-post.php HTTP.*

    Let’s understand this code snippet bit by bit.

    • [Definition]: This standard section header is required for Fail2Ban filters.
    • failregex: This line defines the regular expression to match:
      • ^<HOST>: Matches the client’s IP address (Fail2Ban automatically replaces <HOST> with the IP pattern) at the beginning of the log line.
      • .*: Matches any characters between the IP address and the specific request string.
      • "POST /wp-comments-post.php HTTP.*: Matches the literal string indicating a POST request being made to the WordPress comment processing script.

    After editing the file, save it and exit the editor (in nano, press Ctrl+X, Y, then Enter).

    Step 3: Test the Regular Expression (Optional but Recommended)

    Before enabling the rule, it’s wise to test your failregex against one of your actual NGINX access logs to ensure it correctly identifies comment posting attempts.

    Run the fail2ban-regex command, replacing your-app-name_access.log with the actual name of one of your application’s access log files:

    sudo fail2ban-regex /home/runcloud/logs/nginx/your-app-name_access.log /etc/fail2ban/filter.d/wordpress-comment.conf
    fail2ban regex matching for blocking SPAM comments

    Analyze the provided output. Fail2Ban will report the following metrics:

    1. Lines matched by failregex.
    2. Lines ignored by ignoreregex (should be 0).
    3. Total lines read.

    You should see a positive number of matches if your log file contains recent comment posting attempts (legitimate or spam). It will also list the actual log lines that matched, allowing you to verify. If you don’t see any matched entries, then you will need to troubleshoot your fail-regex before moving forward.

    📖 Suggested read: The 6 Best WordPress Security Plugins (2022)

    Step 4: Create the Fail2Ban Jail Configuration

    Now, we define a “jail” that uses the filter we created and specifies the conditions for banning (like maxretry, findtime) and the ban duration (bantime). It’s important to add this configuration to jail.local to avoid it being overwritten by package updates.

    Open /etc/fail2ban/jail.local with your text editor. If this file doesn’t exist, you can create a new one. By default, Fail2Ban reads from /etc/fail2ban/jail.conf, and it’s best practice to copy jail.conf to jail.local and make your customizations there.

    sudo nano /etc/fail2ban/jail.local

    Scroll to the end of the file and add the following jail definition:

    [wordpress-comment-rate-limit]
    backend = auto
    allowipv6 = auto
    enabled = true
    port = http,https
    filter = wordpress-comment
    logpath = /home/runcloud/logs/nginx/*_access.log
    bantime.increment = true
    bantime.factor = 6
    bantime.maxtime = 1w
    bantime = 3h
    findtime = 1h
    maxretry = 5

    We have already written a detailed Guide to Configuring Fail2Ban, but let’s quickly break down these parameters to understand what they do:

    • [wordpress-comment-rate-limit]: A unique name for this specific jail configuration.
    • enabled = true: Activates this jail. Set to false to disable it without deleting the configuration.
    • port = http,https: Specifies the ports Fail2Ban should block traffic on for the banned IP. Blocking web traffic is appropriate here.
    • filter = wordpress-comment: Tells Fail2Ban to use the filter definition we created in Step 1 (referencing the filename wordpress-comment.conf without the .conf extension).
    • logpath = /home/runcloud/logs/nginx/*_access.log: Specifies the log file(s) to monitor. The wildcard * ensures it monitors the NGINX access logs for all applications managed by RunCloud in the standard location. Adjust this path if your logs are stored elsewhere.
    • maxretry = 5: The number of matches (comment posts) allowed from a single IP before triggering a ban. A value of 2 means the third attempt will trigger the ban.
    • findtime = 1h: The time window within which the maxretry count must occur. If an IP posts more than 5 times within any 1-hour period, it gets banned.
    • bantime = 3h: The initial duration for which the IP address will be banned (3 hours).
    • bantime.increment = true: Enables escalating ban times for repeat offenders.
    • bantime.factor = 6: Multiplier for the ban time. Each subsequent ban for the same IP will be multiplied by this factor (e.g., 2nd ban = 3h * 6 = 18 hours).
    • bantime.maxtime = 1w: The maximum duration an IP can be banned for (1 week). Even with the factor, bans won’t exceed this length.

    If you want to monitor multiple websites using the single configuration, then you can either individually list out the log file for each of the application in its separate line (as shown above) or you can use a wildcard to read all the log files in a directory (/home/runcloud/logs/nginx/*_access.log).

    After making the necessary changes, you can save the file and exit the editor (Ctrl+X, Y, Enter in nano).

    📖 Suggested read: How to Use ModSecurity and OWASP CRS for Web App Firewall (WAF) to Secure Your Website

    Step 5: Reload Fail2Ban Configuration

    For the new filter and jail to take effect, you must reload the Fail2Ban service. To do this, you can simply execute the following command in your terminal:

    sudo systemctl reload fail2ban
    sudo systemctl status fail2ban

    Fail2Ban will now start monitoring the specified NGINX logs using your new rule. Now, whenever someone tries to repeatedly post several comments in a short period, your firewall will completely block that IP address for the defined period. 

    If you accidentally block yourself, read our guide on How to Unban an IP Address in Fail2Ban.

    Step 6: Monitor Fail2Ban (Optional but Recommended)

    After enabling the jail, you can check the status of Fail2Ban and see if your new jail is active and if any IPs have been banned. Check the overall status and list active jails:

    sudo fail2ban-client status

    Additionally, you can also get detailed status for your specific jail using the following command:

    sudo fail2ban-client status wordpress-comment-rate-limit

    The above command will show if the jail is running, the filter being used, the log paths, and, importantly, a list of IP addresses currently banned by this specific jail.

    📖 Suggested read: PHP Security – Best Practices To Secure Your Web App in 2025

    Final Thoughts

    This guide has explored an effective, server-level technique to mitigate WordPress comment spam by implementing Fail2Ban rate limiting. This method tackles the problem from a different angle, focusing on the frequency of posting attempts rather than just the content. It provides a powerful layer of defense against automated bots hammering your wp-comments-post.php endpoint.

    What makes this approach particularly effective and distinct from standard WordPress anti-spam plugins is its server-wide application. A single Fail2Ban rule protects all the WordPress sites hosted on your RunCloud server, efficiently blocking malicious IP addresses at the firewall level before they can strain your web application resources. This is usually unachievable with site-specific plugins alone.

    By using Fail2Ban, you gain efficient, low-overhead protection that complements your existing WordPress security practices. This highlights the power of RunCloud: it provides an intuitive platform for managing your servers and applications while still granting you the full underlying access and control necessary to implement advanced, custom security measures like this Fail2Ban configuration.

    Ready to experience powerful, flexible server management that doesn’t lock you out? Sign up for RunCloud today and take control of your web hosting environment.

    FAQs on Stopping WordPress Comment Spam

    Does disabling comments improve site security?

    Yes, disabling comments entirely reduces your site’s attack surface by removing a primary vector for user-submitted content and potential code injection attempts. Although it is not a complete security solution, it eliminates comment-specific vulnerabilities and simplifies security management. But it also removes the way you interact with your users.

    Can comment spam hurt my SEO?

    Absolutely. Excessive spam comments filled with low-quality or malicious links can dilute your page quality, negatively impact user experience, and potentially lead to search engine penalties. They also consume crawl budget and server resources that could be better used on legitimate content.

    Is it safe to allow comments from registered users only?

    It’s safer than allowing anonymous comments, significantly reducing bot spam, but it doesn’t eliminate the threat entirely, as bots can automate registration. To stop fake user signups, you should also implement strong registration security, like email verification and reCAPTCHA on registration forms.

  • How to Install WordPress on Ubuntu

    How to Install WordPress on Ubuntu

    Most Ubuntu servers can handle far more than a single website. Hosting multiple sites on the same server helps you use resources more efficiently and cut costs.

    This guide will walk you through the essential steps for installing and configuring multiple WordPress websites using the popular NGINX (LEMP) stack.

    Why Host Multiple Sites on a Single Server?

    Before diving into the technical steps, let’s clarify why consolidating websites onto one server using NGINX is such a good strategy:

    1. Significant Cost Savings: This is often the most compelling benefit. Instead of paying for multiple hosting plans or servers, you use the hardware or VPS plan you already have, drastically reducing monthly hosting costs.
    2. Optimized Resource Utilization: Make full use of your server’s CPU, RAM, and storage. Many websites, especially those with low-to-moderate or complementary traffic patterns (e.g., one busy during the day, another at night), can coexist happily without demanding excessive individual server resources.
    3. Easier Maintenance: Managing updates and configurations on a single server is often simpler than maintaining multiple separate environments.
    4. Centralized Infrastructure: Server-wide tasks like backups, security scanning, or performance monitoring become more streamlined when focused on a single machine hosting multiple WordPress sites.

    Steps for Hosting Multiple WordPress Sites on Ubuntu via NGINX

    Follow these steps to host multiple WordPress sites on a single Ubuntu server using the NGINX stack.

    For enhanced security and easier management down the line, we’ll follow the best practice of creating a separate database and a dedicated database user for each WordPress site. This isolates each site’s data, preventing potential issues on one site from affecting others.

    Step 1: Install the LEMP Stack (NGINX, MariaDB/MySQL, PHP)

    First, install the LEMP stack (Linux, NGINX, MariaDB, and PHP) which provides the foundation for your WordPress sites:

    • (L)inux: The operating system (Ubuntu, in our case).
    • (E)NGINX: (Pronounced “Engine-X”) Our high-performance web server. This software listens for incoming connections from visitors’ browsers and serves the appropriate web pages or passes requests to other processes (like PHP).
    • (M)ariaDB/MySQL: The database system that stores WordPress content. WordPress needs a database to store posts, pages, user information, settings, theme/plugin options, and more. We’ll install MariaDB, a widely used, community-developed fork of MySQL, which functions as a seamless replacement.
    • (P)HP: WordPress uses the PHP scripting language.
      • php-fpm (FastCGI Process Manager): This library serves web requests with NGINX.
      • php-mysql: WordPress uses this library to communicate with the database.

    Execute the following commands on your Ubuntu server to install the necessary software:

    sudo apt update
    sudo apt install nginx php8.3-cli php8.3-fpm php8.3-mysql mariadb-server -y

    In addition to this, WordPress also relies on several specific PHP extensions to perform various tasks such as handling images (php-gd), managing international characters (php-intl, php-mbstring), dealing with XML data (php-xml, php-xmlrpc), working with zip files (php-zip), and making external requests (php-curl). We need to install these alongside PHP-FPM.

    Install these PHP extensions now to avoid errors later:

    sudo apt install php8.3-curl php8.3-gd php8.3-intl php8.3-mbstring php8.3-soap php8.3-xml php8.3-zip -y

    With the core LEMP stack installed, our server now has the essential building blocks ready.

    Step 2: Secure MariaDB/MySQL Installation

    After installing the database server, you need to run the included security script to initialize your database.

    Run the security script and follow the prompts to:

    • Set a root password
    • Remove anonymous users
    • Disallow remote root login
    • Delete the test database
    • Reload privileges
    sudo mysql_secure_installation

    This process is fairly simple, just follow the on-screen prompts and select the default options.

    📖 Suggested read: How to Change/Reset MySQL Root Password on Ubuntu Linux?

    Step 3: Create Database and User for the First WordPress Site

    Create a separate database and user for each site to isolate data and improve security. If you create multiple websites on the same server, you must execute the following commands separately for each site you create, and with unique credentials.

    Log in to the MariaDB/MySQL shell as root:

    sudo mysql -u root -p

    Enter the root password you set during mysql_secure_installation in Step 2 and then create the database using the following command (use a descriptive name, e.g., runcloud_site1_db):

    CREATE DATABASE runcloud_site1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

    Create a dedicated database user (replace runcloud_site1_user and YourStrongRunCloudPassword):

    CREATE USER 'runcloud_site1_user'@'localhost' IDENTIFIED BY 'YourStrongRunCloudPassword';

    Using ‘localhost’ means this user can only connect from the server, which is more secure.

    Grant privileges to this newly created user only on their specific database:

    GRANT ALL PRIVILEGES ON runcloud_site1_db.* TO 'runcloud_site1_user'@'localhost';

    Apply the changes and exit the MariaDB/MySQL shell:

    FLUSH PRIVILEGES;
    EXIT;

    Step 4: Download and Prepare WordPress Files for the First Site

    Next, you need to download and extract the WordPress core files on your server. Before doing that, you must decide where to keep these files. Most website administrators keep these files in the /var/www/ directory. You can do this using the following command:

    sudo mkdir -p /var/www/runcloud_site1.com/public_html

    In the above command, replace runcloud_site1.com with the actual domain or a descriptive name for the site.

    Download and extract WordPress into your site’s root folder:

    cd /tmp
    wget https://wordpress.org/latest.tar.gz

    Extract the archive into the correct folder. Once again, make sure to replace the runcloud_site1.com with the name of the folder that you created earlier.

    sudo tar -xzf latest.tar.gz -C /var/www/runcloud_site1.com/public_html/ --strip-components=1

    Set the correct ownership and permissions so NGINX and PHP-FPM can access them. To do this, replace the runcloud_site1.com in the following command with your domain name and run it in your terminal:

    sudo chown -R www-data:www-data /var/www/runcloud_site1.com/public_html

    Step 5: Configure NGINX Server Block for the First Site

    NGINX uses server block files (similar to Apache’s Virtual Hosts) to manage individual sites. Inside each block, we will define important details about how to handle web requests for this website.

    1. server_name: This tells NGINX which domain name(s) (like yourdomain.com or www.yourdomain.com) this block is responsible for.
    2. root: This specifies the exact directory on your server where the website’s files (your WordPress installation) are located.

    By creating a separate server block for each website, NGINX knows precisely where to direct incoming traffic based on the requested domain.

    Create a new NGINX configuration file for your site in sites-available using the following command:

    sudo nano /etc/nginx/sites-available/runcloud_site1.com.conf

    In this config file, paste the configuration below, making sure you first replace the following placeholders:

    1. runcloud_site1.com and www.runcloud_site1.com with your actual domain(s) or any subdomain you configure in step 6.
    2. /var/www/runcloud_site1.com/public_html with the correct path to your site’s files.
    3. php8.3-fpm.sock with the correct PHP-FPM socket path if you are using a different PHP version.

    If you are unsure how to do this, refer to our blog post, which explains how to edit files on remote servers with SSH and Nano.

    server {
        listen 80;
        listen [::]:80; # For IPv6
        server_name runcloud_site1.com www.runcloud_site1.com; # Your domain(s) here
        root /var/www/runcloud_site1.com/public_html; # Path to WP files
        index index.php index.html index.htm;
        # Handle requests - try file, then directory, then pass to WordPress
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
        # Pass PHP scripts to PHP-FPM
        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            # Make sure the socket path matches your PHP version
            fastcgi_pass unix:/run/php/php8.3-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
        location = /wp-config.php {
            deny all;
        }
        # Add caching headers for static files (optional but recommended)
        location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ {
            expires 1M;
            access_log off;
            add_header Cache-Control "public, max-age=604800";
        }
        # Handle favicon/robots.txt directly (optional)
        location = /favicon.ico { log_not_found off; access_log off; }
        location = /robots.txt { log_not_found off; access_log off; allow all; }
    }

    Save and close the file (Ctrl+X, then Y, then Enter).

    After this, you need to enable the site by creating a symbolic link from sites-available to sites-enabled:

    sudo ln -s /etc/nginx/sites-available/runcloud_site1.com.conf /etc/nginx/sites-enabled/

    After creating the configuration, you can deploy it immediately. However, it is always a good idea to test this configuration before deploying.

    Run the following command to check the syntax of your configuration file:

    sudo nginx -t

    If you get a message that says “test is successful”, you can proceed to the next step. Otherwise, you will need to review your config file for typos.

    Finally, reload NGINX to load the new site configuration using the following command:

    sudo systemctl reload nginx

    Step 6: Configure DNS Records

    Ideally, you should configure your DNS records first, and then install WordPress on your server. DNS propagation is a slow process, and it can take anywhere between 30 seconds and 48 hours for the changes to propagate.

    The exact steps to do this will vary depending on your VPS provider and DNS registrar. For example, if you are using DigitalOcean to host your server and purchased your domain from Cloudflare, then you will need to log in to your Cloudflare account and create an A record for your domain (runcloud_site1.com) pointing to your server’s public IPv4 address.

    Also, create a CNAME record for www pointing to runcloud_site1.com, or a separate A record if you prefer. Add AAAA records if using IPv6.

    If you are hosting multiple websites on the same server, then you will need to create a separate DNS record for each domain name and point them to the same IP address.

    If you face any errors or want to learn more, then we recommend visiting the RunCloud blog, where we have already published in-depth articles on the following topics:

    Step 7: Run the WordPress Installation

    After creating your DNS records, wait a couple of minutes. Once the DNS records have propagated, open your web browser and navigate to your domain name (e.g., http://runcloud_site1.com).

    You should see the WordPress setup screen. Select your language.

    installing WordPress on ubuntu linux server

    In the next step, you’ll be asked for database information. Enter the details you created in Step 3:

    • Database Name: runcloud_site1_db
    • Username: runcloud_site1_user
    • Password: YourStrongRunCloudPassword
    • Database Host: localhost
    • Table Prefix: wp_ (or change if desired)

    WordPress will attempt to connect to the database and create the wp-config.php file. Once the database connection is successful, click “Run the installation“.

    On the next screen, provide your site title, create an administrator username with a strong password, and enter your email address.

    Finally, click “Install WordPress“. Once the installation is complete, you will be greeted with the following screen:

    Now you can log in to your new WordPress dashboard!

    Step 8: Setting Up Additional WordPress Sites (Optional)

    To host more websites (e.g., site2.org), repeat the relevant steps for each new site:

    1. Database: Repeat Step 3 to create a new, separate database (e.g., site2_db) and a new, dedicated user (e.g., site2_user) with a unique, strong password, granting privileges only on site2_db.
    1. Files: Repeat Step 4 to create a new directory (e.g., /var/www/site2.org/public_html), download/extract WordPress into it, and set the correct www-data ownership.
    2. NGINX Config: Repeat Step 5 to create a new NGINX server block file (e.g., /etc/nginx/sites-available/site2.org.conf). Make sure to update the server_name directive to site2.org www.site2.org and the root directive to /var/www/site2.org/public_html. Remember to use the correct fastcgi_pass socket path. Enable the new site (sudo ln -s …), test, and restart NGINX using the commands provided above.
    3. DNS: Repeat Step 6, pointing the DNS records for site2.org (and www.site2.org) to your server’s IP address.
    4. WordPress Install: Repeat Step 7, navigating to http://site2.org (once DNS propagates) and using the database credentials created specifically for site2 during the web setup.

    NGINX uses the Host header from the incoming HTTP request (which contains the domain name the user typed) to match against the server_name directives in your enabled configuration files. This is how it routes traffic to the correct website’s document root and configuration block.

    Final Thoughts & Your Next Steps

    You’ve now installed and configured the LEMP stack to host multiple WordPress sites on Ubuntu using NGINX.

    While your sites are technically up and running, getting them truly production-ready requires additional steps:

    1. Handling Direct IP / Unmatched Domain Visits: What should happen if someone tries to access your server via its IP address directly, or uses a domain name you haven’t configured in an NGINX server block? You should configure a default NGINX block to catch these requests, perhaps redirecting them to your primary website’s homepage or showing a specific landing page.
    2. Optimizing Performance:
      • Image Processing: Installing the imagick PHP extension can significantly improve how WordPress handles image manipulation and optimization, leading to faster load times.
      • Caching: Enabling caching can significantly speed up your website. This can involve several layers: NGINX caching for static assets, PHP opcode caching (like OPcache), and WordPress-level caching plugins (e.g., W3 Total Cache, WP Super Cache).
    3. Securing Your Sites with SSL: In today’s web, HTTPS is non-negotiable. You must configure SSL/TLS certificates for all your domains to encrypt traffic, protect user data, improve SEO, and build trust.
    4. Implementing Automated Backups: What happens if something goes wrong? You must configure regular, automated backups of your website files (/var/www/) and databases.
    5. Adopting a Safe Workflow with Staging: Making changes directly on a live site is risky. Setting up a staging environment allows you to safely test updates (WordPress core, themes, plugins) or new features before deploying them to the public-facing site.

    As you can see, moving from a basic setup to fully managed, secure, and optimized hosting involves considerable ongoing effort. Manually configuring default server behavior, tuning performance, managing SSL certificates for multiple domains, scheduling reliable backups, and setting up staging environments are complex and time-consuming and leave significant room for error, especially as you add more sites.

    This is exactly why we built RunCloud.

    You’ve seen how much time and effort it takes to manually set up and manage multiple WordPress sites on a single server.

    RunCloud does the heavy lifting for you.

    • Deploy WordPress sites in minutes, not hours.
    • Automate SSL, backups, and server configs.
    • Monitor performance and security from a single dashboard.
    • Manage PHP, databases, and firewalls without touching the terminal.
    • Create staging environments with one click.

    Start building faster with RunCloud.

  • The Best Docker Alternatives for Containerization in 2025

    The Best Docker Alternatives for Containerization in 2025

    Docker has changed software development and application deployment through containerization. Its intuitive command-line interface, tools such as Docker Desktop, and the vast Docker Hub ecosystem have all made creating, sharing images, and running containerized applications incredibly accessible.

    But many people don’t realise that the Docker engine isn’t the only containerization technology available.

    This post will discuss some of the best alternatives to Docker and compare powerful options that adhere to the Open Container Initiative (OCI) standards.

    Whether you’re concerned about security, optimizing for Kubernetes clusters, managing container images across different container registries, or simply seeking improvements in your container management strategy, by the end of this article, you will be able to find the best containerization platform for your specific needs.

    Let’s get started!

    What is Containerization?

    Containerization is a new way to deploy applications on a remote server. Traditionally, we’ve been copying the application’s source code and executing it on the remote server.

    However, containerization technology allows us to bundle an application’s code and all its necessary dependencies, libraries, configuration files, and binaries, into a single, isolated unit called a container. This container image is a self-sufficient package that can run consistently across different computing environments, from a developer’s laptop to production servers in the cloud or on-premises data centers.

    In Linux, containerization uses operating system-level virtualization features, such as namespaces and control groups (cgroups). Unlike traditional virtual machines (VMs) that require a full guest operating system for each instance, containers share the host system’s OS kernel. This makes containers very lightweight, faster to start, and less resource-intensive than VMs. This allows developers to deploy multiple containers on a single VM for higher density and more efficient use of underlying hardware resources.

    📖 Suggested read: 20 Essential Docker Commands You Should Know

    Best Docker Alternatives for Containerization

    Docker is by far the most popular container runtime available. So much so that many people use the terms ‘Docker’ and ‘containers’ interchangeably – but it isn’t the only containerization technology.

    Let’s take a look at alternative container runtimes that you can use instead of Docker:

    S No.NameVisit Website
    1Podman https://podman.io/
    2Linux Containers https://linuxcontainers.org/
    3Red Hat OpenShift https://www.redhat.com/en/technologies/cloud-computing/openshift
    4Apptainer/Singularityhttps://apptainer.org/
    5Containerd https://containerd.io/
    6Cri-ohttps://cri-o.io/
    7Mirantis Container Runtime https://www.mirantis.com/software/mirantis-container-runtime/

    Podman

    Podman is a helpful tool for anyone working with software containers. It lets you easily find, download, run, build, and share containers using straightforward commands like search, pull, run, build, and push. One special thing about Podman is its ability to group related containers into ‘pods’, which makes it easier to manage applications where different parts need to work closely, similar to how bigger systems like Kubernetes operate.

    If you prefer using a visual interface instead of typing commands, you can use the Podman Desktop application on Windows, macOS, and Linux. This app gives you a single screen to manage your containers, even if they were created with other tools such as Docker.

    Podman Desktop makes building new container images simple, as well as getting images from online repositories, grouping containers into pods, and checking logs. It even helps you prepare and move your container applications to run on Kubernetes.

    📖 Suggested read: How to Create a Docker Image for Your Application

    Linux Containers

    Linux Containers, often abbreviated as LXC, are one of the longest-standing options built directly on the Linux kernel and include features such as namespaces and groups. LXC aims to create environments close to a standard Linux installation but without a separate kernel. This differs slightly from Docker, which typically focuses on packaging a single application and its dependencies.

    LXC is geared more towards running a ‘system container’ – a lightweight virtual machine that can run multiple services or a full init system inside. This ‘system container’ approach might not be a drop-in replacement for your Docker workflow and may require you to configure how you deploy applications.

    LXC uses powerful Linux features and offers management tools and libraries (like liblxc). It mimics a full OS environment, which might be more than most people need for simple application isolation. LXC could be great if you needed to replicate a traditional server setup within a container, but if you are just looking to run your apps, it might introduce unnecessary complexity.

    📖 Suggested read: Docker Security: Best Practices to Secure a Docker Container

    Red Hat OpenShift

    Red Hat OpenShift is much more than just a container runtime. It is a full-fledged application platform built on Kubernetes designed to handle the entire lifecycle of applications, from development and building to deployment and management at scale, even across different cloud environments or on your own servers.

    If you just want to build and run containers, this might not be the right tool for you. Red Hat OpenShift is designed to provide a consistent environment with integrated tools for building, automating deployments (like CI/CD pipelines), and managing applications, not just basic container orchestration.

    The platform offers different ways to use it, either as a managed service on clouds like AWS or Azure, where Red Hat handles the underlying infrastructure, or as a self-managed service for more control. It also has built-in security, developer tools, and the ability to manage virtual machines alongside containers.

    While Red Hat OpenShift is a powerful tool, especially for larger teams or complex applications that need this robust management and security, it is also more complex than just using Docker. Therefore, you must weigh whether the comprehensive features justify the potential learning curve and operational overhead for your needs.

    📖 Suggested read: How to Install WordPress on Docker in 2025 [Step-By-Step Guide]

    Apptainer

    Apptainer, which used to be called Singularity, is another tool for packaging and running software inside containers, similar to how Docker works. It’s open-source software, now part of the Linux Foundation, and designed to be straightforward, quick, and safe. Apptainer is particularly popular in environments where many people share the same computer systems, like university computing clusters or research labs, and for running software that needs a lot of computing power.

    It primarily focuses on performance-intensive applications commonly found in High-Performance Computing (HPC), scientific research, and AI/ML workloads. It is designed for environments where maximizing computational performance, managing complex software stacks, ensuring reproducibility, and handling specialized hardware like GPUs is very important.

    Apptainer is different in handling containers and interacting with the computer it’s running on. It packs everything into a single file, making the container easy to copy, move between computers, or share with others. Apptainer also lets the software inside the container easily use special hardware on the host machine, like powerful graphics cards (GPUs) or fast network connections, which is important for scientific computing.

    Its security approach is also quite simple: by default, you have the same permissions inside the container as you do outside, which helps prevent users from accidentally gaining extra privileges on the system.

    📖 Suggested read: What Are Docker Logs And How To Use Them

    Containerd

    Containerd is a core container runtime focused on managing the complete container lifecycle. This includes tasks like image transfer and storage, container execution and supervision, low-level storage, and network attachments.

    It might surprise you that Docker uses containerd under the hood (or components derived from it), meaning containerd isn’t necessarily a replacement for the entire Docker developer experience, but rather the engine component that does the heavy lifting.

    However, it is much lower-level than the Docker run command, as it exposes the distinct stages of container creation and execution. Rather than providing developers with a simple, all-in-one command-line interface, it’s designed more for integration into larger systems or for users who need fine-grained control.

    It has well-established documentation, API, and client libraries, particularly for the Go client for programmatic control. You can easily use this client to connect to the daemon, pull images, create OCI specs, manage snapshots (container filesystems), and much more.

    While containerd is a crucial piece of the container ecosystem and the standard runtime interface (CRI) implementation for Kubernetes, it doesn’t directly replace the user-facing Docker command-line tool and its associated build/compose functionalities out of the box. Instead, it replaces the runtime part that Docker traditionally managed.

    If you are looking for just the runtime component, containerd is the go-to option. However, replicating the full Docker developer workflow requires other tools (such as nerdctl for a Docker-compatible CLI or build tools like BuildKit).

    📖 Suggested read: Bringing Containerization to RunCloud’s Cloud Architecture

    Cri-o

    If you are working with Kubernetes, you might already be familiar with CRI-O. It is a lightweight Kubernetes Container Runtime Interface (CRI) implementation. This means its primary purpose isn’t to be a general-purpose container engine like Docker, but rather to provide exactly what Kubernetes needs to manage container lifecycles (pods) efficiently and reliably, using standard OCI-compliant runtimes like runc underneath.

    CRI-O acts as the bridge between the Kubernetes kubelet and the low-level container operations. It handles pulling images from any OCI-compliant registry, managing container storage, generating the OCI runtime spec, launching the actual runtime (like runc), setting up networking via CNI, and using conmon for monitoring. Concentrating only on these Kubernetes-essential tasks, it aims to be more stable and resource-efficient within a cluster than a more feature-rich daemon like Docker’s.

    If you are thinking of replacing Docker, you can use CRI-O to replace the runtime component on the Kubernetes nodes. However, you should note that it doesn’t offer a direct replacement for the Docker command-line interface or tools such as Docker Compose for local development workflows.

    Mirantis Container Runtime

    Mirantis Container Runtime (MCR) is similar to ‘Docker Engine – Enterprise’. It is designed to be compatible with the core Docker API and commands you might already know. The main goal of MCR is to provide this familiar Docker Engine functionality, but specifically tailored for enterprise needs, along with commercial support (like 24×7 options) and enhanced security features, which might be necessary if your organization has stricter requirements than those that standard open-source Docker offers.

    MCR heavily emphasizes security aspects often required by large organizations or regulated industries. For example, it uses FIPS 140-2 validated cryptography, has secure default configurations, and offers capabilities like enforcing the use of digitally signed images to secure the software supply chain.

    It has broad capability as it supports both Linux and Windows containers. It can run in standalone mode, as part of a Kubernetes deployment, or in Docker Swarm clusters. This means you can use it in various infrastructure setups without demanding a complete overhaul of orchestration strategies.

    Wrapping Up

    Choosing the right container runtime is a critical decision that depends heavily on your team’s needs, your infrastructure, and the type of applications you’re building. While Docker has been the default choice for years, it’s clear that the container landscape in 2025 offers powerful alternatives such as Podman, LXC, containerd, CRI-O, and OpenShift, each with unique strengths.

    If you manage large Kubernetes clusters, CRI-O or containerd might make sense. If you need a daemon-less solution with strong security principles, Podman is a compelling option. And if you operate in highly regulated enterprise environments, Mirantis Container Runtime brings Docker compatibility with hardened security features.

    However, while choosing the right containerization platform is critical, managing your servers and deployments effectively is equally important – and that’s where RunCloud comes in.

    RunCloud simplifies server management for developers and teams working with containerized or traditional PHP-based applications. Whether you’re using Docker, containerd, or another runtime under the hood, RunCloud helps you:

    • Deploy web applications faster
    • Set up automated backups
    • Manage server security with best practices baked in
    • Monitor performance from a unified dashboard
    • Scale projects effortlessly as your infrastructure grows

    Instead of worrying about the underlying complexities of servers and deployments, you can focus entirely on building and shipping better software.

    If you’re ready to streamline your application deployments and server management, no matter what container runtime you use, sign up for RunCloud today.

    Thousands of developers and businesses already trust RunCloud to manage their mission-critical projects. Discover a simpler, faster, more scalable way to run your applications.

    FAQs on Docker Alternatives for Containerization

    Is Podman better than Docker?

    Podman isn’t inherently ‘better’, but it offers advantages such as a daemonless architecture for enhanced security and rootless container execution. Docker has a more mature ecosystem and wider initial adoption, which makes it a strong choice for many workflows.

    Do I need Kubernetes if I use Docker?

    No, you don’t automatically need Kubernetes just for using Docker, as Docker excels at managing containers on a single host. Kubernetes becomes necessary to orchestrate, scale, and manage containerized applications across multiple hosts or clusters.

    Is LXC faster than Docker?

    LXC can exhibit slightly better performance in certain benchmarks due to operating at a lower level, closer to the kernel, often termed ‘system containers’. However, for typical application container workloads managed by Docker, the performance difference is usually negligible and less critical than Docker’s developer-focused tooling. The choice often depends on whether you must run full OS-like environments (LXC) or isolated applications (Docker).

    What is the best containerization platform?

    There is no single ‘best’ containerization platform; the ideal choice depends on your specific use case, team expertise, and requirements. Docker remains extremely popular for its ease of use and rich ecosystem, while Podman is favored for security-focused or daemonless environments.

    What is the difference between Docker and Kubernetes?

    Docker primarily focuses on building, shipping, and running individual containerized applications, often on a single machine. On the other hand, Kubernetes is a container orchestration platform designed to automate the deployment, scaling, and management of containerized applications across clusters of machines. Simply put, Docker creates the containers, and Kubernetes manages them at scale in production environments.

    Are Docker alternatives suitable for high-traffic applications?

    Docker alternatives like Podman, containerd, and CRI-O are suitable and commonly used for high-traffic, production-grade applications. The ability to handle high traffic effectively relies heavily on the orchestration layer (like Kubernetes) and the application architecture.

    What is the difference between containerization and virtualization?

    Virtualization creates virtual machines (VMs), each running a complete operating system instance with its own kernel on top of a hypervisor. Containerization packages an application and its dependencies, isolating them at the process level while sharing the host OS kernel. Therefore, containers are much lighter, faster to start, and consume fewer resources than VMs.

  • How to Identify and Kill Queries with MySQL Command-Line Tool

    How to Identify and Kill Queries with MySQL Command-Line Tool

    Is your application slow? Are users complaining about lag? This slowdown might be because your MySQL server is struggling under the weight of a long-running or problematic database query.

    When your WordPress site or web application relies heavily on its database (and most do!), a single poorly performing query can have a massive impact.

    Although many third-party tools are available to help with specific problems, in this article, we will use the built-in MySQL command-line tool, which offers a direct, powerful, and quick way to diagnose these issues.

    We’ll guide you through using the command line to:

    1. View currently running processes using SHOW PROCESSLIST.
    2. Identify the specific slow query or problematic process ID.
    3. Safely terminate (KILL) the query when required.

    Let’s get started!

    Prerequisites

    Before you can manage MySQL queries, you’ll need to ensure that you have the necessary access and permissions on your server. You’ll need the following:

    1. Shell access to your server
    2. MySQL user account with specific privileges. For administrative tasks like this, it is common to use the MySQL root user as it has all the necessary privileges.

    How to Kill MySQL Queries via Command Line

    Step 1: Connecting to Your MySQL Server via Command Line

    You can access the MySQL command-line interface via SSH once you’ve connected to your server. The most common way to connect locally is using the MySQL root user. Open your SSH terminal and execute the following command:

    mysql -u root -p   

    Let’s break this down:

    • mysql: Invokes the MySQL command-line client program.
    • -u root: Specifies that you want to log in as the MySQL user named root. Replace root if you are using a different administrative MySQL user.
    • -p: Tells the client to prompt you for the password. It’s more secure than typing the password directly in the command line.

    📖 Suggested read: How to Change/Reset MySQL Root Password on Ubuntu Linux?

    After running this command, you’ll be prompted to enter a password. Paste or type the MySQL root password you retrieved from your RunCloud dashboard. You’ll be greeted with the MySQL monitor prompt (mysql>) if the credentials are correct.

    Step 2: Viewing Running Processes in MySQL

    Now that you’re connected to your MySQL server via the command line, you can run the SHOW PROCESSLIST command to get a snapshot of all the active connections (threads) to your database server and what they are doing at that precise moment. Simply type the following at the mysql> prompt and press ‘Enter’:

    SHOW PROCESSLIST;

    While this command is useful, it truncates the actual SQL query being executed in the ‘Info’ column. For more effective troubleshooting, especially when dealing with complex or long queries, it’s highly recommended to use the extended version:

    SHOW FULL PROCESSLIST;

    The FULL keyword allows you to see the complete SQL statement, which is necessary for diagnosis.

    The output of either command presents a table with several columns, and understanding these columns is key to identifying problematic queries:

    • Id: This is the unique identifier for the connection thread. You will need this number later if you decide to terminate a query or connection using the KILL command.
    • User: Shows the MySQL username associated with the connection thread. This helps you trace the query back to a specific application user or system process.
    • Host: Displays the hostname or IP address (and port) from which the connection originates. This is useful for identifying queries coming from specific application servers, cron jobs, or even unexpected locations.
    • DB: This column indicates the thread’s current default database. If no database is selected, it will be NULL.
    • Command: Describes the type of command the thread is currently executing. For example, the query command means that the thread is actively executing an SQL statement.
    • Time: This is one of the most important columns for performance troubleshooting. It tells us the amount of time (in seconds) that the thread has spent in its current state. For ‘Query’ states, a high ‘Time’ value is a strong indicator of a long-running, potentially problematic query.
    • State: This column provides more granular details about what the thread is doing within its current command. Some states are benign (starting, checking permissions), but others often point towards bottlenecks or issues:
      • System lock: The query is waiting to acquire a lock on a table or row currently held by another thread. This is a common cause of application hangs.
      • Sending data: The thread is processing and sending results back to the client. If this state persists for a long time, it might indicate a query returning a huge result set or network latency.
      • Writing to net: Similar to sending data, indicates network transfer activity.
    • Info: This column displays the actual SQL statement being executed by the thread.

    📖 Suggested read: SQLite vs MySQL vs PostgreSQL (Detailed Comparison)

    If you are using RunCloud, you can use the Slow Script Monitoring functionality from your RunCloud dashboard to identify slow database operations over time. This method is ideal for less technical users as it doesn’t require connecting to your server via SSH or performing any other command-line operations.

    An alternative method offers more flexibility for users comfortable with SQL.

    MySQL provides the PROCESSLIST table within the information_schema database. You can query this table directly using standard SQL SELECT statements to create powerful filters.

    For instance, to find all actively running queries (Query command) that have been executing for more than 60 seconds, and order them by the longest running first, you could use:

    SELECT id, info FROM information_schema.PROCESSLIST
    WHERE COMMAND = 'Query' AND TIME > 60
    ORDER BY TIME DESC;

    This approach can be very helpful on busy servers where the output of SHOW PROCESSLIST is overwhelming. You can pinpoint the threads causing performance degradation or blocking by carefully examining the process list output. Similarly, you can filter visually by ‘User’ or ‘Host’ if you suspect a particular application or job is causing trouble.

    📖 Suggested read: How to Connect a MySQL Database to PHP (A Developer’s Guide)

    Step 3: Analyzing the Query (Optional but Recommended)

    Before killing a slow or seemingly stuck MySQL query, it’s important to investigate the underlying cause first to ensure it doesn’t happen again. You can begin by copying the complete query text from the ‘Info’ column associated with the problematic process.

    Once you have this query text, the next critical step is understanding its execution plan. In a separate MySQL session, execute EXPLAIN <query_text>; to get an overview of your SQL command. Replace the <query_text> with the SQL statement you retrieved.

    This EXPLAIN command provides insights into how MySQL intends to execute the query. This can reveal potential bottlenecks, such as full table scans, which would indicate potentially missing indexes on columns used in WHERE or JOIN clauses, inefficient join types, or an unexpectedly high number of rows being examined.

    Fixing the underlying issue leads to long-term performance gains. For example, let’s assume optimizing a frequent query saves just 20% of its CPU time. That could mean your current server can handle significantly more traffic, or you might even be able to downsize to a smaller, cheaper AWS instance, which would directly save money while providing a faster experience for your users.

    📖 Suggested read: MariaDB vs MySQL – A Detailed Comparison & How You Should Choose

    Step 4: Killing the Query or Connection (KILL)

    Once you’ve identified a suspicious query using the command described above, you can use the kill command to terminate the thread and manually restore server performance.

    ⚠️ Warning: Always double-check that you are using the correct process ID obtained from SHOW PROCESSLIST before executing any KILL command. Terminating the wrong process can lead to unexpected application errors or data inconsistencies.

    KILL QUERY <process_id>;

    This is generally the preferred first attempt. This command tries to terminate only the specific statement that the thread is currently executing, leaving the connection itself open. This is less disruptive to the connecting application.

    For example, if process ID 12345 is running a slow query, you would run:

    KILL QUERY 12345;

    Remember that KILL QUERY might not take effect instantly if the thread is performing an operation that cannot be safely interrupted (like writing to disk). In such cases, it will wait until the thread reaches a point where it can be safely terminated.

    KILL CONNECTION <process_id>;

    If the KILL QUERY command doesn’t work or if you need to terminate the entire connection associated with the thread, you can forcefully terminate the connection. This terminates the statement and drops the client connection.

    KILL CONNECTION 12345;

    In the following example, we can see that the database forcefully terminated the connection from the client. Therefore, you should always use this command with caution as it can lead to unexpected errors.

    Step 5: Verifying the Kill

    After issuing a KILL QUERY or KILL CONNECTION command, you must confirm that it worked.

    The most straightforward way to do this is to run SHOW PROCESSLIST; again immediately. If the kill was successful, the process ID you targeted should no longer be in the list.

    Occasionally, you might see the thread you attempted to kill still listed, but with ‘Killed’ appearing in the Command column. This usually means MySQL has registered the kill request but hasn’t terminated the thread yet. This can happen if the thread is engaged in an operation that cannot be interrupted instantly, such as waiting for disk I/O or performing cleanup tasks.

    The thread will disappear shortly after showing the ‘Killed’ state. However, if you used KILL QUERY and the thread persists, it might indicate the query itself is resistant to termination in its current state. In such scenarios, you can use the more forceful KILL CONNECTION command to terminate the connection and release its resources.

    Important Considerations and Best Practices for Killing MySQL Queries

    While the MySQL command-line tool provides a direct way to manage running queries, using the KILL command should always be done thoughtfully and with an understanding of the potential repercussions.

    • Kill with Caution: Terminating queries, especially KILL CONNECTION, isn’t always clean. Be aware of the potential consequences:
      • Transaction Rollbacks: If you kill a thread executing Data Manipulation Language (DML) statements like INSERT, UPDATE, or DELETE within a transaction (particularly with InnoDB), the entire transaction will typically be rolled back to ensure data consistency. This might be desirable, but it’s important to understand it will happen.
      • Application Errors: Applications are often not designed to handle unexpected database connection drops. Killing a connection might result in application-level errors, incomplete operations, or confusing states for end-users.
      • Resource Cleanup: While modern storage engines such as InnoDB are good at cleaning up, forcefully killing threads can sometimes, albeit rarely, leave behind temporary tables or orphaned locks that might require manual cleanup later.
    • Don’t Kill System Threads: Exercise extreme caution when viewing the process list. You might see threads run by internal system users (e.g., system user, event_scheduler) or replication users (often named repl or similar). Avoid killing these threads unless you have a deep understanding of MySQL internals and are sure it’s necessary and safe, as doing so can disrupt essential background processes, break replication, or even lead to server instability.
    • Focus on Root Cause Analysis: Killing a query is almost always a temporary band-aid, not a permanent solution. The most important step after resolving an immediate performance crisis is to investigate why the query was slow or problematic in the first place. Was it due to missing indexes? Poorly written SQL? Inefficient application logic? A bad schema design? It is always recommended that the application code be analyzed to identify and fix the underlying issue. Otherwise, the problem is likely to recur.
    • Proactive Prevention with max_execution_time: You can consider setting the max_execution_time system variable. This allows you to define a timeout (in milliseconds). The server will automatically abort queries exceeding this time limit, preventing runaway read queries from consuming excessive resources.

    Final Thoughts

    Identifying and killing problematic queries manually using MySQL’s command-line tool is an essential skill for any serious developer or server administrator. Knowing how to spot performance bottlenecks quickly can save your application from crashes, downtime, and user frustration.

    But even with the right techniques, managing servers directly through the terminal takes time, demands technical expertise, and leaves too much room for human error.

    That’s where RunCloud can transform your workflow.

    RunCloud provides a simple, powerful platform that handles the heavy lifting of server management for you. Instead of spending hours troubleshooting MySQL issues through command-line sessions, you can:

    • Monitor server performance and database health visually through an intuitive dashboard
    • Use built-in Slow Script Monitoring to proactively catch issues before they affect users
    • Automate backups, deployments, and SSH alerts – all without touching the command line
    • Easily manage MySQL databases, users, and permissions without memorizing commands

    Thousands of developers and businesses already trust RunCloud to manage their mission-critical servers – and for good reason. It saves time, reduces stress, and gives you peace of mind that your applications are running at their best.

    Ready to experience better server management? Sign up for RunCloud today.

    Stop putting out fires. Start focusing on building, growing, and delivering better results – with RunCloud by your side.

    Frequently Asked Questions About Managing MySQL Queries

    Managing a MySQL server often raises important questions, especially when diagnosing slow queries or optimizing database performance. Below, we answer the most common questions developers and administrators ask about viewing, analyzing, and safely killing MySQL queries.

    How can I list only queries that are running longer than a certain time in MySQL?

    You can filter the information_schema.PROCESSLIST table directly. For example: SELECT id, user, time, info FROM information_schema.PROCESSLIST
    WHERE command = 'Query' AND time > 60;
    This shows queries that have been active for more than 60 seconds, making it easier to detect slow or stuck queries.

    Is it better to kill a query manually or let MySQL’s timeout settings handle it?

    In emergencies, manually killing a slow query is faster. However, using server settings like max_execution_time provides automatic safeguards to prevent long-running queries from becoming a recurring problem without human intervention.

    How often should I monitor running MySQL queries?

    In production environments, continuous automated monitoring is ideal. RunCloud’s Slow Script Monitoring can alert you to persistent slow queries without constant manual checks. Manual investigation should be triggered whenever performance drops or after major deployment changes.

    Can killing queries help fix “Too many connections” MySQL errors?

    Yes, selectively killing idle or stuck queries can immediately free up connections. However, this is a temporary fix. For long-term stability, you should also optimize your database configuration and connection pooling.

    Will killing a query cause data loss or corruption?

    Killing a query mid-execution won’t typically cause corruption if you use transactional storage engines like InnoDB. However, it may cause the current transaction to roll back, potentially undoing changes made during that session. Always investigate and resolve the underlying issue afterward.

    What’s the safest way to kill a problematic query?

    Use KILL QUERY <process_id>; first, as it only attempts to stop the active SQL statement without closing the entire database connection. If that fails or the thread is unresponsive, escalate to KILL CONNECTION <process_id>; to terminate the session.

    How can I prevent long-running queries in the future?

    Analyze your slow queries using EXPLAIN plans and optimize indexing, query structure, or application code. Additionally, set reasonable limits like max_execution_time and actively monitor performance metrics using tools such as RunCloud’s dashboard.


    Ready to simplify server management and focus on what matters most? Sign up for RunCloud and see why thousands of developers and businesses trust it for fast, secure, and reliable server operations.

  • How to Build a CI/CD Pipeline with GitHub Actions and Docker

    How to Build a CI/CD Pipeline with GitHub Actions and Docker

    Are you tired of manually building, testing, and deploying your applications?

    Modern Continuous Integration (CI) and Continuous Deployment (CD) approaches can automatically trigger a deployment pipeline to build your Docker image, run tests, push it to a container registry like GHCR or Docker Hub, and deploy it to your server.

    The best part is that you can complete all of this in less than a minute after pushing code to your GitHub repository.

    By combining Docker with the automation capabilities of GitHub Actions, you can create a fast and effective DevOps pipeline. Docker ensures your application runs the same way everywhere by packaging it with its dependencies in a portable Docker container based on instructions in your Dockerfile. GitHub Actions then automates the build and push steps, securely manages secrets like access tokens, and handles the final deployment to your infrastructure.

    In this guide, we’ll walk you through configuring your GitHub Actions workflow step-by-step, from publishing a container to deploying it on your server without third-party tools or subscriptions.

    By the end of this tutorial, you will be able to configure a deployment pipeline that updates your live server in under a minute after you push changes to it.

    Let’s get started!

    What are GitHub Actions?

    GitHub Actions is a powerful automation tool built directly into the GitHub platform. It listens for specific events happening in your repository, like someone pushing new code, creating a pull request, or even on a set schedule, and then automatically performs tasks you’ve defined. These tasks form a workflow, which is essentially a sequence of steps designed to achieve a specific goal. You can use this functionality to create a Continuous Integration (CI) and Continuous Deployment (CD) pipeline.

    This means you can automate the entire process of building your software, running tests to ensure quality, and even deploying it to servers (perhaps managed through tools such as RunCloud) without manual intervention.

    Key Features of GitHub Actions

    GitHub Actions has several useful features that make it a compelling choice for automation. Firstly, its event-driven nature allows workflows to trigger automatically in response to a wide variety of GitHub events. Secondly, matrix builds let you efficiently test your code across different environments simultaneously; you can define combinations of operating systems (like Linux, macOS, and Windows), software versions (like different Node.js or Python versions), or other variables, and GitHub Actions will run a job for each combination.

    Furthermore, GitHub provides hosted runners, which are virtual machines managed by GitHub that can execute your workflow jobs without requiring you to manage any infrastructure. If you have very specific needs, then you can also consider using self-hosted runners on your own servers or cloud infrastructure.

    All the actions and workflows on GitHub can be reused. You can even configure pre-built steps created by the community (available in the GitHub Marketplace) and save significant development time. Lastly, GitHub Actions includes integrated secrets management for securely handling sensitive information like API keys and passwords. It provides live logs for monitoring workflow progress in real time and the ability to store artifacts like build outputs or test reports.

    📖 Suggested read: What is Docker And How Does it Work

    Steps to Deploy Docker Container with GitHub Actions for CI/CD

    Let’s walk through the steps to automate building your application’s Docker image, pushing it to a registry, and then deploying it to your server every time you push changes to your repository.

    Prerequisites:

    • GitHub Repository: You need a GitHub repository containing all your application code. Make sure you have committed and pushed your latest code changes to GitHub.
    • Dockerfile: You must have a Dockerfile in the root of your repository. This file contains the step-by-step instructions Docker uses to build an image of your application. The specific commands inside the Dockerfile depend heavily on your application’s language, framework, and dependencies (e.g., installing packages, copying code, setting entry points), so we assume you have already created a functional Dockerfile.

    Step 1: Connect to Linux Server via SSH

    First, ensure you can connect to the target Linux server where your Docker container will run. You’ll need SSH access for this.

    ssh your_server_user@your_server_ip

    In the above command, replace your_server_user with your username and your_server_ip with the server’s IP address. If you manage your server with RunCloud, you can use the simplified SSH key management to store SSH keys. We recommend reading the RunCloud documentation to learn how to easily create and manage SSH keys for secure server access.

    📖 Suggested read: What Are Docker Images And How To Use Them

    Step 2: Verify Docker Installation on the Server

    Once connected to your server via SSH, you need to confirm that Docker is installed and running correctly. The Docker Command Line Interface (CLI) is required to pull images and run containers. You can test this by running the standard Docker test image:

    docker run hello-world

    If Docker is installed and working, you will see a message starting with “Hello from Docker!”. This message indicates that your installation appears to be working correctly.

    If the command fails or Docker is not found, you must install Docker Engine on your Linux server before proceeding. Follow the official Docker installation documentation specific to your server’s Linux distribution (e.g., Ubuntu, RHEL).

    📖 Suggested read: How To Create a Docker Image For Your Application

    Step 3: Add GitHub Action Secrets for SSH Access

    To allow your GitHub Actions workflow to securely log in to your server and execute deployment commands, you must store your server’s connection details as encrypted secrets in your GitHub repository. You should never hardcode sensitive information directly into your workflow file – we recommend using GitHub’s built-in secret management system for this.

    Navigate to your GitHub repository > Settings > Secrets and variables > Actions. Click “New repository secret” for each of the following:

    1. SERVER_IP: The public IP address of your Linux server.
    2. SERVER_PORT: The SSH port for your server (usually 22, but might be different if customized).
    3. SERVER_USER: The username you use to log in to your server via SSH. We strongly recommend creating a new user account specifically for this deployment step and giving it appropriate permissions for better security.
    4. SERVER_PRIVATE_SSH_KEY: The entire content of the private SSH key file that corresponds to a public key authorized on your server. Your private SSH key should look something like this:
    -----BEGIN OPENSSH PRIVATE KEY-----
    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
    ...
    UV7ErwUhELMZFrAAAAE3RhdHRpY29kZXJAc3Rhcmx1c3QBAgMEBQYH
    -----END OPENSSH PRIVATE KEY-----

    Using secrets prevents exposing your server credentials in your codebase. The workflow will reference these secrets securely during execution. We strongly recommend creating a dedicated SSH key pair specifically for automation.

    Again, consulting the RunCloud documentation can be very helpful in generating and managing SSH keys securely, especially regarding best practices for SSH security.

    📖 Suggested read: Understanding Docker Services | RunCloud Docs

    Step 4: Configure GitHub Actions Workflow

    Now, define the CI/CD pipeline using a GitHub Actions workflow file. This file tells GitHub what steps to perform when triggered (e.g., on a push to your main branch).

    Create a YAML file named docker-publish.yml inside your repository’s .github/workflows/ directory. You can create this directory and file directly via the GitHub web interface or in your local repository using a text editor, and then commit and push the changes.

    Storing secrets for GitHub Actions

    Paste the following code into .github/workflows/docker-publish.yml:

    name: Publish & Deploy Docker container
    
    # This workflow uses actions that are not certified by GitHub.
    # They are provided by a third-party and are governed by
    # separate terms of service, privacy policy, and support
    # documentation.
    
    
    on:
      push:
        # Adjust branch name if needed (e.g., master, production)
        branches: [ "main" ]
        # Publish semver tags as releases.
        tags: [ 'v*.*.*' ]
    env:
      # Use docker.io for Docker Hub if empty
      REGISTRY: ghcr.io
      # github.repository as <account>/<repo>
      IMAGE_NAME: ${{ github.repository }}
    jobs:
      build:
        runs-on: ubuntu-latest
        permissions:
          contents: read
          packages: write
          # This is used to complete the identity challenge
          # with sigstore/fulcio when running outside of PRs.
          id-token: write
    
    
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4
    
    
          # Install the cosign tool except on PR
          # https://github.com/sigstore/cosign-installer
          - name: Install cosign
            if: github.event_name != 'pull_request'
            uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0
            with:
              cosign-release: 'v2.2.4'
    
    
          # Set up BuildKit Docker container builder to be able to build
          # multi-platform images and export cache
          # https://github.com/docker/setup-buildx-action
          - name: Set up Docker Buildx
            uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
    
    
          # Login against a Docker registry except on PR
          # https://github.com/docker/login-action
          - name: Log into registry ${{ env.REGISTRY }}
            if: github.event_name != 'pull_request'
            uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
            with:
              registry: ${{ env.REGISTRY }}
              username: ${{ github.actor }}
              password: ${{ secrets.GITHUB_TOKEN }}
    
    
          # Extract metadata (tags, labels) for Docker
          # https://github.com/docker/metadata-action
          - name: Extract Docker metadata
            id: meta
            uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
            with:
              images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
    
    
          # Build and push Docker image with Buildx (don't push on PR)
          # https://github.com/docker/build-push-action
          - name: Build and push Docker image
            id: build-and-push
            uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
            with:
              context: .
              push: ${{ github.event_name != 'pull_request' }}
              tags: ${{ steps.meta.outputs.tags }}
              labels: ${{ steps.meta.outputs.labels }}
              cache-from: type=gha
              cache-to: type=gha,mode=max
    
    
          # Sign the resulting Docker image digest except on PRs.
          # This will only write to the public Rekor transparency log when the Docker
          # repository is public to avoid leaking data.  If you would like to publish
          # transparency data even for private images, pass --force to cosign below.
          # https://github.com/sigstore/cosign
          - name: Sign the published Docker image
            if: ${{ github.event_name != 'pull_request' }}
            env:
              # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
              TAGS: ${{ steps.meta.outputs.tags }}
              DIGEST: ${{ steps.build-and-push.outputs.digest }}
            # This step uses the identity token to provision an ephemeral certificate
            # against the sigstore community Fulcio instance.
            run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
    
    
      deploy:
        needs: build
        runs-on: ubuntu-latest
        steps:
          - name: SSH and Deploy to Server
            uses: appleboy/ssh-action@v1
            with:
              host: ${{ secrets.SERVER_IP }}
              username: ${{ secrets.SERVER_USER }}
              key: ${{ secrets.SERVER_PRIVATE_SSH_KEY }}
              port: ${{ secrets.SERVER_PORT }}
              script: |
                echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
                echo "--- Pulling latest Docker image ---"
                docker pull ghcr.io/tatticoder/terraform-get-time:main
                echo "--- Stopping existing container (if running) ---"
                docker stop my_container 
                echo "--- Removing existing container ---"
                docker rm my_container 
                echo "--- Starting new container ---"
               # Adjust ports (-p host:container) 
               # Add any necessary environment variables (-e)
                docker run -d --name my_container -p 3000:80 ghcr.io/tatticoder/terraform-get-time:main

    Let’s understand the important sections of the above code snippet:

    • name: Sets the display name for your workflow in the GitHub Actions tab.
    • on: push: branches: [ main ]: This triggers the workflow every time code is pushed to the main branch. You can change main to your default or production branch name (e.g., master).
    • Build Job: This section handles the process of creating and publishing the Docker container.
      • Checkout code: Uses the standard actions/checkout action to get your repository code onto the runner.
      • Log in to GHCR: Uses docker/login-action to authenticate with GitHub Container Registry using the automatically generated GITHUB_TOKEN.
      • Build and push: Uses docker/build-push-action.
    • Deploy via SSH Job: This job uses the popular SSH Remote Commands action to connect to your server using the secrets you configured and execute commands.
      • host, username, key, port: These fields use the secrets you created in Step 3.
      • script: This block contains the shell commands which will be executed on your target server.

        ❗Very Important – please read the following points very carefully:
        • The first command logs into GHCR on the server. Pulling public GHCR images might not require login. For private images, you can just use the provided command without any modifications.
        • The subsequent command pulls the latest tagged image from GHCR. Make sure to edit this command and replace ghcr.io/tatticoder/terraform-get-time:main with the name of your container image and its corresponding tag.
        • The subsequent command stops and removes any container with the name ‘my_container’ to avoid conflicts. Make sure to temporarily remove these commands to prevent the workflow from failing if the container doesn’t exist yet.
        • The final command runs a new container in detached mode (-d) using the pulled image. Make sure to replace the image’s name with the one you want to use and configure any additional parameters as per your requirements.

    ⚠️ Warning: The deployment script uses docker stop and docker rm before docker run. This means there will be a brief moment of downtime while the container is replaced. For zero-downtime deployments, more advanced strategies like blue-green deployments or using orchestration tools like Kubernetes are needed, which are beyond this basic setup.

    To minimize the impact of downtime, you can consider deploying once a day on weekdays outside of peak hours. This schedule can be configured easily using the GitHub action itself.

    📖 Suggested read: Docker Security: Best Practices to Secure a Docker Container

    Step 5: Commit Workflow and Trigger Deployment

    Finally, save the docker-publish.yml file. If you created it locally, commit it and push it to your GitHub repository using the following commands:

    git add .github/workflows/docker-publish.yml
    git commit -m "Add GitHub Actions workflow for Docker build and deploy"
    git push 
    Deploying and running a GitHub Actions for CI/CD

    Once you push this commit (or any future code changes) to the specified branch (main in this example), GitHub Actions will automatically detect the workflow file and start executing the defined steps.

    You can monitor the progress by going to the “Actions” tab in your GitHub repository. If all steps succeed, your code will be built into a Docker image, pushed to GHCR, and then pulled and run as a container on your designated Linux server.

    Once you have published your Dockerfile to GHCR, you will see a new tab in the bottom right of your GitHub dashboard. You can click on the name of your package to view your recently published packages.

    Step 6: Remove Unused Docker Resources (Optional)

    When you use a CI/CD pipeline, you will quickly end up with a large number of old obsolete containers on your server. These containers are often not needed and can slowly fill your disk space. If you are running low on disk space, then you can add an optional cleanup step to your deployment script to prevent your server’s disk space from filling up with old, unused Docker images, containers, and ‘build cache’.

    The following command will automatically remove any Docker resources (like stopped containers and images not associated with a running container) that haven’t been used in the last 24 hours without requiring confirmation. Running this periodically helps maintain server health and efficiently reclaim storage:

    docker system prune --filter "until=24h" --force

    If your deployment process takes a long time, consider optimizing the build stage of your container by using a caching layer within Docker to cache dependencies.

    Wrapping Up: Who Should Use Docker with GitHub Actions for CI/CD?

    Whether you’re a solo developer or part of a large team, automating builds and deployments saves invaluable time and reduces the potential for human error inherent in manual processes.

    While GitHub Actions handles the automation of building your Docker images and triggering deployment scripts, manually configuring, securing, monitoring, and updating servers can be complex and time-consuming.

    RunCloud provides a clean, efficient way to manage servers without the usual hassle. From provisioning and security hardening to database setup and app deployment, it streamlines the tasks that slow developers down. You stay in control of your infrastructure, but without getting buried in configuration files or command-line firefighting.

    That means more time building, testing, and shipping better software.

    Ready to take the work out of server management? Start with RunCloud today.

    FAQs on Docker with GitHub Actions for CI/CD

    What are the advantages of using Docker for CI/CD?

    Docker ensures consistent environments from development through production. It provides process isolation and ensures that builds and tests don’t interfere with each other or the host system dependencies. 

    How do I secure my Docker images in GitHub Actions?

    Start by scanning your images for vulnerabilities using container scanning tools directly within your GitHub Actions workflow. To reduce the attack surface, use minimal, trusted base images and avoid installing unnecessary packages. Always configure containers to run as non-root users and manage secrets securely using GitHub Secrets, never embedding them in the image layers.

    Can I use Docker Compose with GitHub Actions?

    Yes, Docker Compose can be effectively used within GitHub Actions workflows to manage multi-container setups. You simply need to ensure Docker Compose is installed on the runner, then use standard docker-compose commands to build images or spin up services like databases for integration testing.

    What is the best way to manage secrets in GitHub Actions?

    The most secure and recommended method is using GitHub Actions encrypted secrets, which are configured at the repository or organization level. These secrets can then be safely accessed within your workflow as environment variables or passed to specific actions needing credentials. Never hardcode sensitive information directly in your workflow files or application code checked into version control.

    Is Docker necessary for CI/CD?

    While not strictly mandatory, Docker offers substantial benefits that make it a highly popular choice for modern CI/CD pipelines. While alternative options are available, Docker provides reproducible and isolated build/test environments that are useful for reliable continuous integration and delivery.

    How does Docker improve CI/CD pipelines?

    Docker drastically improves CI/CD pipelines by guaranteeing environment consistency across all stages, from developer laptops to production servers. Its containerization isolates dependencies, preventing conflicts and simplifying the configuration of build agents. 

    Can I use self-hosted runners with Docker in GitHub Actions?

    You can absolutely use self-hosted runners with Docker in GitHub Actions. This approach gives you complete control over the build environment and resources.

    What is the difference between Docker and Kubernetes for CI/CD?

    Docker is primarily used within the CI/CD pipeline to build application images, run tests in isolated containerized environments, and consistently package dependencies. Kubernetes is a container orchestrator typically acting as the deployment target after the CI pipeline, responsible for managing the runtime, scaling, and health of containers in a cluster. Docker creates the portable application packages used in CI, while Kubernetes manages fleets of those packages in production or staging environments (CD).

  • How to Deploy Laravel with Docker on VPS in 2025 (Comprehensive Guide)

    How to Deploy Laravel with Docker on VPS in 2025 (Comprehensive Guide)

    Deploying your Laravel application with Docker on a VPS might seem daunting at first – especially when you’re juggling server configurations, dependency management, and ensuring your app runs seamlessly in production. Even after building a well-optimized web application, replicating your local environment on a server can be a whole new challenge.

    In this comprehensive guide, we’ll show you how to deploy Laravel with Docker on a VPS using Laravel Sail.

    Sail simplifies the process by handling the Docker setup for you, making it a great option whether you’re new to Docker or looking for a streamlined approach.

    You’ll learn how to download Laravel, spin up essential services such as the web server, PHP, and database, and run the necessary setup commands to get your application live.

    Let’s dive in!

    Why Use Docker for Laravel Deployment?

    Deploying a Laravel application from your local development setup to a live production server is not easy. If you have deployed applications in the past, you’ll probably agree that the deployment process introduces numerous complexities, and it’s challenging to manage environment consistency.

    Traditionally, server setup involved manually installing and configuring PHP, web servers such as NGINX or Apache, databases, caching services such as Redis or Memcached, and countless system libraries – all directly onto the server’s operating system.

    This process is not only time-consuming but also prone to errors and inconsistencies. Subtle differences between development, staging, and production environments cause unexpected bugs and failures during application deployment.

    Docker fundamentally solves this by enabling you to package your entire application into standardized, isolated units called Docker containers, including its specific dependencies and configurations.

    Advantages of Dockerizing Laravel Applications

    The primary advantage of containerizing your Laravel applications with Docker is that it allows you to have a consistent development and deployment experience for all developers. By packaging your application code along with the exact versions of PHP, extensions, web server (NGINX/Apache), system libraries, and other dependencies within a Docker image, you eliminate variations between developer machines, testing environments, and production servers.

    This portability means a container built on one machine will run identically on any other machine with Docker installed, drastically reducing bugs related to environment differences.

    In addition, Dockerization brings significant benefits in terms of isolation, scalability, and resource efficiency for Laravel projects. Each Docker container runs in its own isolated userspace, preventing conflicts between different applications or microservices running on the same host. It also enhances security by limiting the potential blast radius of vulnerabilities.

    This isolation makes it easier to scale specific components of your application (e.g., PHP-FPM workers, queue workers) independently based on demand, often orchestrated via Docker Compose or more advanced container management tools such as Kubernetes.

    Compared to traditional virtual machines, containers have significantly lower overhead as they share the host OS kernel. This leads to faster startup times, better resource utilization, and the ability to run more application instances on the same hardware, ultimately improving overall reliability and cost-effectiveness.

    📖 Suggested read: What is Docker And How Does it Work

    Step-by-Step Instructions For Deploying Your First Laravel App with Docker (Sail)

    This section explains how to deploy your Laravel application on a generic cloud VPS using Docker.

    If you are using RunCloud to manage your servers, then you can refer to our Laravel documentation to learn how to do this effectively.

    Prerequisites

    Before we begin installing Laravel, ensure your server environment is correctly prepared.

    1. Server Access: You’ll need access to a Linux server (such as a VPS from providers such as DigitalOcean, Linode, Vultr, etc.) via SSH.
    1. Sudo Privileges: You must be logged in as a user with sudo privileges or as the root user directly (though using a sudo user is generally recommended for security). Remember, commands run with sudo have elevated permissions, so execute them carefully.
    2. Docker Installation and Service: Docker must be installed and running on your server. You can check if it is installed by running docker –version. If it’s not found, you’ll need to install it following the official Docker documentation for your Linux distribution.

    Note: Many cloud providers offer server images with Docker pre-installed. Using one of these can save you the installation step.

    📖 Suggested read: What Are Docker Images And How To Use Them

    Step 1: Download Your Laravel Application

    We will use the official Laravel.build service to download a starter Laravel project configured for Sail. The command below downloads a script and executes it using bash.

    Run this command, making sure you replace runcloud-laravel-app with the desired name for your application’s directory. This name will be used for the project folder.

    curl -s https://laravel.build/runcloud-tutorial | sudo bash

    Important Security Precaution: Piping (|) commands directly from curl to sudo bash executes the downloaded script with root privileges. While laravel.build is an official and trusted source, be cautious when running scripts from the internet this way. Read our blog post on Pipes vs Xargs to learn more on this topic.

    📖 Suggested read: How To Create a Docker Image For Your Application

    In the above command:

    • curl -s: Downloads the script silently (no progress meter).
    • https://laravel.build/runcloud-tutorial: This tells the service to generate a setup script for an app named runcloud-tutorial.
    • | sudo bash: Pipes the downloaded script directly to the bash interpreter, executed with sudo (root) privileges. This creates the project directory and sets initial permissions.

    Step 2: Navigate into Your Application Directory

    Once the previous command completes, navigate into the newly created project directory. Remember to use the actual application name you chose:

    cd runcloud-tutorial

    You should now be inside your Laravel project’s root directory.

    📖 Suggested read: Understanding Docker Services | RunCloud Docs

    Step 3: Start the Docker Containers with Laravel Sail

    Laravel Sail is an interface for managing your application’s Docker containers. We’ll use it to build and start the necessary services (web server, PHP, database, etc.).

    Execute the following command to start Sail in “detached” mode (-d), meaning the containers will run in the background:

    sudo ./vendor/bin/sail up -d

    In the above command:

    • sudo: We use sudo here because Sail needs root permissions to manage Docker networking and volumes.
    • ./vendor/bin/sail: Executes the Sail script located in your project’s vendor directory.
    • up: This command tells Docker (via Sail and Docker Compose) to create and start the containers defined in the docker-compose.yml file. The first time you run this, it will download the necessary Docker images (such as PHP, NGINX, MySQL), which can take several minutes (sometimes ten or more), depending on your internet connection.
    • -d: Runs the containers in the background so your terminal prompt remains available.

    📖 Suggested read: Docker Security: Best Practices to Secure a Docker Container

    Step 5: Run Database Migrations

    Once the containers (including the database container) are running, you’ll need to set up your application’s database schema. Laravel uses “migrations” for this.

    Run the following command to execute the default Laravel migrations:

    sudo ./vendor/bin/sail artisan migrate

    In the above command:

    • sudo ./vendor/bin/sail: Again, we use Sail to execute a command.
    • artisan migrate: This tells Sail to run the PHP artisan migrate command inside the main application container (the one running PHP). This command creates the necessary tables in the database (like the users table, etc.).

    You should see an output indicating that the migrations ran successfully.

    Step 6: Access Your Application

    Your Laravel application should now be running and accessible!

    • On a Server: Open your web browser and navigate to your server’s public IP address: http://your_server_ip. Sail, by default, configures the web server container to listen on port 80.
    • On Your Local Machine (if developing locally): If you performed these steps on your local computer instead of a server, you can usually access it via http://localhost.

    If you cannot access the site via the server’s IP address, your server’s firewall might be blocking incoming connections on port 80 (HTTP). You will need to configure your firewall (e.g., ufw, firewalld, or your cloud provider’s firewall settings) to allow traffic on TCP port 80.

    📖 Suggested read: How to Use Cloudflare Firewall Rules to Protect Your Web Application

    Step 7: Troubleshooting Potential Permission Errors (If Needed)

    Sometimes you might encounter file permission errors within your Laravel application, due to how Docker handles file volumes and user mapping between the host server and the container. This often happens because the web server process inside the container (running as the sail user) doesn’t have write permission to files owned by the root user on the host (created during the initial curl | sudo bash step).

    If you suspect permission issues, you can fix them by changing the ownership of the project files inside the container to the sail user.

    Enter the main application container as root:

    sudo ./vendor/bin/sail root-shell

    This gives you a root command prompt inside your Laravel application’s container.

    Change ownership recursively: This command changes the owner and group of the html directory (as well as everything inside it) to sail:

    chown -R sail:sail /var/www/html

    Let’s understand each part of the above command.

    • chown: Change owner command.
    • -R: Recursive (apply to the directory and all files/directories within it).
    • sail:sail: Set the user to sail and the group to sail.
    • html: The target directory (which corresponds to your project root, mounted at /var/www/html).

    Close the container shell:

    exit

    After running these commands, try accessing your application again, and refresh the web page.

    Wrapping Up: Deploying Laravel with Docker on a VPS

    While Sail simplifies the Docker aspect for a single Laravel project, managing the underlying server, handling security configurations, setting up monitoring, deploying multiple applications, and keeping everything updated still requires significant effort and Linux expertise. This is where platforms specifically designed for server management truly shine.

    RunCloud makes it incredibly easy to develop, deploy, and maintain your web applications across one or many servers, all from a single, intuitive central dashboard.

    It abstracts away the complexities of server administration, letting you focus on building great applications.

    RunCloud works with standard Laravel applications, high-performance setups such as Laravel Octane, and popular CMS platforms such as WordPress. You can start using RunCloud and choose from various optimized server stacks directly through the RunCloud interface.

    Ready to experience truly effortless server management and application deployment?

    Sign up for RunCloud today and see the difference for yourself!

    FAQs on Deploying Laravel with Docker on a VPS

    What are the benefits of using Docker for Laravel deployment?

    Docker packages your Laravel app and its dependencies into containers, ensuring consistent environments from development to production. This isolation prevents conflicts between application dependencies and simplifies portability across different servers or cloud providers.

    How do I secure my Dockerized Laravel application?

    You can secure your Dockerized Laravel app by following standard web security practices within your code, using minimal, trusted base images, and running containers as non-root users. RunCloud provides several security features out of the box and simplifies configuration management.

    Can I use Docker Compose with Laravel?

    Absolutely, Docker Compose is highly recommended, especially for local development and simpler multi-container production setups with Laravel. It allows you to define and manage all the related services your application needs (such as the web server, PHP-FPM, database, and cache) in a single YAML file. This makes it easy to spin up, connect, and manage the entire application stack with simple commands.

    What is the best way to manage environment variables in Docker?

    For security reasons, avoid hardcoding environment variables or committing .env files directly into your Docker image. Instead, pass environment variables into the container at runtime using Docker’s -e flag, Docker Compose environment, or env_file directives.

    Is Docker necessary for deploying Laravel?

    No, Docker isn’t strictly necessary; you can successfully deploy Laravel using a traditional approach by setting up a LAMP or LEMP stack directly on your VPS. However, Docker provides significant advantages in environment consistency, dependency management, and deployment predictability. Tools such as RunCloud make both traditional and Docker-based deployments significantly easier to manage.

    What are the alternatives to Docker for deploying Laravel?

    You can deploy your web applications using the traditional deployment directly onto a configured VPS. RunCloud makes this process extremely easy by providing a centralized dashboard for VPS management.

    Can I use Kubernetes to manage Laravel deployments?

    Yes, Kubernetes (K8s) is a powerful container orchestration system suitable for managing complex, large-scale Laravel applications requiring high availability, auto-scaling, and rolling updates. However, it introduces significant operational complexity compared to simpler Docker or Docker Compose setups. Managing deployments via a tool such as RunCloud provides sufficient capability for many projects without the K8s learning curve.

    What is the difference between Docker and traditional VPS deployment?

    Traditional VPS deployment required you to install and manage all software (OS, web server, PHP, database, dependencies) directly on the virtual server, sharing the host OS kernel and resources in a less isolated way. Docker uses containerization to package the application and its dependencies into isolated user-space environments that run consistently anywhere, sharing the host OS kernel but keeping libraries and binaries separate.

  • Self-Hosting Docker vs Cloud-Based Docker: Pros and Cons

    Self-Hosting Docker vs Cloud-Based Docker: Pros and Cons

    Do you ever feel like getting your software to run reliably everywhere is almost as challenging as writing it in the first place? If so, then we strongly recommend learning all about Docker containerization.

    Docker containerization is a technology that packages applications into neat, portable containers that can be run anywhere.

    But once you’ve created containers, the next big question is – where they should live? Do you take command of your own hardware in a self-hosted setup, or leverage the vast power and convenience of the cloud?

    This guide will also help you choose between self-hosting Docker and using cloud platforms.

    Let’s get started!

    What is Docker?

    You know that classic developer joke, “But it works on my machine!” – funny because it’s often painfully true. Getting software to run correctly on different computers, with all their various settings and installed programs, has often been a massive headache. Docker is a way to fix this.

    Docker is like a standardized shipping container, but for software. You package your application and everything it needs to run (like specific code libraries, tools, and settings) into a neat little box called a “container”. This container can run practically anywhere, on your laptop, a colleague’s computer, or a server in a data center, and it should always work exactly the same way.

    Docker essentially isolates your application, so it doesn’t care what else is running on the host computer. It brings its own environment with it. This makes developing and deploying applications much faster and more reliable.

    But it’s important to remember that Docker isn’t the only container runtime out there! Other great technologies, such as Podman and Containerd, do similar things, offering different features or approaches that some people prefer. So, while you’ll hear “Docker” a lot, think of it as the famous brand name for a type of technology (containers) with several players.

    📖 Suggested read: What is Docker And How Does it Work

    What is Self-Hosting Docker?

    It means you take responsibility for running these containers on the hardware you manage. Instead of paying a cloud company such as AWS or Google Cloud to run your applications, you set up your own server (which could be an old PC in your closet, a powerful machine you bought specifically for this, or even a tiny Raspberry Pi) and use Docker (or one of its alternatives) to run the software containers on it.

    You can think of it as choosing between renting an apartment (using a cloud provider) and owning your own house (self-hosting). When you self-host Docker applications, you set up the server, install the base operating system, install Docker itself, and then deploy and manage the application containers on that system.

    This could be for running anything from a personal blog, a media server like Plex, a file-syncing service, a password manager, or even more complex business applications. You’re the landlord, the maintenance crew, and the resident all rolled into one.

    📖 Suggested read: What Are Docker Images And How To Use Them

    What Are The Benefits of Self-Hosting Docker?

    Why would anyone go through the trouble of setting up their own server to run Docker containers? Well, there are some pretty compelling reasons. The biggest one is often control.

    When you self-host, you have complete control over your data and how the application is configured. Your data stays on your hardware, which can be a huge plus for privacy-conscious folks. You’re not subject to a cloud provider’s terms of service changes, price hikes, or potential service shutdowns.

    Another major benefit can be cost savings, especially in the long run. While there’s an upfront cost for hardware, you avoid potentially hefty monthly subscription fees for cloud services, especially if you need to run many applications or require significant resources.

    It’s also an incredible learning opportunity. Setting up and managing your own server and Docker environment teaches you a ton about Linux, networking, security, and how applications really work under the hood, which are valuable skills in today’s tech world. Plus, you get the satisfaction of building and managing your own little corner of the internet.

    📖 Suggested read: How To Create a Docker Image For Your Application

    What Are The Drawbacks of Self-Hosting Docker?

    As you might have guessed already, self-hosting Docker isn’t easy, and it comes with its own set of chores. The biggest drawback of self-hosting is responsibility. You are solely responsible for everything: buying and maintaining the hardware, installing and updating the operating system and Docker, configuring network settings, ensuring security (this is a big one!), and performing regular backups.

    If something breaks, there’s no support line to call, and it’s up to you to fix it. This requires a certain level of technical knowledge and a willingness to learn and troubleshoot.

    There’s also the upfront cost of hardware, which can range from minimal for a Raspberry Pi to significant for a powerful server. You also need to consider ongoing costs like electricity. Furthermore, your home internet connection might not be ideal for hosting services, especially regarding upload speed or data caps.

    Finally, it takes time, time to set up, time to maintain, and time to fix things when they inevitably go wrong. It’s definitely more involved than just clicking a button on a cloud provider’s website.

    📖 Suggested read: When And Why To Use Docker — Full Guide

    What is Cloud-Based Docker?

    The flip side to running Docker containers on your own servers (self-hosting) is Cloud-Based Docker. This means you’re paying a cloud provider like Amazon Web Services (AWS), Google Cloud Platform (GCP), Microsoft Azure, DigitalOcean, or others, to run your Docker containers for you on their massive, optimized infrastructure.

    Instead of managing physical servers yourself, you interact with web dashboards or command-line tools to tell the provider what containers you want to run, how many resources they need, and how they should connect to the internet or other services.

    Think back to the apartment versus house analogy. Cloud-based Docker is like renting a fully serviced apartment in a large complex. You don’t worry about the building’s foundation, the plumbing, or the electricity grid connection; the building management (the cloud provider) handles all that.

    They offer various services specifically designed for running containers, ranging from simple “run this container for me” options to complex orchestration systems like Kubernetes (often provided as managed services like EKS, GKE, or AKS) that can manage large clusters of containers automatically. This option allows you to focus more on your application inside the container and less on the nuts and bolts that keep it physically running.

    📖 Suggested read: Docker Security — Best Practices to Secure a Docker Container

    What Are The Benefits of Cloud-Based Docker?

    Choosing the cloud route for your Docker containers comes with some significant advantages. One of the biggest perks is scalability.

    Need more power for a sudden traffic spike? With most cloud providers, you can scale up your resources (CPU, RAM, number of container instances) almost instantly with just a few clicks or commands – and scale back when demand drops.

    Most cloud providers only bill for what you use, which can be very efficient. Reliability and uptime are also major selling points; these providers have teams of experts, redundant hardware, backup power, and high-speed network connections designed to keep things running smoothly, often backed by guarantees called Service Level Agreements (SLAs).

    Additionally, cloud providers handle the underlying infrastructure management, and you don’t need to worry about hardware failures, operating system updates, or patching the Docker engine itself. This frees up your time to focus purely on developing and improving your application.

    They also offer a rich ecosystem of integrated services, making it easy to add databases, load balancers, monitoring tools, automatic backups, and advanced security features to your containerized applications. Getting started can often be quicker and require less upfront investment than buying dedicated server hardware.

    📖 Suggested read: 20 Essential Docker Commands You Should Know

    What Are The Drawbacks of Cloud-Based Docker?

    While the convenience is tempting, renting a cloud server has its downsides. The most obvious one is cost. While pay-as-you-go sounds great, cloud bills can quickly spiral out of control if you’re not careful about resource usage, especially at scale, or leave resources running unnecessarily.

    Understanding the often complex pricing models of different providers requires careful attention. You might also experience “vendor lock-in”, where moving your setup from one cloud provider to another becomes difficult due to reliance on specific proprietary services or tools.

    Another key drawback is reduced control. You don’t own the hardware and have limited say over the underlying infrastructure, network configuration specifics, or the provider’s maintenance schedules. Although cloud providers offer a lot of flexibility, some advanced users might also encounter limitations compared to having direct access to the bare metal.

    Data privacy can also be a concern for some; your application data resides on the provider’s servers, subject to their terms, policies, and the legal jurisdiction they operate under. Lastly, while cloud platforms abstract away hardware management, navigating their vast array of services, interfaces, and configurations introduces its own layer of complexity that requires learning.

    Wrapping Up: Who Should Use Self-Hosting Docker vs Cloud-Based Docker?

    Choosing between self-hosting Docker and using a cloud-based provider depends on your needs, technical comfort level, budget, and priorities.

    If you prioritize maximum control over your data, enjoy tinkering with technology, have particular privacy requirements, or are looking for the potentially lowest long-term cost (and don’t mind the upfront hardware investment and maintenance), then self-hosting Docker on your own server is likely a great fit.

    On the other hand, if your priority is convenience, rapid scalability, high availability backed by SLAs, and minimizing the time spent on infrastructure management, then a cloud-based Docker solution (like those from AWS, Google Cloud, Azure, etc.) is probably the way to go. This path suits startups needing to move fast, businesses experiencing variable workloads, teams that prefer focusing solely on application development, and anyone who values the ease of integrated managed services like databases and load balancers. While potentially more expensive month-to-month, it offloads a significant operational burden.

    Ultimately, the “best” choice is the one that aligns with your goals.

    But what if you want the control and potential cost benefits of self-hosting without all the command-line complexity?

    That’s where RunCloud comes in!

    Installing and hosting WordPress in Docker

    RunCloud dramatically simplifies managing your own servers and deploying applications, including Docker containers for managing different PHP runtimes.

    Sign up for RunCloud today and discover how simple server management can be.

    FAQs on Self-Hosting Docker vs Cloud-Based Docker

    Is self-hosting Docker more secure than cloud-based Docker?

    Security depends heavily on implementation, not just the hosting type; self-hosting Docker gives you full control over security measures, but you are entirely responsible for implementing and maintaining them correctly. Cloud providers invest heavily in security infrastructure and personnel, offering robust protection, but you rely on their systems and policies. Ultimately, a poorly secured self-hosted setup is less secure than a well-managed cloud environment, and vice versa.

    What are the cost differences between self-hosting Docker and using a cloud-based solution?

    Self-hosting Docker typically has higher upfront hardware costs but can lead to lower, predictable monthly expenses, mainly electricity and internet. Cloud-based Docker solutions usually have little to no upfront cost but involve recurring monthly fees based on resource consumption, which can escalate quickly as usage grows. Carefully analyze your expected resource needs and growth to determine the most cost-effective option.

    Which is more scalable: self-hosted Docker or cloud-based Docker?

    Cloud-based Docker solutions are inherently designed for easy and rapid scalability. You can adjust resources up or down almost instantly via dashboards or APIs. Scaling a self-hosted Docker environment requires manually adding more hardware (servers, RAM, storage), which takes time, planning, and physical intervention.

    Can I easily switch from self-hosting Docker to a cloud-based solution?

    Migrating Docker containers themselves is relatively straightforward since containers package dependencies, but the ease of switching depends on your overall architecture. If your self-hosted setup relies heavily on local network configurations or specific hardware integrations, moving to a cloud provider will require careful planning and reconfiguring networking, storage, and associated services.

    What is the performance difference between self-hosting and cloud-based Docker?

    Performance can vary greatly depending on the hardware (self-hosted) or chosen instance types (cloud) and network conditions. High-end self-hosted hardware might outperform entry-level cloud instances, while premium cloud instances offer performance levels that are hard to match along with optimized network backbones.

    Is self-hosting Docker suitable for small businesses?

    Self-hosting Docker can be suitable for small businesses, especially those with in-house technical expertise or those using management tools. It offers potential cost savings and greater data control. However, it requires a commitment to managing infrastructure, security, and updates, which can divert focus from core business activities.

    What are the maintenance requirements for self-hosting Docker?

    Self-hosting Docker demands ongoing maintenance, including updating the host operating system, patching the Docker engine itself, monitoring resource usage, managing hardware, and maintaining security configurations. You are also responsible for setting up and verifying backups and planning for hardware failures. Using server management platforms like RunCloud can automate some tasks, but the ultimate responsibility for the infrastructure’s health and security rests with the owner.

    How does data backup work in self-hosting vs cloud-based Docker solutions?

    With self-hosting Docker, you must design and implement your backup strategy, deciding what data (volumes, databases, config files) to back up, how often, and where to securely store the backups. Cloud providers typically offer integrated, often automated, backup solutions for storage volumes and databases associated with your containers.

  • The Best 5 WordPress Vulnerability Scanners in 2025 (Compared)

    The Best 5 WordPress Vulnerability Scanners in 2025 (Compared)

    Protecting your WordPress site from vulnerabilities isn’t optional – it’s essential.

    With WordPress powering over 40% of the web, it’s a prime target for attackers looking to exploit security flaws.

    While themes and plugins offer great functionality, they can sometimes open the door to malware, data breaches, and other security threats.

    That’s why using a reliable WordPress vulnerability scanner is critical. These tools help you detect weaknesses before hackers do, keeping your site secure and your data protected. But with so many options available – from free tools to comprehensive premium solutions – finding the best WordPress vulnerability scanner can feel overwhelming.

    To make your choice easier, we’ve put together a list of the best WordPress vulnerability scanners for 2025. Whether you’re looking for a budget-friendly option or a feature-rich powerhouse, you’ll find something that fits your needs. Plus, we’ll guide you on how to use these scanners effectively to stay one step ahead of potential threats.

    Let’s dive in.

    Top Vulnerability Scanners for WordPress

    Here’s a look at the top WordPress vulnerability scanners for 2025. These tools help you detect security flaws before they turn into serious problems, giving you peace of mind and a secure site.

    Patchstack

    Patchstack is a specialized WordPress security solution focusing on proactive vulnerability detection and mitigation, particularly within plugins and themes. It protects WordPress websites by identifying potential exploits early and blocking attacks before they can cause damage. Patchstack users get a 48-hour early warning and virtual patching, which means your website will be protected from vulnerabilities 48 hours before the public is notified. The best part is that Patchstack will protect your site even if the plugin developer hasn’t released a patch.

    Key Features

    • Virtual Patching: Applies rapid mitigation rules to block exploits without altering plugin code or breaking site functionality.
    • Early Protection: Provides vulnerability patches and protection up to 48 hours before public disclosure.
    • Advanced Vulnerability Intelligence: Leverages extensive vulnerability data, including exclusive intel, for automatic detection.
    • Remote Management: Allows for remote software updates and security hardening configuration across managed sites.
    • API Integration: Enables connecting Patchstack data and functions to existing development or management workflows.
    Patchstack Vulnerability Scanners

    Pricing and Plans

    Patchstack caters primarily to professionals managing multiple sites and larger enterprises. The Developer plan is ideal for agencies, starting at $89 monthly (billed annually) for 50 sites, including core protection, remote management, and API access, with a 30-day trial available. The Enterprise plan offers custom solutions and pricing upon request for businesses needing unlimited scalability, advanced compliance (SLA/DPA), and dedicated support.

    📖 Suggested read: Docker Security: Best Practices to Secure a Docker Container

    MalCare

    MalCare offers complete WordPress security, combining vulnerability scanning with powerful malware detection and removal. It continuously monitors your plugins and themes, alerting you to risks from outdated or compromised components. Its “Safe Updates” feature minimizes the risk of site issues when applying patches, giving you a reliable way to keep your site secure.

    Key Features

    • Vulnerability Scanning: Performs daily automatic checks against a maintained database of known vulnerabilities.
    • Personalized Email Alerts: Notifies users promptly via email when a vulnerable plugin or theme is detected on their site.
    • Safe Auto-Updates: Offers an option to automatically update vulnerable plugins while performing visual regression tests to ensure site stability.

    Pricing and Plans

    The entry-level Plus plan costs $149 per year for one website and includes essential features such as daily malware and vulnerability scanning, instant malware removal, and a real-time firewall.

    Higher tiers like Prime at $199 per year, Pro at $299 per year, and Max at $499 per year for a single site build upon this foundation, offering progressively more frequent scanning and backups, faster expert support response times, performance monitoring, advanced staging options, and API access for the top tiers.

    📖 Suggested read: Difference between DoS vs DDoS vs DrDoS (With Comparison Table)

    Wordfence Security

    Wordfence Security is a widely recognized name in WordPress protection. It offers both a popular security plugin and a distinct, powerful threat intelligence platform known as Wordfence Intelligence. This platform is a core component of their vulnerability management strategy, as it provides a comprehensive and actively maintained database that focuses specifically on WordPress core, theme, and plugin vulnerabilities.

    Key Features

    • Real-Time Webhooks: Provides instant vulnerability notifications through Slack, Discord, or custom HTTP integrations, free of charge.
    • Threat Intelligence Dashboard: Displays real-time attack data, trends, top attacking IPs, and targeted vulnerabilities across their network.
    • Wordfence CLI Integration: Allows the vulnerability database to be used for high-performance, server-level scanning via the command line.
    • User-Friendly Search Interface: Enables robust searching and filtering within the vulnerability database.

    Pricing and Plans

    Wordfence sets itself apart by offering its core vulnerability intelligence platform, Wordfence Intelligence, entirely for free. You get access to an extensive database of vulnerabilities, integration via API, and real-time webhook alerts – at no cost, whether for personal or commercial use.

    Wordfence also offers paid premium versions of its security plugin (Wordfence Premium), which start at $149$ per year and can go as high as $1250 per year.

    📖 Suggested read: The 6 Best WordPress Security Plugins (2022)

    WPScan

    In the past decade, WPScan has established itself as a foundational tool in WordPress security. It focuses on identifying vulnerabilities within WordPress core, plugins, and themes. Its core strength lies in maintaining one of the most extensive and meticulously curated vulnerability databases available, updated constantly by dedicated security professionals. This database powers its various tools and integrations to provide timely and accurate threat information.

    Key Features

    • Extensive Vulnerability Database: Catalogues over 60,000 WordPress core, plugin, and theme vulnerabilities.
    • Manual Vetting: All vulnerability data is manually reviewed and verified by experienced WordPress security experts.
    • Constant Updates: The database is continuously updated as new threats and vulnerabilities are discovered.
    • CLI Security Scanner: Offers a command-line interface tool for security professionals and developers to perform scans.

    Pricing and Plans

    WPScan offers flexible access tiers for different needs. Large organizations can opt for the Enterprise plan, which includes advanced API access and real-time webhook alerts, with custom pricing upon request. Security researchers can use the CLI tool and API for free (capped at 25 calls per day for non-commercial use). Smaller site owners can use the Jetpack Protect plugin, which leverages WPScan’s data for vulnerability alerts, with upgrade options for enhanced security.

    📖 Suggested read: 10 Security Tips to Secure VPS Server in 2025 [Ultimate Guide]

    Sucuri

    Sucuri offers a comprehensive website security platform focused on incident response, malware removal, and ongoing protection. It advertises itself as a full-service security partner that provides cleanup services with preventative measures like a robust Web Application Firewall (WAF) and performance enhancements via its Content Delivery Network (CDN). A key aspect of its offering is the guaranteed malware removal service provided by its 24/7 security team.

    Key Features

    • Guaranteed Malware Removal: Offers unlimited cleanups by security experts within the plan duration, with varying response time SLAs.
    • Performance Optimization: Includes a global CDN with caching options to improve website speed and availability.
    • Security Scanning & Monitoring: Provides regular scanning for malware, blocklist status, and SSL certificate issues (frequency varies by plan).
    • 24/7 Security Team Support: Access to security analysts for cleanup and support.

    Pricing and Plans

    Sucuri provides several annual security plans that vary mainly by how fast they guarantee malware removal and how frequently they scan your site. Their Basic plan for one website costs $229 per year and includes their main security tools with a promise to clean up malware within 30 hours. If you need faster help, the Pro plan at $339 per year reduces that cleanup time to 12 hours, and the Business plan at $549 per year offers the fastest response, aiming for 6 hours, along with more frequent scans.

    📖 Suggested read: PHP Security – Best Practices To Secure Your Web App in 2025

    How to Use a WordPress Vulnerability Scanner

    Using a WordPress vulnerability scanner is essential, but it can be daunting if you’re new to it. Here’s a simple guide to setting up and using a vulnerability scanner effectively on your site.

    Step 1: Choose and Install Your Scanner

    • Plugin-Based Scanners: Many popular options like Patchstack are available as WordPress plugins. Install them directly from your WordPress dashboard (Plugins > Add New), search for the scanner, click Install Now, and then Activate.
    • External Scanners: Some services (like Sucuri SiteCheck or WPScan’s web interface) scan your site remotely. You just need to enter your website’s URL on their website. No installation is needed, but they might offer less depth than installed plugins.
    • CLI Tools: For more technical users, tools like the WPScan CLI (Command Line Interface) tool can be run from a server terminal. This requires SSH access and familiarity with command-line operations but offers powerful scanning capabilities.

    For this tutorial, we’ll demonstrate how to scan for vulnerabilities on your WordPress site using Patchstack.

    📖 Suggested read: How To Create Custom NGINX Configuration Easily Using RunCloud

    Step 2: Configure Basic Settings (If Applicable)

    • After activating a plugin scanner, navigate to its settings page within your WordPress dashboard.
    • You might need to enter an API key (especially for premium features or tools like WPScan that connect to a central database). Follow the scanner’s instructions to obtain and save the key.
    • Configure notification settings (where alerts should be sent) and automatic scan schedules (daily or weekly is recommended).

    📖 Suggested read: 10 Best WordPress Management Tools To Easily Manage Multiple Websites

    Step 3: Run an Initial Scan

    • Most website scanners automatically scan your website, but if you see a “Scan Now,” “Start Scan,” or similar button within the scanner’s interface in your WordPress dashboard or on the external scanner’s website, press it and wait for the scan to finish.
    • The vulnerability scanning tool will check your WordPress core, installed plugin, and theme versions against its database of known vulnerabilities (identified by CVE numbers or internal IDs). It may also check for basic security misconfigurations.

    📖 Suggested read: How to Use Cloudflare Firewall Rules to Protect Your Web Application

    Step 4: Analyze the Scan Results

    • Once the scan is completed, review the report carefully. It will list any detected issues, typically categorized by severity (e.g., Low, Medium, High, Critical).
    • Look for items flagged as vulnerable, noting the component name, the affected version range, and, ideally, the version number containing the fix.
    • Pay attention to any configuration warnings, such as publicly accessible, sensitive files (wp-config.php backup), or directory listing being enabled.

    Step 5: Remediate Found Vulnerabilities

    • Backup First: Start by backing up your site. Make a complete copy of your website files and database before making any changes to ensure you can restore it if needed.
    • Update: The most common fix is to update the vulnerable component. Go to Dashboard > Updates or the Plugins/Themes pages in WordPress and update any plugins, themes, or the WordPress core identified in the scan report.
    • Patch or Use Virtual Patching: If an update isn’t available for a vulnerable plugin/theme, check if your scanner or WAF (Web Application Firewall) offers “virtual patching”. This blocks exploitation attempts without changing the code.
    • Remove or Replace: If no update or virtual patch is available, and the component isn’t essential, consider deactivating and deleting the vulnerable plugin or theme and finding a secure alternative.
    • Fix Configurations: Address any configuration issues reported, such as adjusting file permissions via FTP/SFTP or adding security rules to your .htaccess file (do this carefully).

    Step 6: Re-Scan and Maintain

    • After applying fixes, rerun the vulnerability scan to confirm that the reported issues are resolved.
    • Ensure automated scans are scheduled to run regularly (at least weekly) to catch newly discovered vulnerabilities promptly. Security is an ongoing process, not a one-time task.

    Wrapping Up: Why Every WordPress Site Needs a Vulnerability Scanner

    A WordPress vulnerability scanner is essential for keeping your site secure. Ignoring vulnerabilities leaves your site exposed to attacks. These scanners proactively search for security flaws, like outdated plugins or weak themes, before hackers exploit them. It’s your first line of defense in maintaining a safe online presence.

    But just using a vulnerability scanner isn’t enough. Solid hosting and server management are foundational layers of security. Platforms like RunCloud significantly bolster your defenses right out of the box.

    RunCloud provides optimized server stacks (like NGINX or OpenLiteSpeed), easy SSL certificate deployment, and user isolation, and includes server-level firewall protection (via tools like ModSecurity and Fail2Ban) and security hardening options by default on server configurations. This setup blocks many common brute-force attacks and malicious requests before they even reach WordPress.

    However, it’s important to understand that RunCloud’s server-level protection and hardening are not substitutes for an application-level vulnerability scanner. RunCloud’s defenses block many common attacks based on known malicious patterns or excessive attempts. Still, they won’t necessarily know if a specific plugin version you’re running has a newly discovered flaw exploitable via a legitimate-looking request. A dedicated WordPress vulnerability scanner inspects your specific WordPress components against vast, constantly updated databases of known issues – a task server firewalls aren’t designed for.

    RunCloud provides a high-performance, secure environment optimized for WordPress, simplifying server management and security configurations. You get speed benefits from fine-tuned stacks, caching, and that critical layer of server defense. Imagine easily configuring your server-level firewall or applying security hardening with just a few clicks.

    Easily manage server-level WAF rules within RunCloud.

    Pairing a dedicated WordPress vulnerability scanner with the secure, optimized hosting environment managed by RunCloud creates a powerful, multi-layered security strategy. You get the best of both worlds: a hardened server deflecting broad attacks and a specialized scanner pinpointing application-specific weaknesses.

    Ready to experience how simple, secure, high-speed WordPress hosting can be?

    Try RunCloud Today and See the Difference

    FAQs on WordPress Vulnerability Scanners

    What is the best free vulnerability scanner for WordPress?

    Several reputable free options exist, including the WPScan CLI tool and free versions of security plugins like Wordfence or Sucuri SiteCheck. The most suitable choice depends on your specific requirements and technical expertise.

    How often should I scan my WordPress site?

    Regular scanning is important for protecting against attacks; you should aim for at least weekly scans for most WordPress websites to catch issues early. High-traffic or e-commerce sites benefit from daily scans to minimize risk exposure between checks.

    Can vulnerability scanners prevent attacks?

    Vulnerability scanners primarily detect weaknesses rather than directly prevent attacks; they act like an early warning system. Preventing attacks requires you to act on the scan results by patching vulnerabilities, using firewalls, and maintaining secure configurations on reliable hosting, like that managed with RunCloud.

    What should I do if a vulnerability is found?

    If a vulnerability is found, assess its severity and understand the recommended fix, typically updating the affected theme, plugin, or core WordPress files. Apply the patch and then re-scan to confirm the issue is resolved, ensuring you have reliable backups before making changes.

    Are premium scanners worth the investment?

    Premium scanners often justify their cost for business or high-traffic sites by offering more frequent updates, deeper scanning capabilities, and dedicated support. These advanced features can detect vulnerabilities faster and more accurately than many free options, making them valuable in your security strategy.

    How do vulnerability scanners differ from malware scanners?

    Vulnerability scanners proactively search for potential weaknesses that attackers might exploit, such as outdated plugins or configuration flaws. Malware scanners reactively look for existing malicious code or infections that have already compromised your site, addressing different stages of security risk.

    Can I use multiple scanners on the same site?

    You can use multiple scanners, potentially increasing detection coverage as tools vary in their databases and methods. However, running several simultaneously, especially active plugins, can impact site performance, so consider a balanced approach like one main tool plus occasional checks with another.

    What is the average cost of a premium vulnerability scanner?

    The cost for premium WordPress vulnerability scanners varies widely, from approximately $50 to over $300 per site annually. Pricing depends heavily on the depth of features offered, the number of sites included, and the level of support provided by the security service.

  • How to Restrict Access to WordPress Files Using the .htaccess File

    How to Restrict Access to WordPress Files Using the .htaccess File

    Is your WordPress website silently vulnerable to attackers? While you focus on creating content and growing your audience, critical files and directories might be exposing your site to serious security threats.

    The humble .htaccess file is your first line of defense – a powerful but often overlooked security tool sitting right in your WordPress installation.

    This guide will walk you through using .htaccess to lock down sensitive components including your wp-config.php file, wp-admin directory, and even control access to your media files and other assets.

    Whether you’re a WordPress developer seeking advanced security implementations or a site owner looking for straightforward protection, you’ll find actionable techniques to fortify your website against unauthorized access and common attack vectors.

    By the end of this guide, you’ll have implemented robust security measures that work silently in the background, protecting your site without affecting legitimate users.

    Ready to secure your WordPress site properly? Let’s dive in.

    What is .htaccess?

    .htaccess (which stands for “hypertext access”) is a configuration file that sits within specific directories on your web server (running Apache). It allows you to configure settings for that directory and any subdirectories underneath it. Instead of modifying the main Apache server configuration (which usually requires higher-level access), you can use .htaccess files to make changes on a per-directory basis.

    These changes can include things like setting up redirects, password-protecting areas, controlling caching, and, importantly for us, restricting access to files and folders.

    Unlike main configuration changes, the beauty of .htaccess is that its changes take effect immediately without requiring a server restart. It is read on every request that hits the server for the directory in which it is located, so its directives are applied instantly.

    📖 Suggested read: Protect Your WordPress Login pages with Cloudflare Zero Trust

    Why Restrict Access to WordPress Files?

    WordPress, like any complex web application, has a specific directory structure. Some files are meant to be publicly accessible (like your theme’s CSS and JavaScript files and images), while others are crucial to the functioning of WordPress and should never be directly accessed by the public. These sensitive files include:

    • wp-config.php: This is the crown jewel. It contains your database credentials (username, password, database name), secret keys used for security, and other vital configuration settings. If a malicious actor gets hold of this, they could compromise your entire site.
    • wp-includes/: This directory contains core WordPress files and libraries. Direct access to these files could expose vulnerabilities or allow attackers to inject malicious code.
    • .htaccess itself: You certainly don’t want someone modifying your security rules!
    • Other sensitive, non-web readable files, Such as backups, logs, or readme.html

    Allowing direct access to these files is like leaving your front door unlocked and putting a sign on it saying, “Valuables inside!”

    We restrict access to protect your WordPress site’s core functionality and sensitive data from being exploited.

    Importance of Securing WordPress Files

    Securing these files is paramount for several reasons:

    1. Preventing Database Compromise: As mentioned, wp-config.php holds your database credentials. Leaking these means attackers could gain full control of your database, allowing them to steal data, inject malicious content, or even delete everything.

    2. Blocking Code Injection: Direct access to core files (wp-includes/) could allow attackers to inject malicious PHP code. Your server could then execute this code, potentially creating backdoors, stealing user data, or defacing your website.

    3. Preventing Information Disclosure: Even if a file doesn’t contain directly exploitable code, it might reveal information about your WordPress installation, such as the version number or the plugins you use. This information can help attackers identify known vulnerabilities.

    4. Maintaining Website Integrity: By restricting access, you ensure that only WordPress itself, through its intended mechanisms, can interact with these critical files. This helps prevent accidental or malicious modifications that could break your website.

    📖 Suggested read: The 6 Best WordPress Security Plugins (2022)

    How to Restrict Access to WordPress Files Using .htaccess: Step-by-Step Guide

    This guide will walk you through securing your WordPress files by modifying your .htaccess file. We’ll use RunCloud’s file manager for ease of access, but the principles apply regardless of how you edit the file (FTP, cPanel, etc.).

    Step 1: Accessing Your .htaccess File (Using RunCloud File Manager)

    1. Select Your Server: Access your RunCloud dashboard and choose the server where your WordPress website is hosted.
    2. Select Your Web Application: Locate the web application corresponding to your WordPress site and click on it.
    3. Open File Manager: In the web application’s details, you’ll find a “File Manager” tab or button. Click on it to open the File Manager.
    1. Locate .htaccess: When you open RunCloud’s File Manager, you’ll land in your application’s root directory (typically located at webapps/<your-app-name>/). The .htaccess file should be visible among your WordPress core files. Don’t worry if you can’t see it immediately – some WordPress installations don’t have one by default, or it might be hidden.

    If you need to create a new .htaccess file, simply right-click in the File Manager and select “Create New File.” Remember that the filename must begin with a period followed by “htaccess” with no file extension (.htaccess). This naming convention identifies it as a special configuration file that Apache will recognize and process when handling requests to your site.

    editing .htaccess

    Note: Files starting with a dot are often hidden by default in many file systems. If you are not using the RunCloud file manager, you might need to enable “Show Hidden Files” in your file manager’s settings.

    Step 2: Adding Rules to Restrict Access

    Always create a backup of your .htaccess file before making any modifications. This critical step cannot be overstated – even a minor syntax error can render your entire website inaccessible. The server reads this file for every page request, so any mistake will immediately affect your site.

    To create a backup in RunCloud:

    1. Right-click on the .htaccess file
    2. Select “Download” to save a local copy, or
    3. Choose “Duplicate” to create a .htaccess.bak file directly on the server

    Once you’ve secured a backup, you can safely edit the file by double-clicking it in RunCloud’s File Manager, which will open the built-in text editor.

    Below are several common security scenarios and the corresponding .htaccess rules you can implement. Each addresses specific vulnerabilities in a standard WordPress installation:

    Use Case 1: Restrict Access to wp-config.php

    As explained above, you should protect your wp-config.php file from unauthorized access. This directive denies access to the wp-config.php file from all sources.

    <Files wp-config.php>
        Order allow, deny
        Deny from all
    </Files>

    📖 Suggested read: 10 Security Tips to Secure VPS Server in 2025 [Ultimate Guide]

    Use Case 2: Limit Access to the wp-admin Area by IP Address

    This is useful if you want to restrict access to your WordPress admin area to only specific IP addresses (e.g., your office or home network). Replace YOUR_IP_ADDRESS with your actual IP address. You can add multiple Allow from lines for additional IPs.

    <IfModule mod_authz_core.c>
    <Location /wp-admin>
            Require ip YOUR_IP_ADDRESS
            # Require ip ANOTHER_IP_ADDRESS  (Add more lines as needed)
    </Location>
    </IfModule>
    <IfModule !mod_authz_core.c>
    <Location /wp-admin>
           Order deny, allow
           Deny from all
           Allow from YOUR_IP_ADDRESS
           # Allow from ANOTHER_IP_ADDRESS  (Add more lines as needed)
    </Location>
    </IfModule>

    In the above code snippet, the Location /wp-admin directive applies the rules specifically to the /wp-admin directory.

    Note: The syntax of these commands might vary slightly depending on the Apache version you are using. Refer to the official documentation for the latest syntax.

    📖 Suggested read: How to Restrict WordPress Admin Access by IP Address? (EASY GUIDE)

    Use Case 3: Protect Media Files from Direct Access (but allow them to be displayed on your site)

    This prevents direct access to files in your wp-content/uploads directory (where images and other media are stored) unless the request is coming from your own website. This helps prevent “hotlinking” (other sites using your images directly, consuming your bandwidth). Replace runcloud.example.com with your actual domain.

    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?RunCloud.example.com [NC]
    RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]

    Let’s break down the above commands and try to understand them one by one:

    • RewriteEngine on: Enables the rewrite engine, which is used for URL manipulation.

    • RewriteCond %{HTTP_REFERER} !^$: This condition checks if the HTTP_REFERER header is not empty. The HTTP_REFERER header indicates the page that is linked to the requested resource.

    • RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?runcloud.example.com [NC]: This condition checks if the HTTP_REFERER does not start with your domain name (with or without www and with either http or https). [NC] means case-insensitive.

    • RewriteRule \.(jpg|jpeg|png|gif)$ - [NC, F, L]: This rule gets applied if both of the above conditions are true. It matches any file ending in .jpg, .jpeg, .png, or .gif. The – means no substitution is performed. [NC, F, L] flags: NC means case-insensitive, F means Forbidden (return a 403 error), and L means this is the last rule to be processed.

    Use Case 4: Block XML-RPC to Prevent DDoS Attacks

    XML-RPC is a WordPress feature that allows remote access to your site. It can be a target for DDoS attacks. If you don’t need it, it’s best to block it. The security experts at Patchstack have written a great article that explains why blocking XML-RPC is a great idea.

    <Files xmlrpc.php>
        Order allow, deny
        Deny from all
    </Files>

    📖 Suggested read: How to Block IP Address Using WordPress .htaccess File to Stop Bad Visitors

    Use Case 5: Restrict Access to Sensitive File Types for Enhanced Security

    Many crawlers and automated robots try to access files directly from the server, even if they aren’t indexed. In our previous post, we explained that robots.txt is merely a suggestion and not enforceable. Therefore, you should always block direct access to various potentially sensitive file types.

    Use the following command to block sensitive files that will never be accessed over the web:

    <FilesMatch "\.(sql|md|log|txt|backup|bak|conf|dist|fla|psd|ini|sh|inc|swp|aspx)$">
        Order allow, deny
        Deny from all
    </FilesMatch>

    In the above directive:

    • <FilesMatch ...>: uses a regular expression to match multiple file extensions.

    • \.(sql|md|log|txt|backup|bak|conf|dist|fla|psd|ini|sh|inc|swp|aspx)$ It will deny access to the listed file extension. You should carefully review this list of extensions and modify it depending on your use case.

    📖 Suggested read: Redirect to HTTPS Using htaccess Behind NGINX Proxy

    Use Case 6: Control Access to Configuration Files by Specific IPs

    Similar to limiting access to wp-admin, you can restrict access to other configuration files (or any file/directory) to specific IP addresses. This example shows how to protect a hypothetical config.ini file:

    <Files config.ini>
    <IfModule mod_authz_core.c>
               Require ip YOUR_IP_ADDRESS
               # Require ip ANOTHER_IP_ADDRESS
    </IfModule>
    <IfModule !mod_authz_core.c>
            Order deny, allow
            Deny from all
            Allow from YOUR_IP_ADDRESS
            # Allow from ANOTHER_IP_ADDRESS
    </IfModule>
    </Files>

    📖 Suggested read: How to Fix a 403 Forbidden Error on Your Site

    Use Case 7: Disable Directory Browsing

    Your WordPress site’s file structure is a treasure map for attackers. When directory listing is enabled, anyone who navigates to a folder without an index file can see a complete inventory of its contents. This exposes your site’s architecture, plugin versions, themes, and potential vulnerabilities – all valuable intelligence for malicious actors.

    Automated scanning bots constantly probe websites for these open directories, looking for paths to exploit. Once they discover unprotected directories, attackers can identify outdated components, locate configuration files, or find other security weaknesses to target.

    By disabling directory browsing, you force these requests to return a “403 Forbidden” error instead of displaying your folder contents. This simple change significantly strengthens your security posture by keeping your site’s internal structure hidden from prying eyes.

    Options -Indexes

    📖 Suggested read: How to Fix the HTTP Error 503 Service Unavailable in 2025 [SOLVED]

    Use Case 8: Restrict Access to the .htaccess File to Protect Configuration Settings

    Your .htaccess file is not just a security tool – it’s also a potential security liability. If attackers can access this file, they gain valuable intelligence about your specific protection measures, allowing them to craft precisely targeted attacks that circumvent your defenses.

    Think of your .htaccess as the blueprint for your security system. When exposed, it reveals exactly which files you’re protecting, which directories you’ve restricted, and what specific countermeasures you’ve implemented. Armed with this information, attackers can methodically test for weaknesses or exceptions in your ruleset.

    To prevent this risk, you should explicitly block access to the .htaccess file itself. This creates a security loop where the very rules that protect your site also protect themselves from being discovered. By implementing this protection, you ensure that your defense strategies remain confidential, significantly reducing the attack surface available to potential intruders.

    <Files ~ "^\.ht">
        Order allow, deny
        Deny from all
        Satisfy All
    </Files>

    Step 4: Testing Your Configuration

    After saving your changes to .htaccess, it’s essential to test them thoroughly:

    1. Clear Your Browser Cache: Your browser might cache old versions of files or responses. Clear your cache to ensure you’re seeing the effects of your changes.

    2. Try Accessing Restricted Files: Attempt to directly access files you’ve restricted (e.g., runcloud.example.com/wp-config.php) in your browser. You should receive a 403 Forbidden error.

    3. Verify Website Functionality: Browse your website thoroughly to make sure everything is still working as expected. Pay close attention to areas that might be affected by your changes (e.g., the admin area and image display).

    4. Check for Errors: If anything is broken, check your browser’s developer console (usually accessed by pressing F12) for error messages. These messages can provide clues about what might be wrong.

    5. Revert if Necessary: If you encounter problems, immediately restore your .htaccess file from the backup you made in Step 2.

    Final Thoughts: Securing Your WordPress Site with RunCloud and .htaccess

    Throughout this guide, we’ve explained the role of the .htaccess file in securing your WordPress installation, focusing on restricting access to sensitive files and directories. While the concepts might seem technical at first, implementing these security measures is significantly easier with a hosting provider like RunCloud.

    RunCloud’s platform is built with performance and security in mind. It’s designed to make server management accessible to anyone, even non-server administrators.

    Let’s recap how RunCloud streamlines the process and enhances security:

    • Easy File Management: RunCloud’s built-in File Manager provides a user-friendly interface for accessing, editing, and managing your .htaccess file directly without needing to use SSH or FTP. This significantly simplifies the process of implementing the security measures we’ve discussed. You can easily create backups, edit the file, and revert changes if needed, all within your RunCloud dashboard.

    • NGINX and Apache Hybrid Options: RunCloud allows you to choose between NGINX or an Apache hybrid configuration. NGINX is known for its speed and efficiency, especially in handling static content. While NGINX doesn’t natively use .htaccess files, RunCloud cleverly handles configurations through its interface, translating many .htaccess-like directives into NGINX-compatible rules.

    • Built-in Security Features: Beyond .htaccess management, RunCloud offers a comprehensive suite of security features:

      • Web Application Firewall (WAF): RunCloud’s WAF helps protect your site from common web attacks, such as cross-site scripting (XSS) and SQL injection. The WAF also handles many of the protections we achieve with .htaccess (like blocking malicious requests) at a higher level.

      • Server-Level Security: RunCloud automatically configures your server with security best practices, including firewall rules, intrusion detection, and regular security updates.

      • SSL/TLS Certificates: RunCloud makes installing and managing free Let’s Encrypt SSL/TLS certificates incredibly easy, ensuring secure communication between your website and its visitors.

    • Git Deployment: By deploying with Git, you eliminate the need for FTP, a very insecure protocol.

    While understanding the power of .htaccess (and its equivalent configurations in NGINX) is valuable, RunCloud simplifies many of these tasks, allowing you to focus on building your website rather than getting bogged down in complex server configurations.

    Start using RunCloud today →

    FAQs on Restricting Access to WordPress Files Using .htaccess

    What is the difference between .htaccess and wp-config.php?

    The .htaccess file is an Apache web server configuration file that controls access and behavior for its directory and subdirectories. It allows for per-directory settings without modifying the main server configuration.
    wp-config.php, on the other hand, is a core WordPress file containing your database credentials, security keys, and other crucial WordPress-specific settings. RunCloud simplifies managing both, allowing easy access and editing via its file manager.

    Can I restrict access to specific users?

    .htaccess primarily restricts access based on IP addresses, not individual WordPress user accounts. You can allow specific IP addresses to access certain areas (like wp-admin), effectively limiting access to users coming from those locations. You’ll need to use WordPress’s built-in roles and capabilities system or a dedicated security plugin for user-level restrictions within WordPress.

    What happens if I break my .htaccess file?

    A broken .htaccess file, usually due to syntax errors, can cause a 500 Internal Server Error, making your entire website (or parts of it) inaccessible. Always back up your .htaccess file before making changes. RunCloud’s file manager makes it easy to create backups and revert to previous versions if something goes wrong.

    How can I restore my .htaccess file?

    Before making any changes, always download a copy of your .htaccess file or create a copy within your file manager (e.g., .htaccess.bak). If you encounter issues, simply replace the broken .htaccess file with your backup copy using RunCloud’s file manager, FTP, or any other file access method. This will quickly restore your site’s functionality.

    Are there plugins that can help with .htaccess?

    Several WordPress security plugins (like Wordfence, Sucuri Security, and iThemes Security) offer features to manage and modify your .htaccess file, often with a user-friendly interface. However, it’s crucial to understand the changes these plugins make, as incorrect configurations can still cause problems. With RunCloud, you can use plugins or manually edit your .htaccess.

    Is it necessary to restrict access to WordPress files?

    Restricting access to sensitive WordPress files like wp-config.php and core directories is a highly recommended security practice. It prevents unauthorized access, protects your database credentials, and reduces the risk of code injection and other attacks. RunCloud, combined with proper .htaccess rules, provides a strong foundation for WordPress security.

    Can I restrict access to media files in WordPress?

    Yes, you can use .htaccess to control access to media files (images, videos, etc.) in your wp-content/uploads directory. This is commonly used to prevent hotlinking (other websites directly linking to your images and using your bandwidth). RunCloud’s easy file management allows you to implement these restrictions.

    How do I know if my .htaccess rules are working?

    After saving your .htaccess changes, clear your browser cache and try to access the files or directories you’ve restricted directly. You should receive a 403 Forbidden error if the rules are working correctly. Also, thoroughly browse your website to ensure all intended functionality remains unaffected.

  • How to Use FTP to Upload Files to WordPress Without Password [Step By Step]

    How to Use FTP to Upload Files to WordPress Without Password [Step By Step]

    Have you ever needed to upload a massive plugin that WordPress couldn’t handle? Or dive deep into your website’s files to fix a mysterious error?

    While WordPress is user-friendly, sometimes you need more direct control.

    That’s where FTP (File Transfer Protocol), or more accurately, its secure sibling SFTP (Secure File Transfer Protocol), comes in.

    This article is your comprehensive guide to understanding and using FTP with WordPress. We’ll cover everything from the basics of FTP to uploading files, troubleshooting how to connect securely, navigate your WordPress directory structure, uploading files, troubleshooting common FTP issues, and even how server management platforms such as RunCloud integrate with FTP.

    Whether you’re a beginner blogger or a seasoned developer, mastering FTP can unlock a new level of control over your WordPress website. Stop relying solely on the WordPress dashboard – let’s learn how to take the reins!

    What is FTP?

    FTP is a standard network protocol used to transfer files between two computers on a computer network. It’s a set of rules that computers follow to copy files from one machine to another. While it’s been a fundamental part of the Internet for decades, standard FTP is inherently insecure.

    How Does FTP Work?

    FTP operates on a client-server model. The client (e.g., an FTP software like FileZilla) initiates a connection to the server (e.g., your web hosting server). FTP uses two separate channels for communication:

    1. Control Channel (Port 21 – for plain FTP): This channel is used for sending commands and responses between the client and server. These commands include “login”, “list files”, “change directory”, “upload file”, “download file”, etc. The control channel establishes the connection and manages the session.
    2. Data Channel (Various Ports): This channel is used for the actual transfer of file data.
    3. With SFTP (SSH File Transfer Protocol), the process is different. SFTP is a subsystem of SSH (Secure Shell). It uses a single secure channel (usually port 22) for both commands and data transfer. All communication is encrypted, making it vastly more secure than standard FTP.

    📖 Suggested read: FTP vs. SFTP – What’s The Difference & Why It Matters

    How to Use FTP to Upload Files to WordPress via SSH Key: Step-by-Step Guide

    In this guide, we will walk you through using FTP (specifically, the secure version, SFTP) to upload files to your WordPress website. While WordPress offers a built-in file uploader for media and plugins, FTP provides more control and is essential for certain tasks, like uploading large files, modifying theme or plugin files directly, or troubleshooting.

    Step 1: Choose an FTP Client

    An FTP client is a software application that allows you to connect to a remote server and transfer files. Many free and paid options are available, but for security and ease of use, we strongly recommend choosing one that supports SFTP (SSH File Transfer Protocol).

    We recommend you take a look at our previous blog post titled “The Best 5 FTP Client for Windows and Mac” – but if you’re in a hurry, here are some popular and reliable choices:

    • FileZilla (Free, Cross-Platform): A widely used, well-regarded, free, open-source FTP client. It’s available for Windows, macOS, and Linux.
    • WinSCP (Free, Windows): Another popular free and open-source client, specifically for Windows.
    • Cyberduck (Free/Paid, Windows & macOS): A versatile client that supports FTP and SFTP and cloud storage services like Amazon S3 and Google Cloud Storage. It has a simple, drag-and-drop interface.
    • Transmit (Paid, macOS): A powerful and feature-rich FTP client for macOS, known for its speed and reliability.

    We’ll assume you’ve chosen FileZilla for this guide, but the general steps will be similar for other clients.

    📖 Suggested read: ​How to Use SFTP with FileZilla to Securely Transfer Files on RunCloud

    Step 2: Connect with FTP Credentials from Your Hosting Provider

    Before you can connect, you’ll need your SFTP credentials. These are not the same as your WordPress admin credentials. Your hosting provider (or server management platform) will provide these details. You’ll typically need the following:

    • Host (or Server Address): This is usually a domain name (e.g., example.com) or an IP address (e.g., 192.168.1.1).
    • Username: This is your SFTP username, often specific to your web hosting account or a user you created on your server.
    • SSH Key: A secret key (like a password) associated with your SFTP username.
    • Port: This is usually 22 for SFTP. Never use port 21 (which is for unencrypted FTP) unless you have a very specific and secure reason.

    Finding Your Credentials: The exact steps for finding your credentials will vary for different cloud providers. However, if you’re using RunCloud, this process is quick and painless. Navigate to your server, then to “Web Applications”. Select your WordPress installation, and note down the IP address, username, and root path (highlighted in the image below).

    After this, ensure that the SFTP user you noted in the previous step has SSH access to your server by navigating to the SSH menu of the server section. If the username is missing from the list, follow RunCloud documentation to learn more about generating and storing SSH keys in the RunCloud vault.

    After this, navigate to your server’s “Security” section and ensure that TCP traffic is allowed on the port being used for SSH. It uses port 22 by default, but server administrators often change it to something unique.

    Once you have gathered all the necessary information, you can open your FTP software and create a connection. In Filezilla, you can do this by clicking on “File > Site Manager”.

    In the Site Manager menu, fill in the following information:

    • Protocol: SFTP
    • Hostname: IP address that you noted earlier
    • Port: If you are not using the default port (22), then you need to enter your port number here
    • Logon Type: Key file
    • User: Enter the username that you noted earlier
    • Key File: Browse the files on your computer and select the private SSH key for your server

    After entering the above information, you can connect to the server. But we encourage you to go one step further and switch to the Advanced tab.

    On this tab, you can set the default local directory (the folder where WordPress is installed on your computer) and the default remote directory (the path you noted earlier).

    📖 Suggested read: How to Check if TCP Port is Open, Closed, or in Use on Linux?

    Finally, you can click “Connect” to initiate the connection with your server. The first time you connect to a server via SFTP, your client will likely display a warning about an unknown host key. This is a security measure to prevent man-in-the-middle attacks. Verify the key’s fingerprint against the one provided by your hosting provider (if available). If it matches, you can safely accept the key and proceed.

    Step 3: Navigate to Your WordPress Directory Structure

    Once connected, you’ll typically see two panes in your FTP client:

    • Left Pane (Local Site): This shows the files and folders on your local computer.
    • Right Pane (Remote Site): This shows the files and folders on your web server.

    You need to navigate to the correct directory on your server where your WordPress files are located. The exact path can vary depending on your hosting setup, but if you follow the steps described above, you will be in your WordPress directory.

    ⚠️ Important: Do not modify core WordPress files (in wp-admin and wp-includes) unless you know what you’re doing. Most file uploads will be within the wp-content directory.

    Step 4: Uploading Files to WordPress

    Now that you’re in the correct directory, uploading files is straightforward:

    1. Locate the file(s) on your local computer (left pane).
    2. Navigate to the destination directory on the server (right pane). For example, if you’re uploading a new theme, navigate to wp-content/themes/.
    3. Drag and Drop: Drag the file(s) or folder(s) from the left pane (local) to the right pane (remote). Alternatively, right-click the file(s) and choose “Upload”.
    4. File Transfer Queue: FileZilla will show the progress of the upload in a queue at the bottom of the window.

    Things to keep in mind:

    • Overwriting Files: If a file with the same name already exists in the destination directory, the FTP client will usually ask you if you want to overwrite it. Be cautious when overwriting files, especially if you’re unsure what they are.
    • File Permissions: Sometimes, you might need to adjust file permissions after uploading. This controls who can read, write, and execute files. Incorrect permissions can cause issues with your website. Your hosting provider or RunCloud documentation can provide guidance on appropriate file permissions. Generally, folders are 755, and files are 644.

    Step 5: Verifying Successful Uploads

    After the upload is complete, it’s a good idea to verify that the files were transferred correctly:

    1. Check the FTP Client: FileZilla (and most other clients) will indicate successful transfers in the queue. Look for any error messages.
    2. Test on Your Website: If you uploaded a plugin or theme, go to your WordPress admin dashboard and check if it appears in the Plugins or Themes section. Activate it and test its functionality. If you upload media files, check the Media Library.
    3. Check File Permissions (if necessary): If you’re experiencing issues, use your FTP client or RunCloud’s file manager to check and adjust file permissions as needed.

    By following these steps, you can confidently use FTP (SFTP) to upload files to your WordPress website. This gives you greater control over your site’s files and enables you to perform tasks that might not be possible through the WordPress admin interface alone.

    📖 Suggested read: How to Fix WordPress Stuck in Maintenance Mode? [100% WORKING]

    Troubleshooting Common FTP Issues

    Even with careful setup, you might encounter issues when using FTP to connect to your WordPress server. This section covers some of the most common problems and provides solutions to get you back on track.

    Connection Errors

    Connection errors are often the first hurdle. Here’s a breakdown of common causes and how to fix them:

    “Connection refused” or “Could not connect to server”

    This usually indicates a problem with the server address, port, or firewall. To solve this issue, try the following steps:

    • Verify Credentials: Double-check the Host/Server Address, Username, Password, and Port. Ensure you’re using port 22 for SFTP (and not 21 for insecure FTP). Even a small typo can prevent connection. Copy and paste the credentials directly from your hosting provider’s control panel or RunCloud dashboard to avoid errors.
    • Check the Server Status: Is your server up and running? Your hosting provider’s status page or RunCloud’s server overview will show you if there are any known outages.
    • Firewall Issues: A firewall on your computer, router, or server might be blocking the connection.
      • Local Firewall: Temporarily disable your computer’s firewall (e.g., Windows Firewall, macOS Firewall) to see if it’s the culprit. If it is, you must add an exception for your FTP client (e.g., FileZilla) to allow connections on port 22.
      • Router Firewall: Check your router’s configuration to ensure it’s not blocking outgoing connections on port 22. You might need to forward port 22 to your computer’s internal IP address.
      • Server Firewall: If you’re managing your server (e.g., with RunCloud), check the server’s firewall rules. Ensure that port 22 is open for incoming connections. RunCloud provides a firewall management interface that simplifies this.
    • Incorrect Protocol: Make sure you’re using SFTP, not plain FTP. Your FTP client should have an option to select the protocol.

    “Authentication failed”

    This means your username or password (or both) is incorrect.

    • Double-Check Credentials: Carefully re-enter your username and password. Pay attention to capitalization, as usernames and passwords are often case-sensitive.
    • Reset Password: If you’re unsure of your password, reset it through your hosting provider’s control panel.
    • SSH Key Authentication (Advanced): If you use SSH key authentication instead of a password, ensure your private key is correctly configured in your FTP client, and the corresponding public key is authorized on the server.

    📖 Suggested read: 3 Ways to Fix Too Many Authentication Failures SSH Root? [SOLVED]

    File Permissions Problems

    Incorrect file permissions can prevent your WordPress website from functioning correctly. When uploading files, you might see errors such as “Permission denied,” or your website might display errors or behave unexpectedly.

    Linux (and Unix-like) systems use file permissions to control who can read, write, and execute files and directories. A standard permission set is 755 (owner: read/write/execute, group: read/execute, others: read/execute) for directories and 644 (owner: read/write, group: read, others: read) for files.

    “Permission denied” when uploading

    If you see this error, then you likely don’t have write permission to the target directory. Use your FTP client to change the directory’s permissions.

    Changing Permissions in FileZilla:

    1. Right-click on the file or directory.
    2. Choose “File permissions…”
    3. Enter the numeric value (e.g., 755) or check the appropriate boxes for read, write, and execute.
    4. Optionally, check “Recurse into subdirectories” to apply the changes to all files and folders within the directory.

    Alternatively, RunCloud provides a one-click option named “Fix Permissions” that will fix all permissions issues. Follow the instructions described in the RunCloud documentation to learn how to resolve file access issues on your server.

    Timeouts and Other Common Issues

    Connection Timeouts

    If your connection is slow or unstable, the FTP client might time out before a transfer completes. You can try the following approaches to fix this:

    • Increase Timeout Settings: Most FTP clients have settings to adjust the connection timeout. Increase the timeout value (e.g., to 60 seconds or more).
    • Use a Wired Connection: For a more stable connection, use a wired Ethernet connection instead of Wi-Fi.

    Transfer Failures

    Sometimes, files might fail to transfer completely; ensure you have enough disk space on both your local computer and the server. RunCloud provides a built-in disk usage monitoring solution to make this easy.

    Wrapping Up: Who Should Use FTP for Their WordPress Websites?

    Throughout this guide, we’ve discussed the details of using FTP and, more importantly, its secure counterpart, SFTP, with WordPress.

    The need for direct FTP access is generally low for basic WordPress users (bloggers and small business owners) who primarily focus on content creation and use the standard WordPress interface for tasks like plugin installation and media uploads. The built-in WordPress tools, combined with a user-friendly server management platform like RunCloud, handle the vast majority of day-to-day operations.

    RunCloud, for instance, offers a comprehensive file manager directly within its web-based dashboard. This file manager allows you to browse your WordPress directories, perform basic text file edits, and manage file permissions, all without needing a separate FTP client.

    However, the need for FTP (SFTP) increases as your WordPress usage becomes more sophisticated. Intermediate users, such as freelancers or agencies managing multiple WordPress sites, often need to customize themes and plugins (requiring direct code edits), troubleshoot issues by examining server logs, or upload larger files that might be cumbersome through the WordPress interface.

    In these scenarios, SFTP provides the necessary direct access and control. RunCloud seamlessly integrates with SFTP, offering easy SFTP user management.

    RunCloud provides the perfect balance of ease of use and advanced functionality. Sign up for RunCloud today.

    FAQs on Using FTP with WordPress

    What is the difference between FTP and SFTP?

    FTP transmits data in plain text, making it highly vulnerable to interception. SFTP (Secure File Transfer Protocol) encrypts all communication, including your username, password, and file data, ensuring secure transfers. Always use SFTP; it’s like the difference between a postcard and a sealed letter.

    Do I need FTP to install WordPress plugins?

    Generally, you don’t need FTP to install plugins, as WordPress has a built-in plugin installer through the admin dashboard. However, FTP (specifically SFTP) can be useful for troubleshooting, manually uploading large plugins, or when the built-in installer fails. RunCloud’s file manager offers a web-based alternative to FTP for many tasks, but direct server access via SFTP is still available.

    Can I use FTP on shared hosting?

    Yes, you can usually use FTP (SFTP is strongly recommended) on shared hosting accounts. Your hosting provider will typically provide you with SFTP credentials to access your web space. However, shared hosting environments may have limitations on connection speeds or concurrent connections.

    What are the security risks of using FTP?

    The primary risk of using plain FTP is the unencrypted transmission of your credentials and data, which exposes them to potential eavesdropping. This can lead to a compromised website, stolen data, or malicious code injection. Always prioritize SFTP to mitigate these significant security risks.

    How do I find my FTP credentials?

    Your web hosting provider provides your FTP (SFTP) credentials, often found in your hosting control panel (like cPanel, Plesk, or a custom panel). For RunCloud-managed servers, you can create SFTP users and manage their access through the RunCloud dashboard, granting specific directory permissions. You will typically need a hostname (or IP address), username, password, and sometimes a port number (22 for SFTP, 21 for FTP – but again, avoid plain FTP).

    Is FTP still relevant in 2025?

    While web-based file managers and other tools are becoming more common, FTP (specifically SFTP) remains relevant for developers and power users. SFTP provides a robust and secure way to directly manage files on a server, which is crucial for tasks like debugging, custom development, and large file transfers. It’s a fundamental tool for server management, even with modern alternatives.

    What do I do if my FTP connection keeps dropping?

    Network instability, firewall issues, or server-side restrictions can cause frequent FTP connection drops. Try using a wired connection instead of Wi-Fi, check your firewall settings to ensure SFTP (port 22) is allowed, and contact your hosting provider or check RunCloud’s server logs for potential issues. Sometimes, adjusting the timeout settings in your FTP client can also help.

    How can I speed up my FTP transfers?

    To improve FTP (SFTP) transfer speeds, ensure you have a stable internet connection and use a wired connection if possible. You can also try using an FTP client that supports multiple concurrent connections (if your server allows it) and compressing files before transferring them. Consider the geographical location of your server; transferring files to a server closer to you will generally be faster.