.. _tutorial-install-debusine:

====================================
Install your first debusine instance
====================================

In this tutorial, you will install your first debusine server and your
first debusine worker. To provide a reproducible experience in a well
defined environment, you will install both in a dedicated virtual machine
running Debian 12 (bookworm).

.. note::

   We will use `incus <https://linuxcontainers.org/incus/>`_ to manage
   the virtual machine. Given that incus is an LXD fork, you might be able
   to easily translate the samples for LXD. If you are more familiar with
   other virtualization tools (libvirt and virt-manager, virtualbox,
   etc.), feel free to use those and to adapt the instructions.

Configure incus
---------------

If you have never used incus, you have to install it and configure it:

.. code-block:: console

   $ sudo apt install incus
   [...]
   Incus has been installed. You must run `sudo incus admin init` to
   perform the initial configuration of Incus.
   Be sure to add user(s) to either the 'incus-admin' group for full
   administrative access or the 'incus' group for restricted access,
   then have them logout and back in to properly setup their access.
   $ sudo incus admin init --auto

.. warning::

   Incus is very recent and is not present in any stable Debian releases.
   You can find the package in Debian Testing and Debian Unstable, and
   soon in bookworm-backports (backports for Debian 12). For the time
   being, you can also use the upstream packages from
   https://github.com/zabbly/incus.

.. note::

   On a headless server, especially if you use the upstream Incus
   repository, you can do a more minimal incus install with:

   .. code-block:: console

        $ sudo apt install --no-install-recommends incus

To make the system-wide incus daemon fully controllable by your user, run
this command:

.. code-block:: console

   $ sudo adduser $USER incus-admin
   info: Adding user `sample-user' to group `incus-admin' ...
   $ newgrp incus-admin

.. note::

   The `newgrp incus-admin` command starts a new shell where you
   immediately have the newly granted group. Otherwise you have to
   close your session and start a new one to get the new privilege.

Install the virtual machine
---------------------------

With incus, there's no installation involved, as we can simply rely
on the pre-built images provided by the linux containers project. So
you can instantiate and start a new virtual machine with this single
command:

.. code-block:: console

   $ incus launch images:debian/bookworm/cloud debusine --vm --device root,size=50GiB
   Creating debusine
   Starting debusine

From there, you can execute any command within the virtual machine
with ``incus execute debusine -- $COMMAND`` (replacing ``$COMMAND`` with
the command of your choice). You can thus easily start a shell inside the
virtual machine:

.. code-block:: console

   $ incus exec debusine -- bash
   root@debusine:~# cat /etc/debian_version
   12.4

.. warning::

   Note that you can only execute a command once the virtual machine has
   finished to boot (it can take up to a few tens of seconds). In the mean
   time, the above command might return an error (`Error: VM agent isn't
   currently running`).

All the commands in this tutorial that start with the ``root@debusine``
prompt are to be executed in such a shell inside the virtual machine.

In order to work properly, the debusine server needs to have a fully
qualified domain name and unfortunately Incus doesn't set one for us.
Let's fix this by granting the ``debusine.internal`` name on top of the
plain unqualified hostname (``debusine``):

.. code-block:: console

   root@debusine:~# sed -i -e "s/$HOSTNAME/debusine.internal &/" /etc/hosts
   root@debusine:~# hostname -f
   debusine.internal

Install the packages
--------------------

First you want to configure APT with debusine's upstream package
repository:

.. code-block:: console

   root@debusine:~# cat >/etc/apt/sources.list.d/debusine.list <<END
   deb [trusted=yes] https://deb.freexian.com/packages/debusine/ ./
   END
   root@debusine:~# apt update
   […]

Then you install a bunch of packages:

* the two packages for the debusine server and the worker
* some Debian tools that are required for the worker to be able to perform
  some useful tasks
* the postgresql database server
* the redis database server
* the nginx webserver

.. code-block:: console

   root@debusine:~# apt install debusine-server debusine-worker \
    postgresql redis nginx \
    sbuild autopkgtest lintian piuparts mmdebstrap qemu-system
   […]
   0 upgraded, 673 newly installed, 0 to remove and 0 not upgraded.
   Need to get 470 MB of archives.
   After this operation, 2232 MB of additional disk space will be used.
   Do you want to continue? [Y/n]
   […]

