Our packages are changing…

Effective June 22, 2016 our packages have changed for new clients. Technology changes as does what is considered the “bare minimum” utility set. Applications built on Symfony assume Composer support. Laravel requires Artisan. Even static sites use SCSS/SASS preprocessors to change look and feel on the fly. Everything is tied back to the terminal, which is now standard on every package. Every package also includes requisite support to run Node, Ruby, or Python utilities from the command-line limited only by available package memory (begins at 256 MB). All accounts prior to June 22, 2016 will be grandfathered into the old rates and specifications.

Along with standardizing terminal support, the baseline $5/month package has been retired in favor of a $10/month Essential package including a doubling of storage to 2 GB. All packages have had monthly transfer doubled as well.

Moving forward, including terminal support on all accounts provides an exciting opportunity to streamline, within the control panel, the development pipeline for clients from source to release of web applications.

Oh, and we’re turning 14 in July, so stay tuned!

Matt Saladna
Founder & Lead CP Developer

apnscp Update + New Fortification Mode: Learning

A new control panel update has been pushed to the servers incorporating a “Learning Mode” to Fortification available under Web > Web Apps. Learning bridges the gap between known and unknown web apps by taking a filesystem snapshot, opening permissions, then taking another snapshot after a predetermined amount of time (60 minutes). Changes are calculated three ways: creation time, modification time, and size to determine what files the web application has modified during this window. Once a changeset has been calculated, the control panel locks down all files except those files (or directories) required by the web server.

Learning Mode is only available on unknown apps. Common apps (WordPress, Joomla!, Drupal, and Magento) have prescribed Fortification Modes available to each (and Web App Write Mode is always available to allow 100% write access for 10 minutes). Learning Mode is relevant only when an application is installed that does not fit into the big four.


Other changes

