Diffusion - Phabricator Repository Browser

Phabricator can host Git, Mercurial and Subversion repositories. It also works well with existing repositories (like GitHub, Bitbucket, or other repositories you already have elsewhere) without needing to host them itself.

Repository Hosting in Diffusion

As the title suggests, I am going to explain setting up Diffusion tool for your own source code hosting solution. If you haven't setup Phabricator yet, do head on to Phabricator. You can also follow my article on setting up Phabricator tool.

Diffusion setup is explained pretty well in diffusion docs on Phabricator. Please read twice before starting to make changes on the server as one mistake and you could be locked out of your instance.

Configuring System User Accounts

Phabricator uses as many as three user accounts;

  • daemon-user - We will configure the root user to run the daemons
  • www-user - We will use www-data to be the web user.
  • vcs-user - We will configure git user to the vcs user.

To enable SSH access to the repositories, edit /etc/sudoers file using visudo or sudoedit to contain:

git ALL=(root) SETENV: NOPASSWD: /usr/bin/git-upload-pack, /usr/bin/git-receive-pack, /usr/bin/git

If git is not yet available, you should install git using apt-get install git-core.

Since we are going to enable ssh access to the repositories, ensure the following holds good;

  • Open /etc/shadow' and find the line for gituser, the second field must not be set to!!. Update it to *orNP` for No Password instead.
  • Open /etc/passwd and find the line for git user, the last field (for the login shell) must be set to a real shell, update it /bin/sh or /bin/bash if it is set to something like /bin/false or /bin/nologin.

Configure phd.user to use our daemon-user;

phabricator/ $ ./bin/config set phd.user root
phabricator/ $ ./bin/config set diffusion.ssh-user git

Configuring SSH

Follow these steps with extra care as it has risk of locking us out of the machine.

  • We'll move the normal sshd daemon to another port, say 222. We will use this port to get a normal login shell.
  • We'll run highly restrictive sshd on port 22 managed by Phabricator.
Move Normal SSHD

Make a backup of sshd_config before making any changes.

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

Update /etc/ssh/sshd_config, change the Port to some other port like 222.

Port 222

Restart sshd and verify that you're able to connect to the new port;

ssh -p 222 ...
Configure and start Phabricator SSHD

We now configure and start a second sshd instance which will run on port 22. This instance will use special locked down configuration that uses Phabricator to handle the authentication and command execution.

  • Create a phabricator-ssh-hook.sh file
  • Create a sshd_phabricator config file
  • Start a copy of sshd using the new configuration

Create phabricator-ssh-hook.sh: Copy the template in phabricator/resources/sshd/phabricator-ssh-hook.sh to somewhere like /usr/libexec/phabricator-ssh-hook.sh` and edit it to have the correct settings.

# Update correct value of VCS-USER and Phabricator root
VCSUSER="git"
ROOT="/opt/taskman/phabricator"

Make it owned by root and restrict editing;

sudo chown root /usr/libexec/phabricator-ssh-hook.sh
sudo chmod 755 /usr/libexec/phabricator-ssh-hook.sh

Create sshd_config for Phabricator: Copy the template in /phabricator/resources/sshd/sshd_config.phabricator.example to somewhere like /etc/ssh/sshd_phabricator.

Start Phabricator SSHD

sudo /usr/sbin/sshd -f /etc/ssh/sshd_phabricator`

IF you did everything correctly, you should be able to run this;

echo {} | ssh git@phabricator.yourcompany.com conduit conduit.ping

... and get a response like this;

{"result":"orbital","error_code":null,"error_info":null}

For troubleshooting, please refer to diffusion setup notes.

You can add the following script to /etc/init.d/sshdphab to have Phabricator SSHD run on start-up;

#! /bin/sh

### BEGIN INIT INFO
# Provides:             sshdphab
# Required-Start:       $remote_fs $syslog
# Required-Stop:        $remote_fs $syslog
# Default-Start:        2 3 4 5
# Default-Stop:
# Short-Description:    OpenBSD Secure Shell server - sshdphab
### END INIT INFO

