diff --git a/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php b/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php
index d1db832aa2..19f8c625d7 100644
--- a/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php
+++ b/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php
@@ -1,496 +1,496 @@
 <?php
 
 final class PhabricatorLDAPAuthProvider extends PhabricatorAuthProvider {
 
   private $adapter;
 
   public function getProviderName() {
     return pht('LDAP');
   }
 
   public function getDescriptionForCreate() {
     return pht(
       'Configure a connection to an LDAP server so that users can use their '.
       'LDAP credentials to log in.');
   }
 
   public function getDefaultProviderConfig() {
     return parent::getDefaultProviderConfig()
       ->setProperty(self::KEY_PORT, 389)
       ->setProperty(self::KEY_VERSION, 3);
   }
 
   public function getAdapter() {
     if (!$this->adapter) {
       $conf = $this->getProviderConfig();
 
       $realname_attributes = $conf->getProperty(self::KEY_REALNAME_ATTRIBUTES);
       if (!is_array($realname_attributes)) {
         $realname_attributes = array();
       }
 
       $search_attributes = $conf->getProperty(self::KEY_SEARCH_ATTRIBUTES);
       $search_attributes = phutil_split_lines($search_attributes, false);
       $search_attributes = array_filter($search_attributes);
 
       $adapter = id(new PhutilLDAPAuthAdapter())
         ->setHostname(
           $conf->getProperty(self::KEY_HOSTNAME))
         ->setPort(
           $conf->getProperty(self::KEY_PORT))
         ->setBaseDistinguishedName(
           $conf->getProperty(self::KEY_DISTINGUISHED_NAME))
         ->setSearchAttributes($search_attributes)
         ->setUsernameAttribute(
           $conf->getProperty(self::KEY_USERNAME_ATTRIBUTE))
         ->setRealNameAttributes($realname_attributes)
         ->setLDAPVersion(
           $conf->getProperty(self::KEY_VERSION))
         ->setLDAPReferrals(
           $conf->getProperty(self::KEY_REFERRALS))
         ->setLDAPStartTLS(
           $conf->getProperty(self::KEY_START_TLS))
         ->setAlwaysSearch($conf->getProperty(self::KEY_ALWAYS_SEARCH))
         ->setAnonymousUsername(
           $conf->getProperty(self::KEY_ANONYMOUS_USERNAME))
         ->setAnonymousPassword(
           new PhutilOpaqueEnvelope(
             $conf->getProperty(self::KEY_ANONYMOUS_PASSWORD)))
         ->setActiveDirectoryDomain(
           $conf->getProperty(self::KEY_ACTIVEDIRECTORY_DOMAIN));
       $this->adapter = $adapter;
     }
     return $this->adapter;
   }
 
   protected function renderLoginForm(AphrontRequest $request, $mode) {
     $viewer = $request->getUser();
 
     $dialog = id(new AphrontDialogView())
       ->setSubmitURI($this->getLoginURI())
       ->setUser($viewer);
 
     if ($mode == 'link') {
       $dialog->setTitle(pht('Link LDAP Account'));
       $dialog->addSubmitButton(pht('Link Accounts'));
       $dialog->addCancelButton($this->getSettingsURI());
     } else if ($mode == 'refresh') {
       $dialog->setTitle(pht('Refresh LDAP Account'));
       $dialog->addSubmitButton(pht('Refresh Account'));
       $dialog->addCancelButton($this->getSettingsURI());
     } else {
       if ($this->shouldAllowRegistration()) {
         $dialog->setTitle(pht('Log In or Register with LDAP'));
         $dialog->addSubmitButton(pht('Log In or Register'));
       } else {
         $dialog->setTitle(pht('Log In with LDAP'));
         $dialog->addSubmitButton(pht('Log In'));
       }
       if ($mode == 'login') {
         $dialog->addCancelButton($this->getStartURI());
       }
     }
 
     $v_user = $request->getStr('ldap_username');
 
     $e_user = null;
     $e_pass = null;
 
     $errors = array();
     if ($request->isHTTPPost()) {
       // NOTE: This is intentionally vague so as not to disclose whether a
       // given username exists.
       $e_user = pht('Invalid');
       $e_pass = pht('Invalid');
       $errors[] = pht('Username or password are incorrect.');
     }
 
     $form = id(new PHUIFormLayoutView())
       ->setUser($viewer)
       ->setFullWidth(true)
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel(pht('LDAP Username'))
           ->setName('ldap_username')
           ->setAutofocus(true)
           ->setValue($v_user)
           ->setError($e_user))
       ->appendChild(
         id(new AphrontFormPasswordControl())
           ->setLabel(pht('LDAP Password'))
           ->setName('ldap_password')
           ->setError($e_pass));
 
     if ($errors) {
       $errors = id(new PHUIInfoView())->setErrors($errors);
     }
 
     $dialog->appendChild($errors);
     $dialog->appendChild($form);
 
 
     return $dialog;
   }
 
   public function processLoginRequest(
     PhabricatorAuthLoginController $controller) {
 
     $request = $controller->getRequest();
     $viewer = $request->getUser();
     $response = null;
     $account = null;
 
     $username = $request->getStr('ldap_username');
     $password = $request->getStr('ldap_password');
     $has_password = strlen($password);
     $password = new PhutilOpaqueEnvelope($password);
 
     if (!strlen($username) || !$has_password) {
       $response = $controller->buildProviderPageResponse(
         $this,
         $this->renderLoginForm($request, 'login'));
       return array($account, $response);
     }
 
     if ($request->isFormPost()) {
       try {
         if (strlen($username) && $has_password) {
           $adapter = $this->getAdapter();
           $adapter->setLoginUsername($username);
           $adapter->setLoginPassword($password);
 
           // TODO: This calls ldap_bind() eventually, which dumps cleartext
           // passwords to the error log. See note in PhutilLDAPAuthAdapter.
           // See T3351.
 
           DarkConsoleErrorLogPluginAPI::enableDiscardMode();
             $identifiers = $adapter->getAccountIdentifiers();
           DarkConsoleErrorLogPluginAPI::disableDiscardMode();
         } else {
           throw new Exception(pht('Username and password are required!'));
         }
       } catch (PhutilAuthCredentialException $ex) {
         $response = $controller->buildProviderPageResponse(
           $this,
           $this->renderLoginForm($request, 'login'));
         return array($account, $response);
       } catch (Exception $ex) {
         // TODO: Make this cleaner.
         throw $ex;
       }
     }
 
     $account = $this->newExternalAccountForIdentifiers($identifiers);
 
     return array($account, $response);
   }
 
 
   const KEY_HOSTNAME                = 'ldap:host';
   const KEY_PORT                    = 'ldap:port';
   const KEY_DISTINGUISHED_NAME      = 'ldap:dn';
   const KEY_SEARCH_ATTRIBUTES       = 'ldap:search-attribute';
   const KEY_USERNAME_ATTRIBUTE      = 'ldap:username-attribute';
   const KEY_REALNAME_ATTRIBUTES     = 'ldap:realname-attributes';
   const KEY_VERSION                 = 'ldap:version';
   const KEY_REFERRALS               = 'ldap:referrals';
   const KEY_START_TLS               = 'ldap:start-tls';
   // TODO: This is misspelled! See T13005.
   const KEY_ANONYMOUS_USERNAME      = 'ldap:anoynmous-username';
   const KEY_ANONYMOUS_PASSWORD      = 'ldap:anonymous-password';
   const KEY_ALWAYS_SEARCH           = 'ldap:always-search';
   const KEY_ACTIVEDIRECTORY_DOMAIN  = 'ldap:activedirectory-domain';
 
   private function getPropertyKeys() {
     return array_keys($this->getPropertyLabels());
   }
 
   private function getPropertyLabels() {
     return array(
       self::KEY_HOSTNAME => pht('LDAP Hostname'),
       self::KEY_PORT => pht('LDAP Port'),
       self::KEY_DISTINGUISHED_NAME => pht('Base Distinguished Name'),
       self::KEY_SEARCH_ATTRIBUTES => pht('Search Attributes'),
       self::KEY_ALWAYS_SEARCH => pht('Always Search'),
       self::KEY_ANONYMOUS_USERNAME => pht('Anonymous Username'),
       self::KEY_ANONYMOUS_PASSWORD => pht('Anonymous Password'),
       self::KEY_USERNAME_ATTRIBUTE => pht('Username Attribute'),
       self::KEY_REALNAME_ATTRIBUTES => pht('Realname Attributes'),
       self::KEY_VERSION => pht('LDAP Version'),
       self::KEY_REFERRALS => pht('Enable Referrals'),
       self::KEY_START_TLS => pht('Use TLS'),
       self::KEY_ACTIVEDIRECTORY_DOMAIN => pht('ActiveDirectory Domain'),
     );
   }
 
   public function readFormValuesFromProvider() {
     $properties = array();
     foreach ($this->getPropertyLabels() as $key => $ignored) {
       $properties[$key] = $this->getProviderConfig()->getProperty($key);
     }
     return $properties;
   }
 
   public function readFormValuesFromRequest(AphrontRequest $request) {
     $values = array();
     foreach ($this->getPropertyKeys() as $key) {
       switch ($key) {
         case self::KEY_REALNAME_ATTRIBUTES:
           $values[$key] = $request->getStrList($key, array());
           break;
         default:
           $values[$key] = $request->getStr($key);
           break;
       }
     }
 
     return $values;
   }
 
   public function processEditForm(
     AphrontRequest $request,
     array $values) {
     $errors = array();
     $issues = array();
     return array($errors, $issues, $values);
   }
 
   public static function assertLDAPExtensionInstalled() {
     if (!function_exists('ldap_bind')) {
       throw new Exception(
         pht(
           'Before you can set up or use LDAP, you need to install the PHP '.
           'LDAP extension. It is not currently installed, so PHP can not '.
           'talk to LDAP. Usually you can install it with '.
           '`%s`, `%s`, or a similar package manager command.',
           'yum install php-ldap',
-          'apt-get install php5-ldap'));
+          'apt-get install php-ldap'));
     }
   }
 
   public function extendEditForm(
     AphrontRequest $request,
     AphrontFormView $form,
     array $values,
     array $issues) {
 
     self::assertLDAPExtensionInstalled();
 
     $labels = $this->getPropertyLabels();
 
     $captions = array(
       self::KEY_HOSTNAME =>
         pht('Example: %s%sFor LDAPS, use: %s',
           phutil_tag('tt', array(), pht('ldap.example.com')),
           phutil_tag('br'),
           phutil_tag('tt', array(), pht('ldaps://ldaps.example.com/'))),
       self::KEY_DISTINGUISHED_NAME =>
         pht('Example: %s',
           phutil_tag('tt', array(), pht('ou=People, dc=example, dc=com'))),
       self::KEY_USERNAME_ATTRIBUTE =>
         pht('Example: %s',
           phutil_tag('tt', array(), pht('sn'))),
       self::KEY_REALNAME_ATTRIBUTES =>
         pht('Example: %s',
           phutil_tag('tt', array(), pht('firstname, lastname'))),
       self::KEY_REFERRALS =>
         pht('Follow referrals. Disable this for Windows AD 2003.'),
       self::KEY_START_TLS =>
         pht('Start TLS after binding to the LDAP server.'),
       self::KEY_ALWAYS_SEARCH =>
         pht('Always bind and search, even without a username and password.'),
     );
 
     $types = array(
       self::KEY_REFERRALS           => 'checkbox',
       self::KEY_START_TLS           => 'checkbox',
       self::KEY_SEARCH_ATTRIBUTES   => 'textarea',
       self::KEY_REALNAME_ATTRIBUTES => 'list',
       self::KEY_ANONYMOUS_PASSWORD  => 'password',
       self::KEY_ALWAYS_SEARCH       => 'checkbox',
     );
 
     $instructions = array(
       self::KEY_SEARCH_ATTRIBUTES   => pht(
         "When a user provides their LDAP username and password, this ".
         "software can either bind to LDAP with those credentials directly ".
         "(which is simpler, but not as powerful) or bind to LDAP with ".
         "anonymous credentials, then search for record matching the supplied ".
         "credentials (which is more complicated, but more powerful).\n\n".
         "For many installs, direct binding is sufficient. However, you may ".
         "want to search first if:\n\n".
         "  - You want users to be able to log in with either their username ".
         "    or their email address.\n".
         "  - The login/username is not part of the distinguished name in ".
         "    your LDAP records.\n".
         "  - You want to restrict logins to a subset of users (like only ".
         "    those in certain departments).\n".
         "  - Your LDAP server is configured in some other way that prevents ".
         "    direct binding from working correctly.\n\n".
         "**To bind directly**, enter the LDAP attribute corresponding to the ".
         "login name into the **Search Attributes** box below. Often, this is ".
         "something like `sn` or `uid`. This is the simplest configuration, ".
         "but will only work if the username is part of the distinguished ".
         "name, and won't let you apply complex restrictions to logins.\n\n".
         "  lang=text,name=Simple Direct Binding\n".
         "  sn\n\n".
         "**To search first**, provide an anonymous username and password ".
         "below (or check the **Always Search** checkbox), then enter one ".
         "or more search queries into this field, one per line. ".
         "After binding, these queries will be used to identify the ".
         "record associated with the login name the user typed.\n\n".
         "Searches will be tried in order until a matching record is found. ".
         "Each query can be a simple attribute name (like `sn` or `mail`), ".
         "which will search for a matching record, or it can be a complex ".
         "query that uses the string `\${login}` to represent the login ".
         "name.\n\n".
         "A common simple configuration is just an attribute name, like ".
         "`sn`, which will work the same way direct binding works:\n\n".
         "  lang=text,name=Simple Example\n".
         "  sn\n\n".
         "A slightly more complex configuration might let the user log in with ".
         "either their login name or email address:\n\n".
         "  lang=text,name=Match Several Attributes\n".
         "  mail\n".
         "  sn\n\n".
         "If your LDAP directory is more complex, or you want to perform ".
         "sophisticated filtering, you can use more complex queries. Depending ".
         "on your directory structure, this example might allow users to log ".
         "in with either their email address or username, but only if they're ".
         "in specific departments:\n\n".
         "  lang=text,name=Complex Example\n".
         "  (&(mail=\${login})(|(departmentNumber=1)(departmentNumber=2)))\n".
         "  (&(sn=\${login})(|(departmentNumber=1)(departmentNumber=2)))\n\n".
         "All of the attribute names used here are just examples: your LDAP ".
         "server may use different attribute names."),
       self::KEY_ALWAYS_SEARCH => pht(
         'To search for an LDAP record before authenticating, either check '.
         'the **Always Search** checkbox or enter an anonymous '.
         'username and password to use to perform the search.'),
       self::KEY_USERNAME_ATTRIBUTE => pht(
         'Optionally, specify a username attribute to use to prefill usernames '.
         'when registering a new account. This is purely cosmetic and does not '.
         'affect the login process, but you can configure it to make sure '.
         'users get the same default username as their LDAP username, so '.
         'usernames remain consistent across systems.'),
       self::KEY_REALNAME_ATTRIBUTES => pht(
         'Optionally, specify one or more comma-separated attributes to use to '.
         'prefill the "Real Name" field when registering a new account. This '.
         'is purely cosmetic and does not affect the login process, but can '.
         'make registration a little easier.'),
     );
 
     foreach ($labels as $key => $label) {
       $caption = idx($captions, $key);
       $type = idx($types, $key);
       $value = idx($values, $key);
 
       $control = null;
       switch ($type) {
         case 'checkbox':
           $control = id(new AphrontFormCheckboxControl())
             ->addCheckbox(
               $key,
               1,
               hsprintf('<strong>%s:</strong> %s', $label, $caption),
               $value);
           break;
         case 'list':
           $control = id(new AphrontFormTextControl())
             ->setName($key)
             ->setLabel($label)
             ->setCaption($caption)
             ->setValue($value ? implode(', ', $value) : null);
           break;
         case 'password':
           $control = id(new AphrontFormPasswordControl())
             ->setName($key)
             ->setLabel($label)
             ->setCaption($caption)
             ->setDisableAutocomplete(true)
             ->setValue($value);
           break;
         case 'textarea':
           $control = id(new AphrontFormTextAreaControl())
             ->setName($key)
             ->setLabel($label)
             ->setCaption($caption)
             ->setValue($value);
           break;
         default:
           $control = id(new AphrontFormTextControl())
             ->setName($key)
             ->setLabel($label)
             ->setCaption($caption)
             ->setValue($value);
           break;
       }
 
       $instruction_text = idx($instructions, $key);
       if (strlen($instruction_text)) {
         $form->appendRemarkupInstructions($instruction_text);
       }
 
       $form->appendChild($control);
     }
   }
 
   public function renderConfigPropertyTransactionTitle(
     PhabricatorAuthProviderConfigTransaction $xaction) {
 
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     $key = $xaction->getMetadataValue(
       PhabricatorAuthProviderConfigTransaction::PROPERTY_KEY);
 
     $labels = $this->getPropertyLabels();
     if (isset($labels[$key])) {
       $label = $labels[$key];
 
       $mask = false;
       switch ($key) {
         case self::KEY_ANONYMOUS_PASSWORD:
           $mask = true;
           break;
       }
 
       if ($mask) {
         return pht(
           '%s updated the "%s" value.',
           $xaction->renderHandleLink($author_phid),
           $label);
       }
 
       if ($old === null || $old === '') {
         return pht(
           '%s set the "%s" value to "%s".',
           $xaction->renderHandleLink($author_phid),
           $label,
           $new);
       } else {
         return pht(
           '%s changed the "%s" value from "%s" to "%s".',
           $xaction->renderHandleLink($author_phid),
           $label,
           $old,
           $new);
       }
     }
 
     return parent::renderConfigPropertyTransactionTitle($xaction);
   }
 
   public static function getLDAPProvider() {
     $providers = self::getAllEnabledProviders();
 
     foreach ($providers as $provider) {
       if ($provider instanceof PhabricatorLDAPAuthProvider) {
         return $provider;
       }
     }
 
     return null;
   }
 
 }