Beyond Fortification enhancements, there is a new API call for unattended commands, pman_schedule_api_cmd(), which powers a significant share of new CP enhancements; scheduled task tagging to prevent duplicate tasks; initial webhook framework; localization (Account > Change Information); and 125 miscellaneous changes and fixes to the control panel!


  • NEW: NO_WAIT flag, send command to backend without waiting for response (DataStream)
  • NEW: localization. Feature does not affect CP language at this time, only one-clicks if support
  • NEW: Joomla! one-click, still need to implement update + extension management (Web Apps)
  • NEW: Web App Write Mode, a fortification mode that temporarily grants write-access to the web server for 10 minutes, then seizes those files created rendering it secure from future modification (Web Apps)
  • NEW: add support for non-numeric array keys (Error Reporter)
  • NEW: add umask support to Util_Process::Sudo()
  • NEW: schedule_api_cmd_admin()- run an api command as any arbitrary account and any user under that account (Pman)
  • NEW: schedule_api_cmd()- run an apnscp command as the current user at a given time (Pman)
  • NEW: add duplicate atd process detection with ID tags (Util_Process::Schedule)
  • NEW: Magento 1.x one-click
  • NEW: $.ajaxWait()- add ajax spinner icon + disable button on interaction (apnscp)
  • NEW: Drupal one-click
  • NEW: set_acls()- glob() support (File)
  • NEW: renew()- renew LE certificates (LetsEncrypt)
  • NEW: add WordPress install option to Add Subdomain/Addon Domains
  • NEW: include recommended preloaded WP stacks
  • NEW: WordPress one-click module (WordPress)
  • NEW: normalize_path()- take a hostname + optional path component and return its corresponding docroot (Web)
  • NEW: support array data types using the format [item1,item2,…] or key-value as [item1:val1,…] (cmd)
  • NEW: empty_mysql_database() – retain schema structure, but purge all records in db (SQL)
  • NEW: export databases (MySQL Manager)
  • NEW: EOL selector on file edit (File Manager)
  • NEW: Let’s Encrypt multi-domain (SAN) support (SSL)
  • FIX: typo on path to log files (File Manager)
  • FIX: allow deletion of directories (File Manager)
  • FIX: fortify(max) called immediately after web app write mode enabled (Web Apps)
  • FIX: truncated parameters include markup language (DNS)
  • FIX: strip quotes if key passed to CLI quoted (cmd)
  • FIX: bring back addon domain editor (Addon Domains)
  • FIX: error once if domain -> site mapping fails instead of on each record (tabulateBandwidth)
  • FIX: email on v4 platforms delivered using LF EOL, parser expects CRLF (parseTicket.php)
  • FIX: trim randomly generated name if name + prefix exceeds user column max length (Module_Support::Webapps)
  • FIX: get_directory_contents()- call stat() instead of stat_backend() to take advantage of stat cache (File)
  • FIX: killing shellinabox left behind children (Service::Terminal)
  • FIX: encode seen server cookie to prevent cookie spanning multiple lines that would break the Set-Cookie header (Auth::Redirect)
  • FIX: get_acls()- incorrect caching (File)
  • FIX: when changing domain, on logout, force an internal proxy redirect to the server. Logging out will clear the temporary proxy location cookie rendering the client unable to login following a domain change (Change Information)
  • FIX: extract inline attachments (parseTicket)
  • FIX: get_user_settings() must return array at all times (Manage Users)
  • FIX: require domains to be selected when creating a subdomain (Subdomains)
  • FIX: get_address_from_domain()- handle addon domains (Admin)
  • FIX: heredoc syntax on v6.5+ platforms (WordPress)
  • FIX: global subdomain url formatting fails (Web Apps)
  • FIX: PHP 5.3 compatibility, using self within a closure (Pman)
  • FIX: match foo.domain-name.com (Regex)
  • FIX: set_acls()- parser fixes (File)
  • FIX: reorder su parameters (Util_Process::Sudo)
  • FIX: new directory form control injection (FileTree)
  • FIX: Uncaught Error: Syntax error, unrecognized expression: option[value=] (Manage Mailboxes)
  • FIX: mysql_database_exists()- if mysql database exists, is not located under site root, and has privileges by dbaseadmin, return true (SQL)
  • FIX: only directories in xferlist are copied (Transfer)
  • FIX: missing __state variable (PostgreSQL Manager)
  • FIX: AJAX indicator does not show (CSS)
  • FIX: multiple stale cache bugs relating to recently-deleted files (File)
  • FIX: TypeError: g.load is not a function (Dashboard)
  • FIX: preserve custom mailbox on user rename (Mail)
  • FIX: unable to remove GA key (Change Information)
  • FIX: fallthrough subdomain improperly configured (Subdomains)
  • FIX: add_virtual_transport()- accessing dns_get_records() as if non-multidimensional array, doh (Email)
  • FIX: broken mailbox editor
  • FIX: escape chroot argument (Util_Process::Chroot)
  • FIX: hostname param missing on user edit when remote hosts not displayed (MySQL Manager)
  • FIX: login option alignment on smaller screens
  • FIX: row improperly cleared (Summary)
  • FIX: support TXT records > 255 characters (DNS)
  • FIX: destination not set on edit (Manage Mailboxes)
  • FIX: install()- SSLCertificateChainFile is not set when replacing a certificate if custom HTTP config present from previous SSL install (SSL)
  • FIX: build CSS assets under subdirectories
  • FIX: get_processes() – Fatal error: Cannot access self:: when no class scope is active on PHP 5.3 (Pman)
  • CHG: add .htaccess to minimum fortification (wordpress)
  • CHG: tag active fortification mode (Web Apps)
  • CHG: load page with database/user list expanded upon deletion (MySQL Manager)
  • CHG: add system status to login page (Login)
  • CHG: chown()- use optimized shadow assertions, ~70x speed up (file)
  • CHG: chown()- prefer tomcat_system_user() for proper Tomcat user (file)
  • CHG: set_acls()- always treat flags as array (file)
  • CHG: renewals that fail due to zero valid hostnames (account moved on) should not elicit a renewal failure (Letsencrypt)
  • CHG: trim parameter before ajax callback (DNS Manager)
  • CHG: auto-install Composer on 4.5+ platforms if missing (php)
  • CHG: cap Magento to 1.x if MySQL < 5.6 (magento)
  • CHG: kick out Magento 2 for now…
  • CHG: on func cache miss, expire func table (apnscpFunctionInterceptor)
  • CHG: db_config()- export table prefix (Web Apps)
  • CHG: remove no recalc mask (n) flag to default ACL settings (file)
  • CHG: proper Magento version tracking (Magento)
  • CHG: add uid support to -u (Auth::CLI)
  • CHG: Add DNS form formatting (DNS Manager)
  • CHG: avoid globbing non-existent paths (File)
  • CHG: set_acls()- retain effective rights mask on acl adjustment (file)
  • CHG: run()- force umask to override system default (0002) for site admins (pman)
  • CHG: fail request if error produced (letsencrypt)
  • CHG: delay HTTP reload for SSL installation by 2 minutes, reload when load permits, and tag by ID to prevent duplicate reload requests (SSL)
  • CHG: fully implement automated Let’s Encrypt SSL renewal
  • CHG: consolidate Util_Process::Batch into Util_Process::Schedule
  • CHG: escape the parameter rather than the components (Util_Account::Editor)
  • CHG: unconditionally enable openssl on certificate install (SSL)
  • CHG: force SSL if certificate setup OK (Magento)
  • CHG: get_acls()- only pull ACL information from shadow layer where appropriate (File)
  • CHG: require fortify()/unfortify() implementations; reflection will not pick these methods up unless explicitly defined in the derived class (WordPress, Drupal)
  • CHG: set trusted_host_patterns on 8.x+ Drupal installations (Drupal)
  • CHG: limit ticket data height to at most 650px (Trouble Tickets)
  • CHG: strip reply from Outlook-generated messages that merge reply + original message in one mime part (parseTicket)
  • CHG: add bypass support for changing primary domain on an account (Change Information)
  • CHG: if detection fails, ensure map entry is removed (Webapps)
  • CHG: get_docroot()- truncate www. if present (Web)
  • CHG: stat()- return empty array instead of null if stat path does not exist (File)
  • CHG: breakout webapp common function to separate support structure (Module_Support::Webapps)
  • CHG: create docroot directory if it does not already exist (WordPress)
  • CHG: open some method privileges to administrator (SSL)
  • CHG: take ceil used, floor free in calculating storage/bandwidth usage (UCard)
  • CHG: take ceil used, floor free in calculating storage/bandwidth usage (UCard)
  • CHG: integrate htaccess manager + app manager into Addon Domains and Subdomains
  • CHG: enable recovery mode
  • CHG: perform correct redirection if account resides on proxy endpoint and is suspended (Auth::Redirect)
  • CHG: add namespace autoloading (apnscpFunctionInterceptor)
  • CHG: support flushing user preferences if preferences written through common_save_preferences() instead of UCard::setPref()
  • CHG: create_temp_mysql_user()- MariaDB 10.1 no longer implicitly creates user on GRANT (SQL)
  • CHG: handle case where all_domains/ exists and is directory gracefully
  • CHG: reject record if its hostname contains spaces (DNS)
  • CHG: add support methods getParameterByName(), getUrl, allow ucwords to extend String object (apnscp)
  • CHG: verify proc pid exists before performing stat (Pman)
  • CHG: move()- only perform symlink chown if uid >= minimum uid or apache; excludes changing to root if symlink was root:root, e.g. mainwebsite_html (File)
  • CHG: bypass systemd when reloading (and config rebuilding) HTTP server (Web)
  • CHG: only invoke g.load if it is really loaded (Dashboard)
  • CHG: mysql_schema_column_maxlen()- cache results (SQL)
  • CHG: set_mysql_privileges()- add support for $privileges to be a two-element array consisting of “read” and “write” privilege simplification (SQL)
  • CHG: purge page cache on file upload on v6.5+ platforms (File Manager)
  • CHG: disable button + replace with “Processing” on account wipe (Change Information)
  • CHG: initialize_download()- remove fifo deletion callback on fork, since code can never logically reach (File)
  • CHG: make recursive directory deletion implied (File Manager)
  • CHG: flush page template buffer before app logic evaluation (Page Template)
  • CHG: unoptimized codepath if calling stat() from UI (File)
  • CHG: remove .php exposure on soap endpoint (Net_WSDL)
  • CHG: display amnesty request if storage within 98.5% capacity, instead of 99.5% (Dashboard)
  • CHG: modify_mailbox() make parameter list less cumbersome, drop catchall ability entirely (Email)
  • CHG: cache payments for only 24 hours (Billing)
  • CHG: send HUP, not USR2 to flush Dovecot auth cache on user creation (User)
  • CHG: move auth flush from user to user creation hook in email module
  • CHG: record_exists() drop timeout from 5 to 1 second (DNS)
  • CHG: expand upload block if previous action is upload (File Manager)
  • CHG: copy()- use non-shadow path on copy for overlayfs-backed platforms, which have issues invalidating the page cache on direct branc manipulation without performing a costly remount (File)
  • CHG: convert backup routines to Util_Process (backup DBs)
  • CHG: install()- ensure http config is rebuilt (SSL)
  • CHG: make postcss available on v6.5+ platforms
  • CHG: use postcss for CSS minification
  • CHG: switch JS build from YUI to UglifyJS
  • CHG: upgrade TinyMCE to 4.3.2
  • CHG: add PEAR5.php compatibility library for Util_HTML_BBCode
  • CHG: split_host()- include hostname that failed splitting (Web)
  • CHG: general JS fixups (DNS Manager)
  • CHG: jail_user()- use the referent if jailed path is a symlink (FTP)
  • CHG: kill SIGUSR2 dovecot/auth on v6.5+ platforms to flush dovecot auth cache (User)
  • CHG: minor analytics appearance tweaks
  • CHG: move open ticket position for admin (Trouble Tickets)
  • CHG: Dovecot on 6.5+ platforms use systemd, which lacks non-LSB commands. Instead of dovecot flush/reload send SIGUSR2 directly to auth process to flush cache on user addition (User)
  • CHG: delete_user()- remove user-specific subdomain during user deletion if only subdomain present (User)
  • CHG: include server name in X-Server header
  • REM: tomcat4/tomcat name conversion from get_service_value() (Module_Skeleton)
  • REM: jquery.ui.css dependency (Terminal)