.. note::

   If you are also running docker on the same computer, you might
   discover at this point that the network is not functional inside the
   virtual machine. This is usually due to docker configuring restrictions
   in the local firewall when the service has to enable IPv4 forwarding.
   See the `incus documentation
   <https://linuxcontainers.org/incus/docs/main/howto/network_bridge_firewalld/#prevent-connectivity-issues-with-incus-and-docker>`__
   for possible solutions.

..
   We might want a "debusine-debian-worker" package that pulls all the
   important dependencies and that perform any system wide setup we might
   need.

Create and initialize the database
----------------------------------

Debusine needs a PostgreSQL database and you need to initialize it
with the proper tables for debusine:

.. code-block:: console

   root@debusine:~# sudo -u postgres createuser debusine-server
   could not change directory to "/root": Permission denied
   root@debusine:~# sudo -u postgres createdb --owner debusine-server debusine
   could not change directory to "/root": Permission denied
   root@debusine:~# sudo -u debusine-server debusine-admin migrate
   Operations to perform:
     Apply all migrations: admin, auth, contenttypes, db, sessions
   Running migrations:
     Applying contenttypes.0001_initial... OK
     […]
     Applying sessions.0001_initial... OK

At this point, the debusine server is functional but we haven't enabled
its web interface yet.

Configure the webserver
-----------------------

You will now configure the webserver:

.. code-block:: console

   root@debusine:~# rm -f /etc/nginx/sites-enabled/default
   root@debusine:~# cp /usr/share/doc/debusine-server/examples/nginx-vhost.conf \
     /etc/nginx/sites-enabled/debusine
   root@debusine:~# systemctl restart nginx

Test the access to the web interface
------------------------------------

Now it's time to ensure that you can open debusine's web interface.

The default configuration of the debusine server assumes that you will
access it through the fully qualified name obtained with ``hostname -f``
in the virtual machine.

On your machine, you can lookup the IPv4 address assigned to your virtual
machine and then associate it with the same hostname by creating an entry
in ``/etc/hosts`` and open your web browser on the corresponding URL:

.. code-block:: console

   $ DEBUSINE_HOSTNAME=$(incus exec debusine -- hostname -f)
   $ IPV4=$(incus list debusine -c 4 -f csv | awk '{print $1}')
   $ echo "$IPV4 $DEBUSINE_HOSTNAME" | sudo tee -a /etc/hosts
   10.178.127.31 debusine.internal
   $ xdg-open http://$DEBUSINE_HOSTNAME/

The debusine server is running:

.. image:: debusine-homepage.png

You notice a login button, but you don't know what credentials to enter.
Let's fix this. Go back in the server virtual machine and use the
``debusine-admin create_user USERNAME EMAIL`` command to create yourself
a user in the system:

.. code-block:: console

   root@debusine:~# sudo -u debusine-server debusine-admin create_user \
        myuser user@example.org
   I4X'JISFj7GhOvN1

The password that has been assigned to the newly created user is displayed
on standard output. Go back to the web browser, and try it out!

Configure the worker
--------------------

While the server part is now ready, the worker isn't yet. First step is to
configure the worker so that it connects to the server and make itself
available:

.. code-block:: console

   root@debusine:~# cp /usr/share/doc/debusine-worker/examples/config.ini \
        /etc/debusine/worker/
   root@debusine:~# sed -i -e "s/localhost/debusine.internal/" \
        /etc/debusine/worker/config.ini
   root@debusine:~# systemctl restart debusine-worker

.. note:: The sample configuration file uses ``http://localhost/api`` as
   the server URL and we change it to ``http://debusine.internal/api`` for
   consistency.

Finally, you approve the worker on the server side:

.. code-block:: console

   root@debusine:~# sudo -u debusine-server debusine-admin list_workers
   Name               Registered                        Connected    Token                                                             Enabled
   -----------------  --------------------------------  -----------  ----------------------------------------------------------------  ---------
   debusine-internal  2024-01-24T15:40:44.703488+00:00  -            6a37e2b73500ff1ac0dfad0c4ea462a72f19b69abe1338da188773aa83351b80  False

   Number of workers: 1
   root@debusine:~# sudo -u debusine-server debusine-admin manage_worker enable debusine-internal

The worker is now ready to process work requests. You can start to
experiment with debusine's features. For this, you can follow the
tutorial :ref:`tutorial-getting-started`.
