Page MenuHomePhorge

No OneTemporary

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}.

File Metadata

Mime Type
text/x-diff
Expires
Thu, Feb 20, 23:27 (3 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1120136
Default Alt Text
(43 KB)

Event Timeline