One-clicks are back

Effective immediately, one-clicks are gradually making their return to the control panel after an 8 year hiatus, but in a limited release on version 4.5+ platforms. Specifically, one-clicks are coming for WordPress, Drupal, Magento, and some basic Node/Ruby/Python scaffolding. Webapps may be managed within the control panel under Web > Web Apps or preloaded on subdomain/addon domain creation under the Advanced options dropdown.

Application install via Web > Add Subdomains
Application install via Web > Add Subdomains
Simple updates within the CP
Simple updates within the CP

Why now?

Simply noted, the control panel is now mature enough and provides enough internal functionality to support one-clicks in a coherent, optimized flow without nasty hacks. These one-clicks are also drastically different from what was once provided in the CP. These rely upon programs developed by the authors of the software to provide functionality. For WordPress there’s wp-cli, Drupal is drush, npm for Node, and gem for Ruby. No, this isn’t reinventing the wheel. It’s taking a perfectly fine wheel and putting it on a vehicle. This is how we are able to bring one-clicks back to the CP in limited capacity.

What about other apps?

These won’t be supported within the control panel until sufficient trust is established.

There is a lot to say about code quality. Why does an app crash? Bad coding. Why does an app have a security flaw? Oversight, bad coding. Why does an app become abandoned? Lack of dedication by the author, and your output is a product of your inputs, so let’s safely assume there is some bad coding involved in that decision making process. There are thousands of PHP applications out there. There are hundreds of Node and Ruby apps out there too, but they all lack a sufficient level of competency to safely and securely run. Having handled a couple dozen PHP7-specific adaptations for clients migrating to Luna, which uses PHP7 by default, I can say confidently that beauty runs skin deep. Often times, apps with less money behind them simply fail to attract necessary talent to produce software that works today and will continue to work tomorrow. Yes, some apps do some really stupid things, like use continue/break outside of loop structures (SimpleMachinesForum comes to mind as a repeat offender). PHP7 has clamped down on these mind-boggling incorrect uses of programming syntax.

