######################
Quickstart from source
######################
.. structured-tutorial:: source/tutorial.yaml
This guide provides instructions for running your own certificate authority by installing django-ca from
source. This method requires a lot of manual configuration and a lot of expert knowledge, but is a good choice
if you use an exotic system or other options do not work for you for some reason. If you're looking for a
faster and easier option, you might consider using :doc:`Docker Compose `.
.. NOTE::
This tutorial uses `structured-tutorials `_.
This means that the documentation you see here is rendered from a configuration file and can also be run
locally to verify correctness and completeness.
.. NOTE::
All commands below assume that you have a shell with superuser privileges.
This tutorial will give you a CA with
* A root and intermediate CA.
* A browsable admin interface, protected by TLS (using certificates signed by your CA).
* Certificate revocation using CRLs and OCSP.
* (Optional) ACMEv2 support (= get certificates using certbot).
************
Requirements
************
.. include:: /include/guide-requirements.rst
Required software
=================
To run **django-ca**, you need Python, a database and a web server (like NGINX or Apache).
Whenever this tutorial installs software, it assumes a Debian/Ubuntu based system. If you use a different
distribution, refer to their manuals for instructions. We assume that the APT cache is up to date and you have
some basics installed:
.. structured-tutorial-part:: apt-update
Install database
----------------
**django-ca** will not run without a `supported database
`_. This tutorial will show you how to use PostgreSQL
or MariaDB. To install either:
.. structured-tutorial-part:: install-db
Install cache
-------------
Using a distributed cache is highly recommended. This tutorial will show you how to use `Memcached
`_ or `Redis `_. To install either:
.. structured-tutorial-part:: install-cache
Install broker for Celery
-------------------------
Using `Celery `_ is optional but also highly recommended for performance and
security reasons. If you use Celery, the web server does not need to use the private key (or the HSM
storing the private key). If you want to split the setup across multiple hosts, only those running Celery
need to be able to sign data (certificates, CRLs, ...).
For Celery, you'll need a broker. Redis can double as a broker, but you can use a variety
of `other systems `_. This
tutorial will show you how to use Redis or `RabbitMQ `_.
Redis was already installed above, as it can double as a cache. If you want to use RabbitMQ instead:
.. structured-tutorial-part:: install-broker
Install :command:`uv`
---------------------
Additionally, this guide uses :command:`uv` to set up a Python Virtual Environment. Please refer to the `installation
instructions `_ for how to install it. On most Linux
systems you can simply run:
.. structured-tutorial-part:: install-uv
Later in the tutorial, we will let :command:`uv` manage python versions. This allows you to use the newest
Python version regardless of what your distribution (version) offers. :command:`uv` will install Python
versions in ``/root/`` by default, which then can not be accessed by Gunicorn and Celery (which run with a
lower-privileged user):
.. structured-tutorial-part:: install-uv-python
Environment
===========
To make the guide less error-prone, we export the domain name for your certificate authority to
``$HOSTNAME``. In all commands below assume that you have set the environment variable like this:
.. structured-tutorial-part:: set-hostname
************
Installation
************
With this guide, you will install **django-ca** to ``/opt/django-ca/``, with your local configuration residing
in ``/etc/django-ca/``.
Start by creating a system user and some essential directories:
.. structured-tutorial-part:: prepare-host
.. _from-source-create-database:
Create database
===============
Create a database and make sure to use a randomly generated password. You will need to again when
configuring django-ca:
.. structured-tutorial-part:: setup-database
Setup broker
============
If you use Redis as a broker, you can use it out of the box. For RabbitMQ, a little configuration is
necessary:
.. structured-tutorial-part:: setup-broker
.. _from-source-add-systemd-services:
Get the source
==============
You can clone django-ca from git or download an archive `from GitHub
`_. In the example below, we extract the source to
``/opt/django-ca/src/`` and create a symlink without a version so that you can roll back to old versions
during an update:
.. structured-tutorial-part:: install-source
Create a virtualenv
===================
We use `uv `_ to create and manage the Python environment. By default, ``uv`` will
manage both a local Python installation and `virtualenv `_ for
you, but you can instruct it to use the system Python installation (try ``uv sync --help``).
.. structured-tutorial-part:: create-virtualenv
Depending on your needs you might also want to disable other extras as well. This is a list of all currently
available extras:
.. include:: /include/pip-extras.rst
You can of course use a regular `virtualenv` and ``pip`` to manage your environment as well. For example:
.. code-block:: console
root@host:~# cd /opt/django-ca/src/django-ca/
root@host:/opt/django-ca/src/django-ca/# python3 -m venv .venv/
root@host:/opt/django-ca/src/django-ca/# .venv/bin/pip install -U \
> pip setuptools wheel
root@host:/opt/django-ca/src/django-ca/# .venv/bin/pip install -U \
> -e /opt/django-ca/src/django-ca[api,hsm,postgres,celery,redis,yaml]
Add SystemD services
====================
SystemD services are included with **django-ca**. You need to add three services, one for the Gunicorn
application server (``django-ca``), one for the Celery task worker (``django-ca-celery``) and one for the
Celery task scheduler (``django-ca-celerybeat``):
.. structured-tutorial-part:: add-systemd-services
Note that the services will not yet start due to :ref:`missing configuration `.
If you use an installation directory other then ``/opt/django-ca``, set ``INSTALL_BASE`` in
:file:`/etc/systemd/systemd-local.conf` (see :ref:`systemd-configuration`) *and* add a SystemD override for
``WorkingDirectory=``.
.. _from-source-configuration:
*************
Configuration
*************
**django-ca** will load configuration from all ``*.yaml`` files in ``/etc/django-ca/`` in alphabetical order.
These files can contain any `Django setting `_, `Celery
setting `_ or :doc:`django-ca setting
`.
If you (mostly) followed the above examples, you can symlink :file:`conf/source/00-settings.yaml` to
``/etc/django-ca`` and just override a few settings in :file:`/etc/django-ca/10-localsettings.yaml`. To create
the symlink:
.. structured-tutorial-part:: add-basic-settings
And then simply create a minimal :file:`/etc/django-ca/10-localsettings.yaml` - but you can override any other
setting here as well:
.. structured-tutorial-part:: add-required-settings
Please see :doc:`/settings` for a list of available settings.
Configure the database
======================
Configure database access in a dedicated configuration file. Use the ``PASSWORD`` you used when you
:ref:`created a database `:
.. structured-tutorial-part:: add-db-settings
Configure the cache
===================
Configure the cache in a dedicated configuration file:
.. structured-tutorial-part:: add-cache-settings
Configure broker
================
Configure the Broker used by Celery in a dedicated configuration file:
.. structured-tutorial-part:: add-broker-settings
Configure Gunicorn
==================
Gunicorn requires a dedicated configuration file. Minimal default settings are included in django-ca:
.. structured-tutorial-part:: add-gunicorn-config
If you need different `Gunicorn settings `_, you'll have to copy
and modify the file instead.
.. _systemd-configuration:
Secure configuration
====================
Since the configuration contains sensitive information (database password, etc), make sure it is not
world-readable:
.. structured-tutorial-part:: secure-configuration
SystemD configuration
=====================
When you :ref:`added SystemD services ` you also created a symlink for
:file:`/etc/django-ca/systemd.conf`. If settings there do not suit you, you can override them in
:file:`/etc/django-ca/systemd-local.conf`.
.. _from-source-add-manage-py-shortcut:
Add manage.py shortcut
======================
As optional convenience, you can create a symlink to a small wrapper script that allows you to easily run
``manage.py`` commands. In the examples below the guide assumes you created this symlink at
:file:`/usr/local/bin/django-ca`, but of course you can name the symlink anything you like:
.. structured-tutorial-part:: add-shortcut
Setup Database and static files
===============================
Populate the database and setup the static files directory:
.. structured-tutorial-part:: run-initial-manage-commands
The ``collectstatic`` command needs to run as root.
*****
Start
*****
You can now finally start the Gunicorn application server and the Celery worker (omit ``django-ca`` service if
you do not intend to run a web server):
.. structured-tutorial-part:: start
Create admin user and set up CAs
================================
Because we :ref:`created a shortcut above ` above, we can use
``django-ca`` to use **django-ca** from the command line.
.. jinja:: manage-from-source
:file: /include/create-user.rst.jinja
Setup NGINX
===========
A web server is required for the admin interface, certificate revocation status via OCSP or CRLs and ACMEv2
(the protocol used by Let's Encrypt/certbot integration).
.. WARNING::
While theoretically possible, do not use a local CAs ACMEv2 interface to get certificates. Any
misconfiguration might make it impossible to retrieve a certificate!
In this setup, we'll create certificates using the CA we created above. If you want to use Let's Encrypt
certificates instead, you can have a look at our :doc:`/quickstart/docker_compose` for an example.
First, you need to install NGINX:
.. structured-tutorial-part:: install-nginx
Delete the default hostname to minimize the setup:
.. structured-tutorial-part:: nginx-basic-setup
Create a private/public key pair for NGINX to use - you could also sign the certificate using a 3rd-party
certificate authority of course:
.. structured-tutorial-part:: create-tls-key
Create DH parameters:
.. structured-tutorial-part:: create-dh-params
**django-ca** includes a template for :manpage:`envsubst(1)` that you can use. The template assumes that you
have set ``$HOSTNAME``:
.. structured-tutorial-part:: create-nginx-config
.. jinja:: guide-source-where-to-go
:file: /include/guide-where-to-go.rst.jinja
:header_update_levels:
******
Update
******
.. include:: /include/update_intro.rst
Downloading the new release works the same as before, but you have to remove the old symlink before creating
the new one:
.. jinja::
:file: /include/guide-update-source.rst.jinja
Create a new virtual environment (with updated dependencies) using ``uv``:
.. code-block:: console
root@host:~# cd /opt/django-ca/src/django-ca/
root@host:/opt/django-ca/src/django-ca/# uv sync --no-default-groups \
> --all-extras --no-extra postgres
Update the database schema and static files:
.. code-block:: console
root@host:~# django-ca migrate
root@host:~# FORCE_USER=root django-ca collectstatic
Restart services:
.. code-block:: console
root@host:~# systemctl restart django-ca django-ca-celery django-ca-celerybeat
Update the NGINX configuration:
.. code-block:: console
root@host:~# envsubst < /opt/django-ca/src/django-ca/nginx/source.template \
> < /opt/django-ca/src/django-ca/nginx/source.template \
> > /etc/nginx/sites-available/django-ca.conf
root@host:~# nginx -t
root@host:~# systemctl restart nginx
*********
Uninstall
*********
To completely uninstall **django-ca**, stop related services and remove files that where created:
.. code-block:: console
root@host:~# systemctl stop django-ca django-ca-celery django-ca-celerybeat
root@host:~# systemctl disable django-ca django-ca-celery django-ca-celerybeat
root@host:~# rm -f /etc/nginx/sites-*/django-ca.conf
root@host:~# rm -f /var/log/nginx/$HOSTNAME*.log
root@host:~# rm -f /usr/local/bin/django-ca
root@host:~# rm -rf /etc/django-ca/ /opt/django-ca/ /var/log/django-ca
root@host:~# rm -f /etc/ssl/$HOSTNAME.{key,pem}
Restart NGINX so that it no longer knows about the configurations:
.. code-block:: console
root@host:~# systemctl restart nginx
Remove the system user:
.. code-block:: console
root@host:~# deluser django-ca
Drop the PostgreSQL database:
.. code-block:: console
root@host:~# sudo -u postgres psql
postgres=# DROP DATABASE django_ca;
DROP DATABASE
postgres=# DROP USER django_ca;
DROP ROLE