Author: thelovekesh

  • Why I Built wpm: A Secure, Go-Based Package Manager for WordPress

    I have spent years working with enterprise WordPress, running websites that are critical to the business and simply cannot go down. When you are operating at that level, infrastructure is not something you can treat as an afterthought. You have to take it seriously from the very beginning if you want things to scale without breaking.

    One of the hardest parts is dealing with dependencies, especially plugins and themes. For teams that manage WordPress through code, Composer is usually the go to tool. The problem is that Composer does not really understand WordPress on its own. To make it work, we depend on tools like wpackagist, which act as a bridge and turn WordPress.org plugins into something Composer can actually use.

    When you install a package via wpackagist, it resolves to something like this:

    {
      "name": "wpackagist-plugin/wordpress-seo",
      "version": "25.6",
      "dist": {
        "type": "zip",
        "url": "https://downloads.wordpress.org/plugin/wordpress-seo.25.6.zip"
      }
    }

    If you look closely, wpackagist is essentially a proxy. It points the Composer resolver to a raw ZIP file on WordPress.org.

    This works for public plugins, but a mature WordPress site relies on commercial/private packages. This is where the headache begins. You have a few not so good options:

    1. Private Composer Repos: You have to manage authentication for every single vendor.
    2. Git URLs: It works, but requires maintaining access tokens.
    3. Manual Scripts: Custom bash scripts to download, unzip, and commit code.

    None of these are free. They all come with maintenance overhead.

    The Missing Features

    A true package manager does more than just download files. It should:

    • Resolve Dependencies: If I install Plugin A and it depends on Plugin B, it should automatically install Plugin B. Currently, because WordPress plugins lack standard dependency metadata, Composer cannot do this. You have to manually download both.
    • Run Lifecycle Scripts: Automate build steps or cleanup tasks after installation.
    • Verify Security: Ensure the file you downloaded is actually the file the author published.

    The Security Gap: This is where things really start to fall apart for enterprises. There is no standard way today to verify where a WordPress plugin actually comes from. If the original source or a proxy server gets compromised, you could end up installing a modified plugin without ever realizing it.

    Origin of the wpm Registry

    To solve this, I created the wpm registry. Unlike existing solutions, this registry enforces a strict metadata schema (wpm.json) that allows for:

    1. True Dependency Resolution: Context-aware installation.
    2. Supply Chain Security: Attestation and cryptographically verifiable signatures at the time of publication.

    We now had a single source of truth for public and private packages. The remaining problem was how to install them.

    Origin of the wpm Package Manager

    We built a specific registry with specific requirements, so we chose to write a package manager from scratch in Go. This leads to the most common question we get:

    “Why reinvent the wheel? Why not just write a Composer plugin?”

    We love Composer, but wpm solves infrastructure challenges that Composer wasn’t designed for:

    1. Deterministic “Installer” vs. “Solver”
    Composer is a dependency solver that calculates the best intersection of versions for a library. wpm is designed as a strict artifact installer. In the WordPress ecosystem, resolving version ranges can be risky (e.g., automated updates triggering database migrations). wpm is built to strictly enforce exact versions defined by the registry, ensuring 100% reproducibility.

    2. The “Single Binary” Advantage
    Composer requires a functional PHP CLI environment, specific extensions (zip/curl), and adequate memory limits. In the fragmented WordPress hosting world, we cannot guarantee these prerequisites.

    By writing wpm in Go, we ship a single, static binary with zero dependencies. It runs on the OS, not the PHP runtime. It includes its own networking stack and Zstd decompressor, meaning it works even on restrictive hosting environments where PHP allows web traffic but blocks CLI tools.

    3. Supply Chain Security (TUF & Sigstore)
    We are prioritizing supply chain security from day one. wpm integrates TUF (The Update Framework) and provenance verification. The tooling for these standards is mature and native in the Go ecosystem (thanks to Cloud Native tools). Porting these complex security frameworks to PHP would be error-prone and slow; in Go, they are first-class citizens.

    The Reality Check

    Composer is the standard tool in the PHP world, but it assumes something that rarely exists in practice. It assumes every server has a clean and properly configured command line environment.

    The reality with WordPress is much messier. Hosting is often locked down, runtimes vary from one server to another, and required extensions are frequently disabled. By building wpm in Go, we avoided these environmental issues altogether.

    We did not build wpm because Composer is a bad tool. We built it because we needed a single, self contained binary that could run securely no matter how the server was set up.

    Real World Example: Installing a Dependency

    Let’s look at a common scenario: You want to install a plugin like dinopack-for-elementor. As the name suggests, this plugin requires the core Elementor plugin to function.

    Here is how the experience differs between the two tools.

    1. The Composer Way

    First, Composer doesn’t know where to find WordPress plugins by default. You must create or edit your composer.json to add the wpackagist repository:

    {
        "repositories": [
            {
                "type": "composer",
                "url": "https://wpackagist.org"
            }
        ]
    }

    Next, you run the install command:

    $ composer require wpackagist-plugin/dinopack-for-elementor

    The Result: Composer downloads dinopack-for-elementor, but fails to download elementor.

    Why? Because the wpackagist proxy doesn’t inject dependency metadata. You now have a broken site. You must manually figure out which version of Elementor is compatible, then run a second command to install it.

    2. The wpm Way

    With wpm, there is zero setup. You don’t need to create a config file or define repositories. The registry already knows the dependency graph.

    You simply run:

    $ wpm install dinopack-for-elementor

    The Result: wpm detects the dependency, resolves the correct version, and installs everything in parallel with blazing speed.

    $ wpm install dinopack-for-elementor                          
    wpm install v0.1.7
    
    + dinopack-for-elementor 1.0.5
    + elementor 3.34.1
    
    2 packages installed

    No config files, no manual dependency hunting, no broken plugins. Just the artifact you requested, ready to run.

    3. Clear visibility into your setup

    Since wpm handles dependencies automatically, you might notice a package you didn’t explicitly request (like elementor above) and wonder, “Why is this here?”

    With wpm, you don’t have to guess. You can simply ask the tool:

    $ wpm why elementor                 
    my-cool-project  (dependencies)
    └─ [email protected]
       └─ [email protected]

    It instantly visualizes the dependency tree, showing you exactly which plugin required elementor to be installed. No config files, no manual dependency hunting, just total transparency.

    The Future of WordPress Dependencies

    For a long time, the WordPress ecosystem has leaned on solutions that were simply good enough. We proxy zip files, ignore dependency graphs, and hope the server is set up the right way. That might work for small sites, but as WordPress runs more mission critical enterprise systems, good enough stops being acceptable.

    wpm is not just another CLI tool. It is a rethink of how the WordPress supply chain should work. By treating plugins and themes as secure, immutable artifacts and separating the installer from the server’s PHP setup, we bring a level of reliability that WordPress has been missing.

    Ready to dive in?

    If you are ready to experience a faster, secure, and more reliable way to manage WordPress dependencies, here is where you can start:

  • Install Let’s Encrypt with Nginx on Ubuntu 20.04

    Install Let’s Encrypt with Nginx on Ubuntu 20.04

    With evolving web security standards, Google has emphasized the importance of using HTTPS, making it the new default for websites. As a result, HTTPS is now essential for securing your site and building user trust.

    In this tutorial, you’ll learn how to use Let’s Encrypt Certbot to obtain a free SSL/TLS certificate for Nginx on Ubuntu 20.04, and how to configure automatic certificate renewal.

    Let’s Encrypt is a free, automated, and open certificate authority (CA) provided by the nonprofit Internet Security Research Group (ISRG). It offers a simple way to enable HTTPS by issuing free SSL certificates.

    To streamline the process, Let’s Encrypt works with Certbot, a software client that automates the tasks of requesting, installing, and renewing certificates on your web server.

    Prerequisites

    Before you begin, make sure you have the following:

    • A sudo-enabled non-root user and a firewall configured on your server.
    • A registered domain name.
    • The following DNS records set up for your domain:
      • An A record pointing example.com to your server’s public IP address.
      • An A record pointing www.example.com to your server’s public IP address.
    • Nginx installed on your server.
    • A server block (virtual host) configured for your domain in Nginx, typically located in the /etc/nginx/sites-available/ directory.

    Installing Certbot

    To obtain a Let’s Encrypt SSL certificate, you’ll first need to install the Certbot software on your server.

    Use the following command to install Certbot along with its Nginx plugin:

    sudo apt install certbot python3-certbot-nginx

    Once the installation is complete, Certbot and its Nginx plugin will be ready to use.

    Next, we’ll review your Nginx configuration to ensure it’s properly set up for certificate issuance.

    Validate Nginx Configuration

    Certbot needs to identify the correct server block in your Nginx configuration to automatically install the SSL certificate. It does this by locating a server_name directive that matches the domain you’re requesting a certificate for.

    To check this, open your domain’s Nginx configuration file with a text editor:

    sudo nano /etc/nginx/sites-available/example.com

    Look for the server_name line. It should look something like:

    server_name example.com www.example.com;
    • If the domain names are correctly listed, you can exit the editor.
    • If not, update the server_name line to include your domain and subdomain. Then save and close the file.

    Next, test your Nginx configuration for syntax errors:

    sudo nginx -t
    • If you receive an error, reopen the file and correct any typos.
    • Once the test passes, reload Nginx to apply the changes:
    sudo systemctl reload nginx

    With the correct server block in place, Certbot will now be able to automatically configure SSL for your domain.

    Up next, let’s configure the firewall to allow HTTPS traffic.

    Allowing HTTPS Through the Firewall

    Before you request an SSL certificate, ensure your firewall allows HTTPS traffic.

    Enable the Nginx Full profile, which includes rules for both HTTP and HTTPS, and then remove the redundant Nginx HTTP rule:

    sudo ufw allow 'Nginx Full'
    sudo ufw delete allow 'Nginx HTTP'

    Check the firewall status to confirm the changes:

    sudo ufw status

    You should see output similar to:

    Status: active
    
    To                         Action      From
    --                         ------      ----
    OpenSSH                    ALLOW       Anywhere
    Nginx Full                 ALLOW       Anywhere
    OpenSSH (v6)               ALLOW       Anywhere (v6)
    Nginx Full (v6)            ALLOW       Anywhere (v6)

    Obtaining an SSL Certificate

    Certbot can obtain and install SSL certificates using a variety of plugins. Here, we’ll use the Nginx plugin, which automatically updates your Nginx configuration and reloads it as needed.

    Run the following command, replacing the domain names with your own:

    sudo certbot --nginx -d example.com -d www.example.com

    If this is your first time using Certbot, you’ll be prompted to:

    1. Enter a valid email address (for renewal and security notices).
    2. Agree to the terms of service.
    3. (Optional) Subscribe to EFF’s newsletter.

    Certbot will then communicate with Let’s Encrypt and run a challenge to verify your domain ownership.

    Once verified, you’ll be asked how to handle HTTP traffic:

    Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: No redirect - Make no further changes to the webserver configuration.
    2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
    new sites, or if you're confident your site works on HTTPS. You can undo this
    change by editing your web server's configuration.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

    Choose an option and press Enter. Certbot will then update your Nginx configuration and reload the server.

    If successful, you’ll see a message like:

    IMPORTANT NOTES:
     - Congratulations! Your certificate and chain have been saved at:
       /etc/letsencrypt/live/example.com/fullchain.pem
       Your key file has been saved at:
       /etc/letsencrypt/live/example.com/privkey.pem
       Your cert will expire on 2020-08-18. To obtain a new or tweaked
       version of this certificate in the future, simply run certbot again
       with the "certonly" option. To non-interactively renew *all* of
       your certificates, run "certbot renew"
     - If you like Certbot, please consider supporting our work by:
    
       Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
       Donating to EFF:                    https://eff.org/donate-le

    Now, visit your site at https://example.com to confirm it’s secured.

    For a detailed security report, test your domain with SSL Labs’ SSL Test. A properly configured site typically receives an A grade.

    Verifying Certbot Auto-Renewal

    Let’s Encrypt certificates are valid for 90 days, but Certbot includes a systemd timer that automatically renews them.

    To check the status of the auto-renewal timer:

    sudo systemctl status certbot.timer

    You should see something like:

    ● certbot.timer - Run certbot twice daily
         Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
         Active: active (waiting) since Mon 2020-05-04 20:04:36 UTC; 2 weeks 1 days ago
        Trigger: Thu 2020-05-21 05:22:32 UTC; 9h left
       Triggers: ● certbot.service

    To test the renewal process manually and ensure everything is working:

    sudo certbot renew --dry-run

    If no errors appear, your renewal setup is working correctly. Certbot will handle automatic renewals and reload Nginx when needed. In case of any issues, notifications will be sent to the email address you provided during setup.

    Conclusion

    Securing your website with HTTPS is no longer optional—it’s a key part of maintaining user trust and meeting modern web standards. In this tutorial, you’ve learned how to use Let’s Encrypt and Certbot to install a free SSL certificate on an Nginx server, as well as how to configure automatic renewals to keep your certificate up to date. With these steps complete, your website is now more secure and ready for encrypted traffic.

    For ongoing security, remember to regularly monitor your server and test your SSL configuration. A secure website not only protects your users—it builds your reputation online.