Lumberg Lumberg Build Status

Lumberg logo

Ruby library for the WHM & cPanel API. It is currently what we consider to be beta-ish. Please report any issues you find. :)


Confirmed to work with ruby 2.1.3, 2.2.0, 2.3.1 and JRuby 1.9 mode.

cPanel Version Targets

  • cPanel 11.4x: v2.0.0
  • cPanel 11.3x: v2.0.0.pre10
  • cPanel 11.2x: v1.1.1


gem install lumberg


Create a server object and connect to WHM using your host and hash:

require 'lumberg'
server =
  host: WHM_HOST,
  hash: WHM_HASH

If you are using HTTP Basic Authentication with a username/password:

server =
  host:       WHM_HOST,
  user:       USERNAME,
  hash:       'my_password',
  basic_auth: true

You can access the modules of WHM by calling server.<module>. For example, server.account or server.dns. Here are the currently supported modules:

  • Account
  • DNS
  • Reseller

Here's how to get a list of accounts:

 = server.
result  = .list

Most responses will return success and a message

p "Returned #{result[:success]} with message: #{result[:message]}"

Returned true with message: Ok

You can grab the data you need from the results hash

num_accounts = result[:params][:acct].size
p "There are #{num_accounts} accounts"

There are 6 accounts

Here's an example of what the returned data looks like for a single account

pp result[:params][:acct].first

  startdate:      false,
  plan:           "default",
  suspended:      false,
  theme:          "x3",
  shell:          "/usr/local/cpanel/bin/jailshell",
  maxpop:         "unlimited",
  maxlst:         "unlimited",
  maxaddons:      "*unknown*",
  suspendtime:    nil,
  ip:             false,
  maxsub:         "unlimited",
  domain:         "",
  maxsql:         "unlimited",
  partition:      "home",
  maxftp:         "unlimited",
  user:           "bob",
  suspendreason:  "not suspended",
  unix_startdate: false,
  diskused:       false,
  maxparked:      "*unknown*",
  email:          "*unknown*",
  disklimit:      "unlimited",
  owner:          "root"

Account Example

Creating a new account requires only a username, domain, and password.

