Merge pull request 'Alpine based Docker image' (#152) from Weasy666/conduit:master into master

Reviewed-on: https://git.koesters.xyz/timo/conduit/pulls/152
Reviewed-by: Timo Kösters <timo@koesters.xyz>
next
Timo Kösters 2020-08-12 21:42:58 +02:00
commit 4b3d6e736f
8 changed files with 434 additions and 3 deletions

27
.dockerignore Normal file
View File

@ -0,0 +1,27 @@
# Local build and dev artifacts
target
sytest
# Docker files
Dockerfile*
docker-compose*
# IDE files
.vscode
.idea
*.iml
# Git folder
.git
.gitea
# Dot files
.env
.gitignore
# Toml files
rustfmt.toml
Rocket-example.toml
# Documentation
*.md

100
DEPLOY_FROM_SOURCE.md Normal file
View File

@ -0,0 +1,100 @@
# Deploy from source
## Prerequisites
Make sure you have `libssl-dev` and `pkg-config` installed and the [rust toolchain](https://rustup.rs) is available on at least on user.
## Install Conduit
```bash
$ sudo useradd -m conduit
$ sudo -u conduit cargo install --git "https://git.koesters.xyz/timo/conduit.git"
```
## Setup systemd service
In this guide, we set up a systemd service for Conduit, so it's easy to start, stop Conduit and set it to autostart when your server reboots. Paste the default systemd service below and configure it to fit your setup (in /etc/systemd/system/conduit.service).
```systemd
[Unit]
Description=Conduit
After=network.target
[Service]
Environment="ROCKET_SERVER_NAME=conduit.rs" # EDIT THIS
Environment="ROCKET_PORT=14004" # Reverse proxy port
#Environment="ROCKET_REGISTRATION_DISABLED=true"
#Environment="ROCKET_LOG=normal" # Detailed logging
Environment="ROCKET_ENV=production"
User=conduit
Group=conduit
Type=simple
Restart=always
ExecStart=/home/conduit/.cargo/bin/conduit
[Install]
WantedBy=multi-user.target
```
Finally, run
```bash
$ sudo systemctl daemon-reload
```
## Setup Reverse Proxy
This depends on whether you use Apache, Nginx or something else. For Apache it looks like this (in /etc/apache2/sites-enabled/050-conduit.conf):
```
<VirtualHost *:443>
ServerName conduit.koesters.xyz # EDIT THIS
AllowEncodedSlashes NoDecode
ServerAlias conduit.koesters.xyz # EDIT THIS
ProxyPreserveHost On
ProxyRequests off
AllowEncodedSlashes NoDecode
ProxyPass / http://localhost:14004/ nocanon
ProxyPassReverse / http://localhost:14004/ nocanon
Include /etc/letsencrypt/options-ssl-apache.conf
# EDIT THESE:
SSLCertificateFile /etc/letsencrypt/live/conduit.koesters.xyz/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/conduit.koesters.xyz/privkey.pem
</VirtualHost>
```
Then run
```bash
$ sudo systemctl reload apache2
```
## SSL Certificate
The easiest way to get an SSL certificate for the domain is to install `certbot` and run this:
```bash
$ sudo certbot -d conduit.koesters.xyz
```
## You're done!
Now you can start Conduit with
```bash
$ sudo systemctl start conduit
```
and set it to start automatically when your system boots with
```bash
$ sudo systemctl enable conduit
```

94
Dockerfile Normal file
View File

@ -0,0 +1,94 @@
# Using multistage build:
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
########################## BUILD IMAGE ##########################
# Alpine build image to build Conduit's statically compiled binary
FROM alpine:3.12 as builder
# Specifies if the local project is build or if Conduit gets build
# from the official git repository. Defaults to the git repo.
ARG LOCAL=false
# Specifies which revision/commit is build. Defaults to HEAD
ARG GIT_REF=HEAD
# Add 'edge'-repository to get Rust 1.45
RUN sed -i \
-e 's|v3\.12|edge|' \
/etc/apk/repositories
# Install packages needed for building all crates
RUN apk add --no-cache \
cargo \
openssl-dev
# Copy project files from current folder
COPY . .
# Build it from the copied local files or from the official git repository
RUN if [[ $LOCAL == "true" ]]; then \
cargo install --path . ; \
else \
cargo install --git "https://git.koesters.xyz/timo/conduit.git" --rev ${GIT_REF}; \
fi
########################## RUNTIME IMAGE ##########################
# Create new stage with a minimal image for the actual
# runtime image/container
FROM alpine:3.12
ARG CREATED
ARG VERSION
ARG GIT_REF=HEAD
# Labels according to https://github.com/opencontainers/image-spec/blob/master/annotations.md
# including a custom label specifying the build command
LABEL org.opencontainers.image.created=${CREATED} \
org.opencontainers.image.authors="Conduit Contributors" \
org.opencontainers.image.title="Conduit" \
org.opencontainers.image.version=${VERSION} \
org.opencontainers.image.vendor="Conduit Contributors" \
org.opencontainers.image.description="A Matrix homeserver written in Rust" \
org.opencontainers.image.url="https://conduit.rs/" \
org.opencontainers.image.revision=${GIT_REF} \
org.opencontainers.image.source="https://git.koesters.xyz/timo/conduit.git" \
org.opencontainers.image.documentation.="" \
org.opencontainers.image.licenses="AGPL-3.0" \
org.opencontainers.image.ref.name="" \
org.label-schema.docker.build="docker build . -t conduit_homeserver:latest --build-arg CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml)" \
maintainer="Weasy666"
# Standard port on which Rocket launches
EXPOSE 8000
# Copy config files from context and the binary from
# the "builder" stage to the current stage into folder
# /srv/conduit and create data folder for database
RUN mkdir -p /srv/conduit/.local/share/conduit
COPY --from=builder /root/.cargo/bin/conduit /srv/conduit/
# Add www-data user and group with UID 82, as used by alpine
# https://git.alpinelinux.org/aports/tree/main/nginx/nginx.pre-install
RUN set -x ; \
addgroup -Sg 82 www-data 2>/dev/null ; \
adduser -S -D -H -h /srv/conduit -G www-data -g www-data www-data 2>/dev/null ; \
addgroup www-data www-data 2>/dev/null && exit 0 ; exit 1
# Change ownership of Conduit files to www-data user and group
RUN chown -cR www-data:www-data /srv/conduit
# Install packages needed to run Conduit
RUN apk add --no-cache \
ca-certificates \
libgcc
# Create a volume for the database, to persist its contents
VOLUME ["/srv/conduit/.local/share/conduit"]
# Set user to www-data
USER www-data
# Set container home directory
WORKDIR /srv/conduit
# Run Conduit
ENTRYPOINT [ "/srv/conduit/conduit" ]

View File

@ -4,7 +4,7 @@
[![Liberapay](https://img.shields.io/liberapay/receives/timokoesters?logo=liberapay)](https://liberapay.com/timokoesters)
[![Matrix](https://img.shields.io/matrix/conduit:koesters.xyz?server_fqdn=matrix.koesters.xyz&logo=matrix)](https://matrix.to/#/#conduit:koesters.xyz)
#### What is the goal
#### What is the goal?
A fast Matrix homeserver that's easy to set up and just works. You can install it on a mini-computer like the Raspberry Pi to host Matrix for your family, friends or company.
@ -18,8 +18,14 @@ Yes! Just open a Matrix client (<https://app.element.io> or Element Android for
#### How can I deploy my own?
You just have to clone the repo, build it with `cargo build --release` and call the binary (target/release/conduit) from somewhere like a systemd script.
It's explained in more detail [here](https://git.koesters.xyz/timo/conduit/wiki/Deploy).
##### From source
Clone the repo, build it with `cargo build --release` and call the binary
(target/release/conduit) from somewhere like a systemd script. [Read more](DEPLOY_FROM_SOURCE.md)
##### Using Docker
Build the docker image and run it with docker or docker-compose. [Read more](docker/README.md)
#### What is it build on?

52
docker-compose.yml Normal file
View File

@ -0,0 +1,52 @@
# Conduit
version: '3'
services:
homeserver:
### If you already built the Conduit image with 'docker build', then you can uncomment the
### 'image' line and comment out the 'build' option.
# image: conduit_homeserver:latest
### If you want meaningful labels in you built Conduit image, you should run docker-compose like this:
### CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml) docker-compose up -d
build:
context: .
args:
CREATED:
VERSION:
LOCAL: "false"
GIT_REF: HEAD
restart: unless-stopped
ports:
- 8448:8000
volumes:
- db:/srv/conduit/.local/share/conduit
### Uncomment if you want to use Rocket.toml to configure Conduit
### Note: Set env vars will override Rocket.toml values
# - ./Rocket.toml:/srv/conduit/Rocket.toml
environment:
ROCKET_SERVER_NAME: localhost:8000 # replace with your own name
### Uncomment and change values as desired
# ROCKET_LOG: normal # Available levels are: off, debug, normal, critical
# ROCKET_PORT: 8000
# ROCKET_REGISTRATION_DISABLED: 'true'
# ROCKET_ENCRYPTION_DISABLED: 'true'
# ROCKET_DATABASE_PATH: /srv/conduit/.local/share/conduit
# ROCKET_WORKERS: 10
# ROCKET_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
### Uncomment if you want to use your own Element-Web App.
### Note: You need to provide a config.json for Element and you also need a second
### Domain or Subdomain for the communication between Element and Conduit
### Config-Docs: https://github.com/vector-im/element-web/blob/develop/docs/config.md
# element-web:
# image: vectorim/riot-web:latest
# restart: unless-stopped
# ports:
# - 8009:80
# volumes:
# - ./element_config.json:/app/config.json
# depends_on:
# - homeserver
volumes:
db:

72
docker/README.md Normal file
View File

@ -0,0 +1,72 @@
# Deploy using Docker
> **Note:** To run and use Conduit you should probably use it with a Domain or Subdomain behind a reverse proxy (like Nginx, Traefik, Apache, ...) with a Lets Encrypt certificate.
## Docker
### Build & Dockerfile
The Dockerfile provided by Conduit has two stages, each of which creates an image.
1. **Builder:** Builds the binary from local context or by cloning a git revision from the official repository.
2. **Runtime:** Copies the built binary from **Builder** and sets up the runtime environment, like creating a volume to persist the database and applying the correct permissions.
The Dockerfile includes a few build arguments that should be supplied when building it.
``` Dockerfile
ARG LOCAL=false
ARG CREATED
ARG VERSION
ARG GIT_REF=HEAD
```
- **CREATED:** Date and time as string (date-time as defined by RFC 3339). Will be used to create the Open Container Initiative compliant label `org.opencontainers.image.created`. Supply by it like this `$(date -u +'%Y-%m-%dT%H:%M:%SZ')`
- **VERSION:** The SemVer version of Conduit, which is in the image. Will be used to create the Open Container Initiative compliant label `org.opencontainers.image.version`. If you have a `Cargo.toml` in your build context, you can get it with `$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml)`
- **LOCAL:** *(Optional)* A boolean value, specifies if the local build context should be used, or if the official repository will be cloned. If not supplied with the build command, it will default to `false`.
- **GIT_REF:** *(Optional)* A git ref, like `HEAD` or a commit ID. The supplied ref will be used to create the Open Container Initiative compliant label `org.opencontainers.image.revision` and will be the ref that is cloned from the repository when not building from the local context. If not supplied with the build command, it will default to `HEAD`.
To build the image you can use the following command
``` bash
docker build . -t conduit_homeserver:latest --build-arg CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml)
```
which also will tag the resulting image as `conduit_homeserver:latest`.
**Note:** it ommits the two optional `build-arg`s.
### Run
After building the image you can simply run it with
``` bash
docker run conduit_homeserver:latest -p 8448:8000 -v db:/srv/conduit/.local/share/conduit -e ROCKET_SERVER_NAME="localhost:8000"
```
For detached mode, you also need to use the `-d` flag. You can pass in more env vars as are shown here, for an overview of possible values, you can take a look at the `docker-compose.yml` file.
If you just want to test Conduit for a short time, you can use the `--rm` flag, which will clean up everything related to your container after you stop it.
## Docker-compose
If the docker command is not for you or your setup, you can also use one of the provided `docker-compose` files. Depending on your proxy setup, use the `docker-compose.traefik.yml` including `docker-compose.override.traefik.yml` or the normal `docker-compose.yml` for every other reverse proxy.
### Build
To build the Conduit image with docker-compose, you first need to open and modify the `docker-compose.yml` file. There you need to comment the `image:` option and uncomment the `build:` option. Then call docker-compose with:
``` bash
CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml) docker-compose up
```
This will also start the container right afterwards, so if want it to run in detached mode, you also should use the `-d` flag. For possible `build-args`, please take a look at the above `Build & Dockerfile` section.
### Run
If you already have built the image, you can just start the container and everything else in the compose file in detached mode with:
``` bash
docker-compose up -d
```

View File

@ -0,0 +1,22 @@
# Conduit - Traefik Reverse Proxy Labels
version: '3'
services:
homeserver:
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy" # Change this to the name of your Traefik docker proxy network
- "traefik.http.routers.to-conduit.rule=Host(`<SUBDOMAIN>.<DOMAIN>`)" # Change to the address on which Conduit is hosted
- "traefik.http.routers.to-conduit.tls=true"
- "traefik.http.routers.to-conduit.tls.certresolver=letsencrypt"
### Uncomment this if you uncommented Element-Web App in the docker-compose.yml
# element-web:
# labels:
# - "traefik.enable=true"
# - "traefik.docker.network=proxy" # Change this to the name of your Traefik docker proxy network
# - "traefik.http.routers.to-element-web.rule=Host(`<SUBDOMAIN>.<DOMAIN>`)" # Change to the address on which Element-Web is hosted
# - "traefik.http.routers.to-element-web.tls=true"
# - "traefik.http.routers.to-element-web.tls.certresolver=letsencrypt"

View File

@ -0,0 +1,58 @@
# Conduit - Behind Traefik Reverse Proxy
version: '3'
services:
homeserver:
### If you already built the Conduit image with 'docker build', then you can uncomment the
### 'image' line and comment out the 'build' option.
# image: conduit_homeserver:latest
### If you want meaningful labels in you built Conduit image, you should run docker-compose like this:
### CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml) docker-compose up -d
build:
context: .
args:
CREATED:
VERSION:
LOCAL: false
GIT_REF: HEAD
restart: unless-stopped
volumes:
- db:/srv/conduit/.local/share/conduit
### Uncomment if you want to use Rocket.toml to configure Conduit
### Note: Set env vars will override Rocket.toml values
# - ./Rocket.toml:/srv/conduit/Rocket.toml
networks:
- proxy
environment:
ROCKET_SERVER_NAME: localhost:8000 # replace with your own name
### Uncomment and change values as desired
# ROCKET_LOG: normal # Available levels are: off, debug, normal, critical
# ROCKET_PORT: 8000
# ROCKET_REGISTRATION_DISABLED: 'true'
# ROCKET_ENCRYPTION_DISABLED: 'true'
# ROCKET_DATABASE_PATH: /srv/conduit/.local/share/conduit
# ROCKET_WORKERS: 10
# ROCKET_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
### Uncomment if you want to use your own Element-Web App.
### Note: You need to provide a config.json for Element and you also need a second
### Domain or Subdomain for the communication between Element and Conduit
### Config-Docs: https://github.com/vector-im/element-web/blob/develop/docs/config.md
# element-web:
# image: vectorim/riot-web:latest
# restart: unless-stopped
# volumes:
# - ./element_config.json:/app/config.json
# networks:
# - proxy
# depends_on:
# - homeserver
volumes:
db:
networks:
# This is the network Traefik listens to, if you network has a different
# name, don't forget to change it here and in the docker-compose.override.yml
proxy:
external: true