Security is paramount, especially in an era where virtualization has enabled thousands more machines access to the Internet. These machines are often manned by unqualified personnel that remain neglected for so long only to succumb to third-party control through an exploit. Your hosting servers routinely block over 2,000 brute-force attacks per day. These blocks are based on egregious patterns (5+ logins within 3 minutes), but hundreds more fly under the radar trying only a handful of logins ever hour. Consequently, clients with weak passwords eventually fall victim to these drive-by hackings. It’s unfortunate. Clients are charged a service fee for cleanups. My time is often diverted, as an emergency, to clean up residual damage to ensure other clients conduct business uninterrupted. Moving forward, I want to continue to focus on building a secure platform. One-clicks help realize this vision through a few awesome components:

Fortification mode

Fortification mode is, by far, the most unique component to web apps deployed within the CP. Fortification bestows a secondary level of permissions through access control lists that permit mutual access by the web server, which runs as a separate user from your account. Before, this was accessible only by opening a ticket. Fortification allows the web server to write and modify files only to which it receives explicit authorization. In the event of a hack, a hacker can only modify files to which the web server has access. Beneficially, if a web site were hacked, the hacker is unable to access your email, SSH keys, and other confidential information. Fortification strikes a perfect balance between ease-of-use and security. Just toggle fortification via Web > Web Apps within the control panel. With fortification on, the web server cannot modify any files on your account. Comments and posts continue to post as normal. With fortification off, you may upload media to posts. Although, you’ll still need your control panel password to install new plugins!

