# Running in Production CritterChat uses nginx for SSL termination as well as a static resources server for production instances. While it is possible to run an instance without nginx it is not recommended. Offloading static assets takes load off of the server itself so that it can concentrate on dynamic requests from clients. Additionally, handling SSL termination is best left to a production-grade reverse proxy such as nginx. There are two options for running a production instance: bare metal and within a docker container. With bare metal you manage the Python virtual environment, dependencies, application service and database instance yourself. With a docker container most of these are handled for you and you are solely responsible for the container itself and the nginx reverse proxy siting in front of it. Both are supported options for production hosting. CritterChat prefers to use MySQL as the database for production instances. You can choose to run with SQLite as your database instead. However, SQLite integration is intended for fast local development. If you anticipate that your production instance will remain fairly small then SQLite could be a reasonable option for you. The included docker container only supports talking to a MySQL instance, so you will need to either host on bare metal or modify the config and docker files in `critterchat-docker/` to operate with SQLite instead. # Bare Metal Hosting In the `example/` directory you'll find a systemd service file for the backend as well as an nginx configuration file for the nginx proxy portion. Both are meant to be customized for your domain and certs as well as where you ultimately decide to deploy CritterChat for a production instance. For SSL certificates, I recommend using `certbot` which is a CLI interface to the Let's Encrypt project. If you want to purchase certificates for use with SSL you can. ## Initial Setup Initial setup is fairly straightforward. Pick a directory that you will deploy to, create it, and make sure that it is owned by the user that will execute the server. If you are using nginx as your reverse proxy and SSL termination then also make sure that the directory is readable by the user that nginx uses since it will serve static assets out of this directory as well. Copy `example/baremetal.mysql.config.yaml` or `example/baremetal.sqlite.config.yaml` (depending on your database of choice) to the directory you've just created and make sure that you customize it for your installation. Create an attachments directory under the installation directory and again make sure that it is owned by the server user and readable by the nginx user. Review your config.yaml to ensure that you've modified everything you need to. Ensure that the `database` section points at your production database. Make sure that the `cookie_key`, `password_key` and `attachment_key` are all set to a random string of sufficient length. I recommend keeping them all different and using a random generator that can give you a string of at least 48 characters. Note that it is important to select good random values now and not change them in the future. Changing these values in a production instance can have undesirable effects. If you change the `cookie_key` in a production instance, all sessions will be logged out. If you change `password_key` in production, all passwords will be invalidated and you will have to manually change all of them. If you change `attachment_key` in a production instance, all existing attachments will 404. So, choose good values when setting up your instance and do not modify them. Make sure you rename your instance to what you want to call it and edit the instance info text file to include any rules or code of conduct. Finally, configure the attachment system. Right now, only local storage is supported, so leave it set to local and leave the prefix as-is. Update the directory to the absolute path of the attachment directory you created above. Now that your config is updated, create a Python virtual environment for the production installation. I recommend sticking it in the deployed folder under a directory called `venv` or similar. It doesn't matter where it is but you'll want to keep organized. Once you've created that virtual environment you'll be activating it every time you want to install updates. For now, activate it so that you can install CritterChat into it either from a checkout of the repo or from PyPI. If you're developing or customizing CritterChat, you'll want to install out of your repo. If you're just running a released version of CritterChat you can install directly from PyPI. If you're installing from your repo, first ensure that you've built the frontend for production as the repo does not ship with pre-built frontend files. You can do that by going into the `frontend/` directory and running `npm run clean && npm run build`. Once that's done, install CritterChat into your virtual environment by going into the `backend/` directory and first running `python3 -m pip install --upgrade pip -r requirements.txt` followed by `python3 -m pip install .`. This will install all dependencies, the static resources and the code itself into your virtual enviornment. If you're installing from PyPI you can skip the build steps since the package ships with pre-built frontend files. Install the package into your virtual environment by running `python3 -m pip install --upgrade pip critterchat`. This will install all dependencies, the static resources and thecode itself into your virtual environment. Now that the software is actually installed, you'll want to seed the database which is presumably empty. In the same terminal that you have the activated virtual environment that you just installed into, run the following command: ``` python3 -m critterchat.manage --config database create ``` Now, you can test that the software is running by executing the following command and seeing that it does not spit out any error messages or crashes: ``` python3 -m critterchat --config ``` Now, make a copy of the `example/critterchat.service` file and place it into `/etc/systemd/system`. Edit the user and group to match the user and group of the production user you will run the backend service as. Edit the environment line for the virtual environment to point at the absolute path of the virutual environment you created and installed into. Edit the environment line for the config to point at the absolute path of the production config you just edited. Edit the environment line for the port to listen on to an available port above 2048 of your choosing. Now, run `systemctl daemon-reload` to let systemd recognize the new service you just created, and then `systemctl enable critterchat` to enable auto-starting on reboot, and finally `systemctl start critterchat` to start the service. You can use `journalctl -u critterchat` to see logs and verify that it started successfully. Finally, we will set up the nginx proxy which will actually serve the production traffic. Make a copy of the `example/critterchat-nginx.conf` file and place it into `/etc/nginx/sites-available`. Edit the `server_name` line everywhere it appears and change it to the domain or subdomain that you are running this under. Don't forget to edit the `return` line in the top portion of the file to auto-promote non-SSL traffic to SSL. Update the SSL certificate lines near the top and in the location directives to point at your SSL certificates you obtained through `certbot` or through purchasing certificates. Update all `proxy_pass` lines and ensure that the port listed there is the same one that you chose in your systemd service configuration above. Update the `alias` line under the `/attachments` location to point to the same absolute path you configured for your attachments in your config.yaml. Update the `alias` line under the `/static` location prefix to the same absolute path you created for your venv. Take careful note to only edit the portion before the `/lib` as the rest of that directory is where installing the backend will put static resources. Now, once this is done, symlink the file you just created into `/etc/nginx/sites-enabled` to activate this and restart nginx using `systemctl restart nginx`. Once the restart is complete you should have a production instance of CritterChat running on the domain you've chosen! ## Running Without nginx The above walkthrough as well as all of the baremetal examples assumes you're going to use nginx as your reverse proxy and SSL termination. If you do not wish to set this up and want to instead use the built-in SSL handler and asset serving code you can but note that nginx will always be more performant than pure Python. You can see the configuration options available to you by running the following command while your production virtual environment is active: ``` python3 -m critterchat --config --help ``` Specifically, you'll want to care about the `--port`, `--nginx-proxy`, `--cert` and `--cert-key` options. It's recommended to still use the `example/critterchat.service` file as a starting point but you'll need to make changes to the `ExecStart` line. For the listen port, you'll need to set this to 443 because CritterChat will be handling SSL directly from client requests. You'll need to get rid of the `--nginx-proxy` option since you aren't using an nginx proxy. Failing to remove this could lead you to being vulnerable to IP spoofing in logs. Next, you'll want to provide the SSL cert files that you obtained from Let's Encrypt or purchasing a certificate. Pass the full path to your certificate fullchain file to `--cert` and the full path to your certificate private key file to `--cert-key`. ## Running Without systemd The above walkthrough as well as all of the baremetal examples assumes you will be creating a virtual environment where you will install CritterChat into which is then managed by systemd. If you do not wish to set this up and instead want to manage CritterChat in some other way you can install CritterChat into your local user's system path for direct executing using [pipx](https://pipx.pypa.io/stable/). Run `pipx install critterchat` to do so, at which point the utility `critterchat` will be available in your system path as a stand-in for `python3 -m critterchat`, and `critterchat-manage` will be available in your system path as a stand-in for `python3 -m critterchat.manage`. Both of these utilities behave identical to their virtual environment counterparts which means you can use them with MySQL or SQLite as well as with or without nginx. If you do not want to set any dependencies up save for ffmpeg which is a simple install you can run CritterChat from a pipx installation with SQLite and built-in SSL termination. Note that when you're running pipx-managed CritterChat, pipx is responsible for updates as well. To update your CritterChat instance, stop the running program and then run `pipx upgrade critterchat`. Don't forget to execute database migrations before restarting by running the following: ``` critterchat-manage --config database upgrade ``` ## Administration Most of the administration for the server can be done in the CLI. At some point I would like to be able to administer through the web interface as well but outside of some basics this has not been implemented yet. The main administration interface can be found by activating the production virtual environment and then running the following command: ``` python3 -m critterchat.manage --help ``` This includes a bunch of stuff for adding and removing custom emojis, adding users, activating and deactivating existing users, changing a user's password, generating a password reset link for a user, creating an invite link to the instance, creating public rooms, and managing the auto-join setting for public rooms. If you are using one or more Mastodon instances as authentication providers it also provides commands for registering against those instances and verifying things work. In the future it will include a host of other helpful utilities. At the moment the software defaults to allowing open signups but leaves users waiting to be activated. You can find users to activate by running the following command: ``` python3 -m critterchat.manage --config user list ``` You can then activate them using a similar command: ``` python3 -m critterchat.manage --config user activate -u ``` Right now there are virtually no moderator tools. If somebody gets too unruly or spicy, you can deactivate their account using the following command. Note that if you have set your account as an administrator you can deactivate their account by clicking their profile and clicking the "deactivate user" button. Additionally, if you designate a room as moderated and one or more moderators for a given public room they can mute the user by clicking their profile and clicking the "mute user" button. Muting a user will mark them as inactive in the room and stop them from messaging or reacting to messages. Deactivating a user will log them out of all interfaces they're logged in on and prevent them from logging back in again while also marking them inactive in all rooms they are in. ``` python3 -m critterchat.manage --config user deactivate -u ``` For more in-depth documentation of administration features please see [ADMINISTRATION.md](ADMINISTRATION.md). ## Upgrading from Repo Once you've got everything installed, if you want to apply updates that you've pulled from this repository, you can do so with the following steps. If you are installing from a repository, first actually pull the changes by refreshing your copy of the repository. Go into the `frontend/` directory and make sure you've built a new production bundle by running `npm run clean && npm run build`. Then, activate the virtual environment you created for the production instance. Now, stop the running server by executing `systemctl stop critterchat`. Now, in the `backend/` directory, run `python3 -m pip install --upgrade pip -r requirements.txt` followed by `python3 -m pip install --upgrade .` to upgrade dependencies and install the new version of CritterChat. Then run to following command to perform any schema migrations that are present in the newly installed code: ``` python3 -m critterchat.manage --config database upgrade ``` Finally, once all those steps are done, re-start the backend service with `systemctl start critterchat`. If all went according to plan you should have the new version running on your instance. Users that are currently logged in should get a new update notification banner and you can refresh the page to load the new version. Note that it is safe to run this while chatters are connected. While the upgrade is in progress they will be blocked from sending new messages and will automatically reconnect once the upgrade is successful. As a reminder, you can check the server logs for the upgraded instance by running `journalctl -u critterchat`. An example script that automates the entire upgrade process is available for you to modify under `example/update-from-repo.sh`. Be sure to customize it to your installation. ## Upgrading from PyPI If you've installed from PyPI instead of from a repo, the following simpler steps can be used to upgrade your production instance. First, stop the running server by executing `systemctl stop critterchat`. Now, activate the virtual environment you created for the production instance. Now, upgrade CritterChat by running `python3 -m pip install --upgrade pip critterchat` which will take care of all dependencies as well as the pre-built frontend files. Then, run the following command to perform any schema migrations that are present in the newly installed code: ``` python3 -m critterchat.manage --config database upgrade ``` Finally, once all those steps are done, re-start the backend service with `systemctl start critterchat`. As a reminder, you can check the server logs for the upgraded instance by running `journalctl -u critterchat`. An example script that automates the entire upgrade process is available for you to modify under `example/update-from-pypi.sh`. Be sure to customize it to your installation. # Docker Hosting All of the files necessary for hosting a production instance with docker can be found in the `critterchat-docker/` folder at the root of the repository. This includes a default config file that will connect to the MySQL instance managed by docker as well as the `Dockerfile` and `docker-compose.yml` files. ## Getting Started To launch the default settings, simply clone the repo and navigate to `critterchat-docker/`, then run: ``` docker compose up -d ``` to launch the app. This uses the config in the `critterchat-docker/` folder called `docker.config.yaml` and provides bind mounts for the mysql database as well as the attachments folder. After making any changes to the configuration, run: ``` docker compose restart ``` to reload the instance and load the new settings. ## Administration Administration tools and other CLI interfaces can be accessed using: ``` docker exec -it CritterChat /bin/sh ``` which will drop you to a shell inside the container. Navigate to `/app/backend/` where you can run the following command to talk to the management CLI: ``` python3 -m critterchat.manage --config config.yaml --help ``` ## Upgrading This has not been tested thoroughly, but should not cause any data loss since the database and attachments are kept in a bind mount. In theory it should be as simple as: ``` docker compose down git pull docker image rm critterchat-docker-backend:latest docker compose up -d ``` to pull the new code and relaunch it.