set -e

# /etc/init.d/sshphab: start and stop the OpenBSD "secure shell(tm)" daemon - sshdphab

test -x /usr/sbin/sshdphab || exit 0
( /usr/sbin/sshdphab -\? 2>&1 | grep -q OpenSSH ) 2>/dev/null || exit 0

umask 022

if test -f /etc/default/ssh; then
    . /etc/default/ssh
fi

. /lib/lsb/init-functions

SSHD_CONFIG="/etc/ssh/sshd_phabricator"

SSHD_OPTS="$SSHD_OPTS -f $SSHD_CONFIG"

if [ -n "$2" ]; then
    SSHD_OPTS="$SSHD_OPTS $2"
fi

# Are we running from init?
run_by_init() {
    ([ "$previous" ] && [ "$runlevel" ]) || [ "$runlevel" = S ]
}

check_for_upstart() {
    return
    if init_is_upstart; then
        exit $1
    fi
}

check_for_no_start() {
    # forget it if we're trying to start, and /etc/ssh/sshdphab_not_to_be_run exists
    if [ -e /etc/ssh/sshdphab_not_to_be_run ]; then
        if [ "$1" = log_end_msg ]; then
            log_end_msg 0 || true
        fi
        if ! run_by_init; then
            log_action_msg "OpenBSD Secure Shell server not in use (/etc/ssh/sshdphab_not_to_be_run)" || true
        fi
        exit 0
    fi
}

check_dev_null() {
    if [ ! -c /dev/null ]; then
        if [ "$1" = log_end_msg ]; then
            log_end_msg 1 || true
        fi
        if ! run_by_init; then
            log_action_msg "/dev/null is not a character device!" || true
        fi
        exit 1
    fi
}

check_privsep_dir() {
    # Create the PrivSep empty dir if necessary
            log_end_msg 0 || true
        else
            log_end_msg 1 || true
        fi
        ;;

  try-restart)
        check_for_upstart 1
        check_privsep_dir
        check_config
        log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshdphab" || true
        RET=0
        start-stop-daemon --stop --quiet --retry 30 --pidfile /var/run/sshd-phabricator.pid || RET="$?"
        case $RET in
            0)
                # old daemon stopped
                check_for_no_start log_end_msg
                check_dev_null log_end_msg
                if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sshd-phabricator.pid --exec /usr/sbin/sshdphab -- $SSHD_OPTS; then
                    log_end_msg 0 || true
                else
                    log_end_msg 1 || true
                fi
                ;;
            1)
                # daemon not running
                log_progress_msg "(not running)" || true
                log_end_msg 0 || true
                ;;
            *)
                # failed to stop
                log_progress_msg "(failed to stop)" || true
                log_end_msg 1 || true
                ;;
        esac
        ;;

  status)
        check_for_upstart 1
        status_of_proc -p /var/run/sshd-phabricator.pid /usr/sbin/sshdphab sshdphab && exit 0 || exit $?
        ;;

  *)
        log_action_msg "Usage: /etc/init.d/sshphab {start|stop|reload|force-reload|restart|try-restart|status}" || true
        exit 1
esac

exit 0

You should now be able to access your instance over ssh on port 222 for normal login and administrative purposes. Phabricator SSHD runs on port 22 to handle authentication and command execution.

Head on to the Diffusion application to create a hosted repository. The interface to create a new hosted repository is fairly intuitive and you should face no issues as such. Refer to Diffusion Docs to understand the process.

Do let me know if you are facing any issue or are stuck at any configuration step.

Hope this helps.

\m/

Vinayak Mishra

Vinayak Mishra, a Cricket Enthusiast with keen interest in web and mobile applications. Hails from Mithila, Nepal, married to Rani and dad to his bundle of joy Bunu. Lives in New Delhi, India. You can follow him on Twitter or check out his website, vnykmshr.com.