result = server..create(
  username: 'newuser',
  domain:   '',
  password: 'password'

if result[:success]
  p result[:message]

Account Creation Ok

You can list all accounts or search for a specific account.

result = server.account.list(search: 'new', searchtype: 'user')
acct   = result[:params][:acct].first
p "Found user '#{acct[:user]}' with domain '#{acct[:domain]}'"

Found user 'newuser' with domain ''

Suspending an account is simple and the reason for suspension is optional.

result = server..suspend(username: 'newuser', reason: 'bad user')
p "user was suspended successfully" if result[:success]

user was suspended successfully

We can look at the account list again to see the reason for the user's suspension.

result = server.account.list(search: 'new', searchtype: 'user')
acct   = result[:params][:acct].first
p "user '#{acct[:user]}' was suspended with reason '#{acct[:suspendreason]}'"

user 'newuser' was suspended with reason 'bad user'

Finally, we remove the user and delete their account.

result = server..remove(username: 'newuser')
p result[:message]

newuser  removed

Reseller Example

Creating a reseller works by changing the status of an existing user account, so first we create a user account and then we can create that user as a reseller.

result = server..create(
  username: 'rtest',
  domain:   '',
  password: 'password'

if result[:success]
  result = server.reseller.create(username: 'rtest', makeowner: true)
  p "created reseller rtest" if result[:success]

created reseller rtest

You can get a list of all of the reseller accounts easily.

result = server.reseller.list
p result[:params][:resellers].inspect

["samir", "rtest"]

Suspending a reseller is pretty straightforward. It's optional to provide a reason for the suspension.

result = server.reseller.suspend(username: 'rtest', reason: 'bad user')
p "reseller was suspended successfully" if result[:success]

user was suspended successfully

Deleting the reseller removes the reseller status from the user account. To also delete the user account, set the :terminatereseller argument.

result = server.reseller.terminate(reseller: 'rtest', terminatereseller: true)
p result[:message]

Account Terminations Complete

Accessing cPanel API

cPanel API interface is provided by the Lumberg::Cpanel module. Classes within the module correspond to cPanel API modules. cPanel API module coverage is currently incomplete and we're seeking contributions. Check out Extending Lumberg::Cpanel for details on how you can help.

Email example

# Create an interface object for cPanel API Email module
email =
  server:       server,  # An instance of Lumberg::Server
  api_username: "jerry"  # User whose cPanel we'll be interacting with

# Get a list of email accounts
email.accounts[:params][:data] #=> Array of info hashes for each email account

# Add an email forwarder to forward mail for to
  domain:   "",
  email:    "my-forwarder",
  fwdopt:   "fwd",
  fwdemail: ""


Extending Lumberg::Cpanel

  1. Find a cPanel API module that isn't already covered. See cPanel API documentation for a full list of available API modules.

  2. Create a file (underscore style) in lib/lumberg/cpanel/ named after the cPanel API module you're working on. If the cPanel API module is "LangMods" name the file "lang_mods.rb". You'll define your class here. require this file from lib/lumberg/cpanel.rb.

  3. Define a class that inherits from Lumberg::Cpanel::Base:

    # Create a class for (fictional) "SomeModule" API module
    module Lumberg
     module Cpanel
       class SomeModule < Base

    The cPanel API module name is normally inferred from the class name, e.g., if the class name is Email the cPanel "Email" API module will be used. If the cPanel API module you're working with doesn't match up with Ruby class naming convention, override the ::api_module class method:

    module Lumberg
     module Cpanel
       class SslInfo
         def self.api_module; "SSLInfo"; end
  4. Fill in the methods.

    module Lumberg
     module Cpanel
       class Branding
         # Public: Get URL locations for specific sprites.
         # options - Hash options for API call params (default: {}):
         #  :img        - String branding object label for the image you want to
         #                retrieve.
         #  :imgtype    - String branding image type you want to retrieve, e.g.,
         #                "icon" or "heading".
         #  :method     - String specification for returned value options.
         #                Acceptable values are: "only_filetype_gif",
         #                "skip_filetype_gif", "snap_to_smallest_width", and
         #                "scale_60percent".
         #  :subtype    - String branding image subtype, e.g., "img", "bg",
         #                "compleximg".
         #  :image      - String parameter allows you to force appropriate
         #                output by setting it to "heading" (optional).
         #  :skipgroups - String parameter allows you to specify whether or not
         #                to include "img" values that begin with "group_" in
         #                the output. "1" indicates that you wish to skip "img"
         #                values that begin with "group_" (optional).
         # Returns Hash API response.
         def list_sprites(options = {})
            api_function: "spritelist"
  • In many cases, you'll name your methods to match up with the documented cPanel API methods. However, the documented method names are sometimes a bit lengthy, confusing, or otherwise unwieldy; feel free to give your corresponding method an improved name.
  • Use TomDoc documentation for your methods. Be sure to document all required and optional parameters from the cPanel API documentation.
  • All methods should take an options arg that defaults to {}. These options should be merged onto the options passed to #perform_request to allow overriding of :api_username or other parameters.

Sanitizing VCR cassettes

All HTTP interactions are recorded using VCR and FakeWeb. Please be sure to remove sensitive data from your cassettes. A Rake task is provided for this purpose: WHM_HASH=$(cat my-access-hash) bundle exec rake sanitize_cassettes

Once you've sanitized your cassettes, manually verify that there's no sensitive information still present (check URLs, authorization params, etc.).

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so we don't break it in a future version unintentionally.
  • Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)
  • Send us a pull request. Bonus points for topic branches.


Copyright (c) 2015-2016 WWWH, LLC. See LICENSE for details.