diff --git a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php
index 09b96d05cf..1862308052 100644
--- a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php
+++ b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php
@@ -1,153 +1,153 @@
 <?php
 
 /**
  * Noncritical PHP configuration checks.
  *
  * For critical checks, see @{class:PhabricatorPHPPreflightSetupCheck}.
  */
 final class PhabricatorPHPConfigSetupCheck extends PhabricatorSetupCheck {
 
   public function getDefaultGroup() {
     return self::GROUP_PHP;
   }
 
   protected function executeChecks() {
 
     if (empty($_SERVER['REMOTE_ADDR'])) {
       $doc_href = PhabricatorEnv::getDoclink('Configuring a Preamble Script');
 
       $summary = pht(
         'You likely need to fix your preamble script so '.
         'REMOTE_ADDR is no longer empty.');
 
       $message = pht(
         'No REMOTE_ADDR is available, so this server cannot determine the '.
         'origin address for requests. This will prevent the software from '.
         'performing important security checks. This most often means you '.
         'have a mistake in your preamble script. Consult the documentation '.
         '(%s) and double-check that the script is written correctly.',
         phutil_tag(
           'a',
           array(
             'href' => $doc_href,
             'target' => '_blank',
             ),
           pht('Configuring a Preamble Script')));
 
       $this->newIssue('php.remote_addr')
         ->setName(pht('No REMOTE_ADDR available'))
         ->setSummary($summary)
         ->setMessage($message);
     }
 
     if (version_compare(phpversion(), '7', '>=')) {
       // This option was removed in PHP7.
       $raw_post_data = -1;
     } else {
       $raw_post_data = (int)ini_get('always_populate_raw_post_data');
     }
 
     if ($raw_post_data != -1) {
       $summary = pht(
         'PHP setting "%s" should be set to "-1" to avoid deprecation '.
         'warnings.',
         'always_populate_raw_post_data');
 
       $message = pht(
         'The "%s" key is set to some value other than "-1" in your PHP '.
         'configuration. This can cause PHP to raise deprecation warnings '.
         'during process startup. Set this option to "-1" to prevent these '.
         'warnings from appearing.',
         'always_populate_raw_post_data');
 
       $this->newIssue('php.always_populate_raw_post_data')
         ->setName(pht('Disable PHP %s', 'always_populate_raw_post_data'))
         ->setSummary($summary)
         ->setMessage($message)
         ->addPHPConfig('always_populate_raw_post_data');
     }
 
     if (!extension_loaded('mysqli')) {
       $summary = pht(
         'Install the MySQLi extension to improve database behavior.');
 
       $message = pht(
         'PHP is currently using the very old "mysql" extension to interact '.
         'with the database. You should install the newer "mysqli" extension '.
         'to improve behaviors (like error handling and query timeouts).'.
         "\n\n".
         'This software will work with the older extension, but upgrading to '.
         'the newer extension is recommended.'.
         "\n\n".
         'You may be able to install the extension with a command like: %s',
 
         // NOTE: We're intentionally telling you to install "mysqlnd" here; on
         // Ubuntu, there's no separate "mysqli" package.
-        phutil_tag('tt', array(), 'sudo apt-get install php5-mysqlnd'));
+        phutil_tag('tt', array(), 'sudo apt-get install php-mysqlnd'));
 
       $this->newIssue('php.mysqli')
         ->setName(pht('MySQLi Extension Not Available'))
         ->setSummary($summary)
         ->setMessage($message);
     } else if (!defined('MYSQLI_ASYNC')) {
       $summary = pht(
         'Configure the MySQL Native Driver to improve database behavior.');
 
       $message = pht(
         'PHP is currently using the older MySQL external driver instead of '.
         'the newer MySQL native driver. The older driver lacks options and '.
         'features (like support for query timeouts) which allow this server '.
         'to interact better with the database.'.
         "\n\n".
         'This software will work with the older driver, but upgrading to the '.
         'native driver is recommended.'.
         "\n\n".
         'You may be able to install the native driver with a command like: %s',
-        phutil_tag('tt', array(), 'sudo apt-get install php5-mysqlnd'));
+        phutil_tag('tt', array(), 'sudo apt-get install php-mysqlnd'));
 
 
       $this->newIssue('php.myqlnd')
         ->setName(pht('MySQL Native Driver Not Available'))
         ->setSummary($summary)
         ->setMessage($message);
     }
 
 
     if (extension_loaded('mysqli')) {
       $infile_key = 'mysqli.allow_local_infile';
     } else {
       $infile_key = 'mysql.allow_local_infile';
     }
 
     if (ini_get($infile_key)) {
       $summary = pht(
         'Disable unsafe option "%s" in PHP configuration.',
         $infile_key);
 
       $message = pht(
         'PHP is currently configured to honor requests from any MySQL server '.
         'it connects to for the content of any local file.'.
         "\n\n".
         'This capability supports MySQL "LOAD DATA LOCAL INFILE" queries, but '.
         'allows a malicious MySQL server read access to the local disk: the '.
         'server can ask the client to send the content of any local file, '.
         'and the client will comply.'.
         "\n\n".
         'Although it is normally difficult for an attacker to convince '.
         'this software to connect to a malicious MySQL server, you should '.
         'disable this option: this capability is unnecessary and inherently '.
         'dangerous.'.
         "\n\n".
         'To disable this option, set: %s',
         phutil_tag('tt', array(), pht('%s = 0', $infile_key)));
 
       $this->newIssue('php.'.$infile_key)
         ->setName(pht('Unsafe PHP "Local Infile" Configuration'))
         ->setSummary($summary)
         ->setMessage($message)
         ->addPHPConfig($infile_key);
     }
 
   }
 
 }