Fortification mode enabled vs disabled on a WordPress install
Fortification mode enabled vs disabled on a WordPress install. Write permisisons enabled/revoked on /wp-content/uploads.

Recovery mode

Circling back to a previous topic, crappy programmers beget crappy code. Recovery mode allows you to disable all third-party plugins and access a plain jane installation. Ideally, this will allow you to iteratively enable each plugin until you can safely determine which third-party programmer shouldn’t be a programmer.

Automatic updates

Coming soon. All one-clicks are enrolled into automatic updates to protect clients from zero-day exploits. These updates will roll out every night at 3 AM EDT during nightly CP updates. Tentatively, this will also extend to Ruby and Node.

Dual-user security

PHP apps run as a secondary user for myriad reasons. The most important reason is auditing; if an account gets hacked, we need to know what may be infected, what is infected, and what’s not. If the web server lacks write-privileges, then it is safe to say no. If the web server created the file within 24 hours of the incident, it’s safe to say yes. And if the web server had mutual write-access, then these require further auditing. Most hosting providers run PHP under your username, which is ludicrous, stupid, and irresponsible. It’s also the reason why major hosting providers bundle SiteLock service (which runs $100/mo plus a cleanup cost per infraction) service, their parent company owns UnitedWeb/IPOWER who in turn owns SiteLock, oh and their stock is (or was) doing very well! I base profit on providing a service, not holding clients who get hacked ransom. A $15 cleanup fee is charged to cover the 10 minutes it takes to do a quick audit and that’s it. We also scan uploads for malware, because once again we are in business to do good, not hold your account hostage due to negligence. In fact, the crux of this release is to make it impossible for you to be a victim. An online presence today is just as important, if not more important, than your physical presence; look at the power Yelp has to create or destroy businesses. Having a prospective client pull up a placeholder to the Syrian Electronic Army is a pretty damning display of incompetence. Look at the Panama Papers hack: outdated WordPress + single-user security. Let’s stop hacked sites. Let’s start by progressively providing secure platforms from the start.

Plugin stacks

WordPress comes with a couple stacks handpicked by my confidence to provide an uninterrupted and uneventful use of service. The security stack includes WordFence, renown for their investigative eye; XML pingback disabling; and comment disabling. The performance stack includes W3 Total Cache, which is used aggressively on the Knowledge Base and periodic database optimizations through WP Optimize. You can install both, either, or none depending upon what works best for your setup.

App enrollment

Got an existing WordPress app and want to enroll it into the new system? Easy as clicking Detect from within Web > Web Apps > Hostname selection. Got WordPress installed within a folder on your domain name? Click the dropdown menu and select Edit Subdir. Select your location from the filetree.

Detection mode
Detection mode


What’s next?

Drupal support through Drush is coming next (May 14 edit: Drupal is here), followed by Magento, which will include Let’s Encrypt support. We should see that sometime within the next week or so, followed by a lull as Passenger process management is planned for integration. Beyond this, I am always open to suggestions. Drop me an email at matt@apisnetworks.com with any idea whether big or small. After all, this control panel and platform wouldn’t exist without your voice!


Matt Saladna
Owner & Platform Developer


May 14, 2016: Drupal is now available
May 18, 2016: Magento 1.x is now available