Finish building Postgres support (#133)

This includes:
 - Building a Docker image for Postgres as well as SQLite
 - Fuller instructions for usage of the package, including the Postgres builds.

A few related things changed here:
 - `.env` is not used anymore -- the defaults in the Dockerfiles are
   sufficient
 - The Rust version in the Dockerfiles is increased to match the MSRV,
   and with it the Alpine version bumped to one built with that Rust
   version.
 - Cargo dependencies on native-tls and openssl updated to include only
   the `vendored` feature, so as not to require a system openssl
   installation.
 - Two GitHub jobs are set up, to build the two different Docker images
 - The documentation incorrectly suggested using `DELETE .. CASCADE` to
   delete clients. This syntax does not exist, as the cascading delete
   is configured in the schema.
This commit is contained in:
Dustin J. Mitchell
2025-07-29 21:52:33 -04:00
committed by GitHub
parent 820aaf363c
commit ab6df362bf
22 changed files with 401 additions and 201 deletions

View File

@ -0,0 +1,49 @@
# Binaries
Taskchampion-sync-server is a single binary that serves HTTP requests on a TCP
port. The server does not implement TLS; for public deployments, the
recommendation is to use a reverse proxy such as Nginx, haproxy, or Apache
httpd.
One binary is provided for each storage backend:
- `taskchampion-sync-server` (SQLite)
- `taskchampion-sync-server-postgres` (Postgres)
### Running the Binary
The server is configured with command-line options or environment variables.
See the `--help` output for full details.
For the SQLite binary, the `--data-dir` option or `DATA_DIR` environment
variable specifies where the server should store its data. For the Postgres
binary, the `--connection` option or `CONNECTION` environment variable
specifies the connection information, in the form of a [LibPQ-style connection
URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS).
The remaining options are common to all binaries.
The `--listen` option specifies the interface and port the server listens on.
It must contain an IP-Address or a DNS name and a port number. This option is
mandatory, but can be repeated to specify multiple interfaces or ports. This
value can be specified in environment variable `LISTEN`, as a comma-separated
list of values.
By default, the server will allow all clients and create them in the database
on first contact. There are two ways to limit the clients the server will
interact with:
- To limit the accepted client IDs, specify them in the environment variable
`CLIENT_ID`, as a comma-separated list of UUIDs. Client IDs can be specified
with `--allow-client-id`, but this should not be used on shared systems, as
command line arguments are visible to all users on the system. This convenient
option is suitable for personal and small-scale deployments.
- To disable the automatic creation of clients, use the `--no-create-clients`
flag or the `CREATE_CLIENTS=false` environment variable. You are now
responsible for creating clients in the database manually, so this option is
more suitable for large scale deployments. See [Integration](../integration.md)
for more information on such deployments.
The server only logs errors by default. To add additional logging output, set
environment variable `RUST_LOG` to `info` to get a log message for every
request, or to `debug` to get more verbose debugging output.

View File

@ -0,0 +1,43 @@
# Docker Compose
The
[`docker-compose.yml`](https://raw.githubusercontent.com/GothenburgBitFactory/taskchampion-sync-server/refs/tags/v0.6.1/docker-compose.yml)
file in this repository is sufficient to run taskchampion-sync-server,
including setting up TLS certificates using Lets Encrypt, thanks to
[Caddy](https://caddyserver.com/). This setup uses the SQLite backend, which is
adequate for one or a few clients.
You will need a server with ports 80 and 443 open to the Internet and with a
fixed, publicly-resolvable hostname. These ports must be available both to your
Taskwarrior clients and to the Lets Encrypt servers.
On that server, download `docker-compose.yml` from the link above (it is pinned
to the latest release) into the current directory. Then run
```sh
TASKCHAMPION_SYNC_SERVER_HOSTNAME=taskwarrior.example.com \
TASKCHAMPION_SYNC_SERVER_CLIENT_ID=your-client-id \
docker compose up
```
The `TASKCHAMPION_SYNC_SERVER_CLIENT_ID` limits the server to the given client
ID; omit it to allow all client IDs. You may specify multiple client IDs
separated by commas.
It can take a few minutes to obtain the certificate; the caddy container will
log a message "certificate obtained successfully" when this is complete, or
error messages if the process fails. Once this process is complete, configure
your `.taskrc`'s to point to the server:
```none
sync.server.url=https://taskwarrior.example.com
sync.server.client_id=your-client-id
sync.encryption_secret=your-encryption-secret
```
The docker-compose images store data in a docker volume named
`taskchampion-sync-server_data`. This volume contains all of the task data, as
well as the TLS certificate information. It will persist over restarts, in a
typical Docker installation. The docker containers will start automatically
when the Docker dameon starts. See the docker-compose documentation for more
information.

View File

@ -0,0 +1,57 @@
# Docker Images
Every release of the server generates Docker images. One image is produced for
each storage backend:
- `ghcr.io/gothenburgbitfactory/taskchampion-sync-server` (SQLite)
- `ghcr.io/gothenburgbitfactory/taskchampion-sync-server-postgres` (Postgres)
The image tags include `latest` for the latest release, and both minor and
patch versions, e.g., `0.5` and `0.5.1`.
## Running the Image
At startup, each image applies some default values and runs the relevant binary
directly. Configuration is typically by environment variables, all of which are
documented in the `--help` output of the binaries. These include
- `RUST_LOG` - log level, one of `trace`, `debug`, `info`, `warn` and `error`.
- `DATA_DIR` (SQLite only; default `/var/lib/taskchampion-sync-server/data`) -
directory for the synced data.
- `CONNECTION` (Postgres only) - Postgres connection information, in the form
of a [LibPQ-style connection
URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS).
- `LISTEN` (default `0.0.0.0:8080`) - address and port on which to listen for
HTTP requests.
- `CLIENT_ID` - comma-separated list of client IDs that will be allowed, or
empty to allow all clients.
- `CREATE_CLIENTS` (default `true`) - if true, automatically create clients on
first sync. If this is set to false, it is up to you to initialize clients in
the DB.
### Example
```shell
docker run -d \
--name=taskchampion-sync-server \
-p 8080:8080 \
-e RUST_LOG=debug \
-v /data/taskchampion-sync-server:/var/lib/taskchampion-sync-server/data \
taskchampion-sync-server
```
### Image-Specific Setup
The SQLite image is configured with `VOLUME
/var/lib/taskchampion-sync-server/data`, persisting the task data in an
anonymous Docker volume. It is recommended to put this on a named volume, or
persistent storage in an environment like Kubernetes, so that it is not
accidentally deleted.
The Postgres image does not automatically create its database schema. See the
[integration section](../integration/pre-built.md) for more detail. This
implementation is tested with Postgres version 17 but should work with any
recent version.
Note that the Docker images do not implement TLS. The expectation is that
another component, such as a Kubernetes ingress, will terminate the TLS
connection and proxy HTTP traffic to the taskchampion-sync-server container.