diff --git a/src/docs/user/configuration/configuration_guide.diviner b/src/docs/user/configuration/configuration_guide.diviner
index 1fde967a95..c5aa82af86 100644
--- a/src/docs/user/configuration/configuration_guide.diviner
+++ b/src/docs/user/configuration/configuration_guide.diviner
@@ -1,213 +1,213 @@
 @title Configuration Guide
 @group config
 
 This document contains basic configuration instructions for Phorge.
 
 = Prerequisites =
 
 This document assumes you've already installed all the components you need.
 If you haven't, see @{article:Installation Guide}.
 
 The next steps are:
 
   - Configure your webserver (Apache, nginx, or lighttpd).
   - Configure the databases.
   - Access Phorge with your browser.
   - Follow the instructions to complete setup.
 
 = Webserver: Configuring Apache =
 
 NOTE: Follow these instructions to use Apache. To use nginx or lighttpd, scroll
 down to their sections.
 
 Get Apache running and verify it's serving a test page. Consult the Apache
 documentation for help. Make sure `mod_php` and `mod_rewrite` are enabled,
 and `mod_ssl` if you intend to set up SSL.
 
 If you haven't already, set up a domain name to point to the host you're
 installing on. You can either install Phorge on a subdomain (like
 phorge.example.com) or an entire domain, but you can not install it in
 some subdirectory of an existing website. Navigate to whatever domain you're
 going to use and make sure Apache serves you something to verify that DNS
 is correctly configured.
 
 NOTE: The domain must contain a dot ('.'), i.e. not be just a bare name like
 'http://example/'. Some web browsers will not set cookies otherwise.
 
 Now create a VirtualHost entry for Phorge. It should look something like
 this:
 
   name=httpd.conf
   <VirtualHost *>
     # Change this to the domain which points to your host.
     ServerName phorge.example.com
 
     # Change this to the path where you put 'phorge' when you checked it
     # out from the upstream when following the Installation Guide.
     #
     # Make sure you include "/webroot" at the end!
     DocumentRoot /path/to/phorge/webroot
 
     RewriteEngine on
     RewriteRule ^(.*)$          /index.php?__path__=$1  [B,L,QSA]
   </VirtualHost>
 
 If Apache isn't currently configured to serve documents out of the directory
 where you put Phorge, you may also need to add `<Directory />` section. The
 syntax for this section depends on which version of Apache you're running.
 (If you don't know, you can usually figure this out by running `httpd -v`.)
 For Apache versions older than 2.4, use this:
 
   name="Apache Older Than 2.4"
   <Directory "/path/to/phorge/webroot">
     Order allow,deny
     Allow from all
   </Directory>
 
 For Apache versions 2.4 and newer, use this:
 
   name="Apache 2.4 and Newer"
   <Directory "/path/to/phorge/webroot">
     Require all granted
   </Directory>
 
 After making your edits, restart Apache, then continue to "Setup" below.
 
 = Webserver: Configuring nginx =
 
 NOTE: Follow these instructions to use nginx. To use Apache or lighttpd, scroll
 to their sections.
 
 For nginx, use a configuration like this:
 
   name=nginx.conf
   server {
     server_name phorge.example.com;
     root        /path/to/phorge/webroot;
 
     location / {
       index index.php;
       rewrite ^/(.*)$ /index.php?__path__=/$1 last;
     }
 
     location /index.php {
       fastcgi_pass   localhost:9000;
       fastcgi_index   index.php;
 
       #required if PHP was built with --enable-force-cgi-redirect
       fastcgi_param  REDIRECT_STATUS    200;
 
       #variables to make the $_SERVER populate in PHP
       fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
       fastcgi_param  QUERY_STRING       $query_string;
       fastcgi_param  REQUEST_METHOD     $request_method;
       fastcgi_param  CONTENT_TYPE       $content_type;
       fastcgi_param  CONTENT_LENGTH     $content_length;
 
       fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
 
       fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
       fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
 
       fastcgi_param  REMOTE_ADDR        $remote_addr;
     }
   }
 
 Restart nginx after making your edits, then continue to "Setup" below.
 
 = Webserver: Configuring lighttpd =
 
 NOTE: Follow these instructions to use lighttpd. To use Apache or nginx, scroll
 up to their sections.
 
 For lighttpd, add a section like this to your lighttpd.conf:
 
   $HTTP["host"] =~ "phorge(\.example\.com)?" {
       server.document-root = "/path/to/phorge/webroot"
       url.rewrite-once = (
           # This simulates QSA ("query string append") mode in apache
           "^(/[^?]*)\?(.*)" => "/index.php?__path__=$1&$2",
           "^(/.*)$" => "/index.php?__path__=$1",
       )
   }
 
 You should also ensure the following modules are listed in your
 server.modules list:
 
   mod_fastcgi
   mod_rewrite
 
 Finally, you should run the following commands to enable php support:
 
-  $ sudo apt-get install php5-cgi  # for Ubuntu; other distros should be similar
+  $ sudo apt-get install php-cgi  # for Ubuntu; other distros should be similar
   $ sudo lighty-enable-mod fastcgi-php
 
 Restart lighttpd after making your edits, then continue below.
 
 
 Load Balancer Health Checks
 ===========================
 
 If you're using a load balancer in front of your webserver, you can configure
 it to perform health checks using the path `/status/`.
 
 
 = Setup =
 
 Now, navigate to whichever subdomain you set up. You should see instructions to
 continue setup. The rest of this document contains additional instructions for
 specific setup steps.
 
 When you resolve any issues and see the welcome screen, enter credentials to
 create your initial administrator account. After you log in, you'll want to
 configure how other users will be able to log in or register -- until you do,
 no one else will be able to sign up or log in. For more information, see
 @{article:Configuring Accounts and Registration}.
 
 = Storage: Configuring MySQL =
 
 During setup, you'll need to configure MySQL. To do this, get MySQL running and
 verify you can connect to it. Consult the MySQL documentation for help. When
 MySQL works, you need to load the Phorge schemata into it. To do this, run:
 
   phorge/ $ ./bin/storage upgrade
 
 If your configuration uses an unprivileged user to connect to the database, you
 may have to override the default user so the schema changes can be applied with
 root or some other admin user:
 
   phorge/ $ ./bin/storage upgrade --user <user> --password <password>
 
 You can avoid the prompt the script issues by passing the `--force` flag (for
 example, if you are scripting the upgrade process).
 
   phorge/ $ ./bin/storage upgrade --force
 
 NOTE: When you update Phorge, run `storage upgrade` again to apply any
 new updates.
 
 = Next Steps =
 
 Continue by:
 
   - setting up your admin account and login/registration with
     @{article:Configuring Accounts and Registration}; or
   - understanding advanced configuration topics with
     @{article:Configuration User Guide: Advanced Configuration}; or
   - configuring an alternate file domain with
     @{article:Configuring a File Domain}; or
   - configuring a preamble script to set up the environment properly behind a
     load balancer, or adjust rate limiting with
     @{article:Configuring a Preamble Script}; or
   - configuring where uploaded files and attachments will be stored with
     @{article:Configuring File Storage}; or
   - configuring Phorge so it can send mail with
     @{article:Configuring Outbound Email}; or
   - configuring inbound mail with @{article:Configuring Inbound Email}; or
   - importing repositories with @{article:Diffusion User Guide}; or
   - learning about daemons with @{article:Managing Daemons with phd}; or
   - learning about notification with
     @{article:Notifications User Guide: Setup and Configuration}; or
   - configuring backups with
     @{article:Configuring Backups and Performing Migrations}; or
   - contributing to Phorge with @{article:Contributor Introduction}.
diff --git a/src/docs/user/field/restarting.diviner b/src/docs/user/field/restarting.diviner
index 638e1f1490..8e21c2ac77 100644
--- a/src/docs/user/field/restarting.diviner
+++ b/src/docs/user/field/restarting.diviner
@@ -1,116 +1,116 @@
 @title Restarting Phorge
 @group fieldmanual
 
 Instructions on how to restart HTTP and PHP servers to reload configuration
 changes in Phorge.
 
 
 Overview
 ========
 
 Phorge's setup and configuration instructions sometimes require you to
 restart your server processes, particularly after making configuration changes.
 This document explains how to restart them properly.
 
 In general, you need to restart both whatever is serving HTTP requests and
 whatever is serving PHP requests. In some cases, these will be the same process
 and handled with one restart command. In other cases, they will be two
 different processes and handled with two different restart commands.
 
 {icon exclamation-circle color=blue} If you have two different processes (for
 example, nginx and PHP-FPM), you need to issue two different restart commands.
 
 It's important to restart both your HTTP server and PHP server because each
 server caches different configuration and settings. Restarting both servers
 after making changes ensures you're running up-to-date configuration.
 
 To restart properly:
 
   - Identify which HTTP server you are running (for example, Apache or nginx).
   - Identify which PHP server you are running (for example, mod_php or PHP-FPM).
   - For each server, follow the instructions below to restart it.
   - If the instructions tell you to do so, make sure you restart **both**
     servers!
 
 
 Quick Start
 ===========
 
 **Apache**: If you use Apache with `mod_php`, you can just restart Apache. You
 do not need to restart `mod_php` separately. See below for instructions on how
 to do this if you aren't sure. This is a very common configuration.
 
 **nginx**: If you use nginx with PHP-FPM, you need to restart both nginx and
 PHP-FPM. See below for instructions on how to do this if you aren't sure. This
 is also a very common configuration.
 
 It's possible to use Apache or nginx in other configurations, or a different
 webserver. Consult the documentation for your system or webserver if you aren't
 sure how things are set up.
 
 
 Universal Restart
 =================
 
 If you are having trouble properly restarting processes on your server, try
 turning it off and on again. This is effective on every known system and
 under all configurations.
 
 
 HTTP Server: Apache
 ===================
 
 If you are using Apache with `mod_php`, you only need to restart Apache.
 
 If you are using Apache in FastCGI mode, you need to restart both Apache and
 the FCGI server (usually PHP-FPM). This is very unusual.
 
 The correct method for restarting Apache depends on what system you are
 running. Consult your system documentation for details. You might use a command
 like one of these on your system, or a different command:
 
 ```
 $ sudo apachectl restart
 $ sudo /etc/init.d/httpd restart
 $ sudo service apache2 restart
 ```
 
 
 HTTP Server: Nginx
 ==================
 
 If you're using Nginx with PHP-FPM, you need to restart both of them. This is
 the most common Nginx configuration.
 
 The correct method for restarting Nginx depends on what system you are running.
 Consult your system documentation for details. You might use a command like
 one of these on your system, or a different command:
 
 ```
 $ sudo /etc/init.d/nginx restart
 $ sudo service nginx restart
 ```
 
 
 PHP Server: mod_php
 ===================
 
 This is a builtin PHP server that runs within Apache. Restarting Apache (see
 above) is sufficient to restart it. There is no separate restart command for
 `mod_php`, so you don't need to do anything else.
 
 
 PHP Server: PHP-FPM
 ===================
 
 If you're using FastCGI mode, PHP-FPM is the most common PHP FastCGI server.
 You'll need to restart it if you're running it.
 
 The correct method for restarting PHP-FPM depends on what system you are
 running. Consult your system documentation for details. You might use a command
 like one of these on your system, or a different command:
 
 ```
 $ sudo /etc/init.d/php-fpm restart
-$ sudo service php5-fpm reload
+$ sudo service php-fpm reload
 ```
diff --git a/src/docs/user/installation_guide.diviner b/src/docs/user/installation_guide.diviner
index f3c2102059..ec7aa186d2 100644
--- a/src/docs/user/installation_guide.diviner
+++ b/src/docs/user/installation_guide.diviner
@@ -1,153 +1,153 @@
 @title Installation Guide
 @group intro
 
 This document contains basic install instructions to get Phorge up and
 running.
 
 Overview
 ========
 
 Phorge is a LAMP (Linux, Apache, MySQL, PHP) application. To install
 Phorge, you will need:
 
   - a normal computer to install it on (shared hosts and unusual environments
     are not supported) running some flavor of Linux or a similar OS;
   - a domain name (like `phorge.example.com`);
   - basic sysadmin skills;
   - Apache, nginx, or another webserver;
   - PHP;
   - MySQL (you will need a server with multiple databases);
   - git
 
 The remainder of this document details these requirements.
 
 You may be interested also in preparing these optional stuff:
 
   - have valid SMTP parameters for outgoing email notifications;
   - having nothing listening on port 22, to then setup a SSH+git server
 
 Installation Requirements
 =========================
 
 You will need **a computer**. Options include:
 
   - **A Normal Computer**: This is strongly recommended. Many installs use a VM
     in EC2. Phorge installs properly and works well on a normal computer.
   - **A Shared Host**: This may work, but is not recommended. Many shared
     hosting environments have restrictions which prevent some of Phorge's
     features from working. Consider using a normal computer instead. We do not
     support shared hosts.
   - **A SAN Appliance, Network Router, Gaming Console, Raspberry Pi, etc.**:
     Although you may be able to install Phorge on specialized hardware, it
     is unlikely to work well and will be difficult for us to support. Strongly
     consider using a normal computer instead. We do not support specialized
     hardware.
   - **A Toaster, Car, Firearm, Thermostat, etc.**: Yes, many modern devices now
     have embedded computing capability. We live in interesting times. However,
     you should not install Phorge on these devices. Instead, install it on
     a normal computer. We do not support installing on noncomputing devices.
 
 To install the Phorge server software, you will need an **operating
 system** on your normal computer which is **not Windows**. Note that the
 command line interface //does// work on Windows, and you can //use//
 Phorge from any operating system with a web browser. However, the server
 software does not run on Windows. It does run on most other operating systems,
 so choose one of these instead:
 
   - **Linux**: Most installs use Linux.
   - **Mac OS X**: Mac OS X is an acceptable flavor of Linux.
   - **FreeBSD**: While FreeBSD is certainly not a flavor of Linux, it is a fine
     operating system possessed of many desirable qualities, and Phorge will
     install and run properly on FreeBSD.
   - **Solaris, etc.**: Other systems which look like Linux and quack like Linux
     will generally work fine, although we may suffer a reduced ability to
     support and resolve issues on unusual operating systems.
 
 Beyond an operating system, you will need **a webserver**.
 
   - **Apache**: Many installs use Apache + `mod_php`.
   - **nginx**: Many installs use nginx + `php-fpm`.
   - **lighttpd**: `lighttpd` is less popular than Apache or nginx, but it
     works fine.
   - **Other**: Other webservers which can run PHP are also likely to work fine,
     although these installation instructions will not cover how to set them up.
   - **PHP Builtin Server**: Phorge will not work with the builtin
     webserver because Phorge depends on making requests to itself on some
     workflows, and the builtin webserver is single-threaded.
 
 You will also need:
 
   - **MySQL**: You need MySQL. We strongly recommend MySQL 5.5 or newer.
     You will need a server with multiple databases.
   - **PHP**: You need a PHP engine:
     - PHP 5 - 5.5 or newer.
     - PHP 7 - 7.1 or newer.
     - PHP 8 - **Not yet supported**. We're working on it as fast as we can,
     and expect to support PHP 8 Real Soon Now.
   - **git**: You need git 2.5.0 or newer on the server.
     No particular version is needed on your clients.
 
 You'll probably also need a **domain name**. In particular, you should read this
 note:
 
 NOTE: Phorge must be installed on an entire domain. You can not install it
 to a path on an existing domain, like `example.com/phorge/`. Instead,
 install it to an entire domain or subdomain, like `phorge.example.com`.
 
 Level Requirements
 ==================
 
 To install and administrate Phorge, you'll need to be comfortable with
 common system administration skills. For example, you should be familiar with
 using the command line, installing software on your operating system of choice,
 working with the filesystem, managing processes, dealing with permissions,
 editing configuration files, and setting environment variables.
 
 If you aren't comfortable with these skills, you can still try to perform an
 install. The install documentation will attempt to guide you through what you
 need to know. However, if you aren't very familiar or comfortable with using
 this set of skills to troubleshoot and resolve problems, you may encounter
 issues which you have substantial difficulty working through.
 
 We assume users installing and administrating Phorge are comfortable with
 common system administration skills and concepts. If you aren't, proceed at
 your own risk and expect that your skills may be tested.
 
 Installing Required Components
 ==============================
 
 Here's a general description of what you need to install:
 
   - git (usually called "git" in package management systems)
   - Apache (usually "httpd" or "apache2") (or nginx)
   - MySQL Server (usually "mysqld" or "mysql-server" or "mariadb-server")
   - PHP (usually "php")
   - Required PHP extensions: mbstring, iconv, mysql (or mysqli), curl, pcntl
-    (these might be something like "php-mysql" or "php5-mysqlnd")
+    (these might be something like "php-mysql" or "php-mysqlnd")
   - Optional PHP extensions: gd, zip
 
 If you already have LAMP setup, you've probably already got everything you need.
 It may also be helpful to refer to the install scripts above, even if they don't
 work for your system.
 
 Now that you have all that stuff installed, grab Phorge and its
 dependencies:
 
   $ cd somewhere/ # pick some install directory
   somewhere/ $ git clone https://we.phorge.it/source/arcanist.git
   somewhere/ $ git clone https://we.phorge.it/source/phorge.git
 
 After cloning, flag them as safe (to avoid the error //"fatal:
 detected dubious ownership in repository at ..."//):
 
   $ sudo git config --system --add safe.directory somewhere/arcanist
   $ sudo git config --system --add safe.directory somewhere/phorge
 
 Next Steps
 ==========
 
 Continue by:
 
   - configuring Phorge with the @{article:Configuration Guide}; or
   - learning how to keep Phorge up to date with
     @{article:Upgrading Phorge}.