diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b1d54d2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +# General good ideas to ignore +.idea +.git +.cache +.venv + +.dockerignore +Dockerfile +Dockerfile_build diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 0000000..6e69775 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,5 @@ +# Configuration related to self-hosted runner. +self-hosted-runner: + # Labels of self-hosted runner in array of strings. + labels: + - arc-runner-set diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..745f4ad --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,27 @@ +on: + pull_request: + +jobs: + test: + runs-on: arc-runner-set + steps: + - uses: actions/checkout@v5 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install pre-commit + run: | + pip install pre-commit + - name: Do pre-commit checks + run: | + pre-commit run --all-files + + docker_builds: + runs-on: arc-runner-set + needs: test + steps: + - uses: actions/checkout@v5 + - name: Build Synapse + run: | + docker build -t synapse:latest . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42a5840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# OSX metadata +.DS_Store +._DS_Store +.idea diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..270e8d5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +default_language_version: + python: python3 +default_install_hook_types: + - pre-commit + - commit-msg +repos: +- repo: https://github.com/compilerla/conventional-pre-commit + rev: v4.2.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: [] +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: no-commit-to-branch + - id: check-executables-have-shebangs + - id: check-ast + - id: check-toml + - id: trailing-whitespace + exclude: ".*.sql" + - id: end-of-file-fixer + exclude: ".*.sql" + - id: check-yaml + - id: check-added-large-files + - id: check-case-conflict + - id: check-json + - id: check-merge-conflict + - id: check-symlinks + - id: pretty-format-json + args: + - --autofix +- repo: https://github.com/IamTheFij/docker-pre-commit.git + rev: v3.0.1 + hooks: + - id: docker-compose-check + files: "docker-compose.*.yml" + exclude: ".*.tpl" +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.5 + hooks: + - id: forbid-crlf + exclude: ".*.sql" + - id: remove-crlf + exclude: ".*.sql" + - id: forbid-tabs + exclude: ".*.sql" + - id: remove-tabs + exclude: ".*.sql" +- repo: https://github.com/Lucas-C/pre-commit-hooks-markup + rev: v1.0.1 + hooks: + - id: rst-linter +- repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + exclude: "poetry.lock" + # args: ['--baseline', '.secrets.baseline'] +- repo: https://github.com/rhysd/actionlint + rev: "v1.7.7" + hooks: + - id: actionlint + args: ["-shellcheck", "''"] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a784979 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM python:3.11-slim AS deps + +# Install OS-level packages +RUN apt-get update && apt-get install -y \ + ca-certificates \ + curl \ + gettext \ + openssl \ + tini \ + vim \ + jq \ + netcat-openbsd \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && curl https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -o /usr/bin/wait-for-it.sh \ + && chmod a+x /usr/bin/wait-for-it.sh \ + && true +RUN pip install --no-cache-dir authlib psycopg2-binary matrix-synapse + +WORKDIR /opt/synapse +COPY scripts ./scripts +COPY templates ./templates +RUN chmod +x /opt/synapse/scripts/*.sh + +FROM deps AS run +WORKDIR /opt/synapse +ENTRYPOINT ["/usr/bin/tini", "--", "/opt/synapse/scripts/synapse-entrypoint.sh"] diff --git a/README.md b/README.md index 56334c6..922cd6c 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# docker-synapse-server \ No newline at end of file +# docker-synapse-server diff --git a/scripts/init_certs.sh b/scripts/init_certs.sh new file mode 100644 index 0000000..bdd6105 --- /dev/null +++ b/scripts/init_certs.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +CERT_DIR="${CERT_DIR:-/data/certs}" + +# LE certs +LE_CERT="/le_certs/rasenmaeher/fullchain.pem" +LE_KEY="/le_certs/rasenmaeher/privkey.pem" + +mkdir -p "$CERT_DIR" + +SERVER_CRT="$CERT_DIR/${SERVER_DOMAIN}.crt" +SERVER_KEY="$CERT_DIR/${SERVER_DOMAIN}.key" + +# Only copy if missing +if [[ ! -f "$SERVER_CRT" || ! -f "$SERVER_KEY" ]]; then + echo "Copying LE certs for $SERVER_DOMAIN..." + cp "$LE_CERT" "$SERVER_CRT" + cp "$LE_KEY" "$SERVER_KEY" +fi diff --git a/scripts/synapse-entrypoint.sh b/scripts/synapse-entrypoint.sh new file mode 100644 index 0000000..a75a498 --- /dev/null +++ b/scripts/synapse-entrypoint.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Resolve our magic names to docker internal ip +GW_IP=$(getent ahostsv4 host.docker.internal | grep RAW | awk '{ print $1 }') +echo "GW_IP=$GW_IP" +grep -v -F -e "localmaeher" -- /etc/hosts >/etc/hosts.new && cat /etc/hosts.new >/etc/hosts +echo "$GW_IP kc.localmaeher.dev.pvarki.fi" >>/etc/hosts +echo "*** BEGIN /etc/hosts ***" +cat /etc/hosts +echo "*** END /etc/hosts ***" + +if [[ -d "/ca_public" ]]; then + echo "Installing custom CAs from /ca_public into OS trust store..." + mkdir -p /usr/local/share/ca-certificates/ + + for pem in /ca_public/*.pem; do + [[ -f "$pem" ]] || continue + base=$(basename "$pem" .pem) + echo " -> installing $pem as ${base}.crt" + cp "$pem" "/usr/local/share/ca-certificates/${base}.crt" + done + + update-ca-certificates --fresh + + echo "CA store updated." +else + echo "WARNING: /ca_public directory not found." +fi + +export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt +export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + +DATA_DIR="/data" +CERT_DIR="$DATA_DIR/certs" +CONFIG_TEMPLATE="/opt/synapse/templates/homeserver.yaml" +CONFIG_FILE="$DATA_DIR/homeserver.yaml" + +/opt/synapse/scripts/init_certs.sh + +OIDC_FILE="/config/registration.json" +echo "Waiting for $OIDC_FILE to be generated..." +until [[ -f "$OIDC_FILE" ]]; do + sleep 2 +done + +export CLIENT_ID=$(jq -r '.client_id' /config/registration.json) +export CLIENT_SECRET=$(jq -r '.client_secret' /config/registration.json) + +if [[ ! -f "$CONFIG_FILE" ]]; then + echo "Creating homeserver.yaml..." + mkdir -p "$DATA_DIR" + envsubst < "$CONFIG_TEMPLATE" > "$CONFIG_FILE" + chown -R 991:991 "$DATA_DIR" + chmod 777 "$DATA_DIR" + chmod 666 "$CONFIG_FILE" +fi + +wait-for-it.sh postgres:5432 --timeout=30 -- echo "Postgres is up!" + +echo "Starting Synapse..." +python -m synapse.app.homeserver --config-path "$CONFIG_FILE" diff --git a/templates/homeserver.yaml b/templates/homeserver.yaml new file mode 100644 index 0000000..6f50d03 --- /dev/null +++ b/templates/homeserver.yaml @@ -0,0 +1,72 @@ +server_name: "${SERVER_DOMAIN}" +public_baseurl: "https://synapse.${SERVER_DOMAIN}:${NGINX_HTTPS_PORT}/" +pid_file: /data/homeserver.pid +macaroon_secret_key: "${SYNAPSE_MACAROON_SECRET_KEY}" + +listeners: + - port: 8448 + tls: true + type: http + x_forwarded: true + resources: + - names: [client, federation] + compress: false + - port: 8008 + tls: false + type: http + x_forwarded: true + resources: + - names: [client] + compress: false + +report_stats: no +media_store_path: /data/media_store + +allow_profile_lookup_over_federation: false + +allow_public_rooms_over_federation: false +allow_public_rooms_without_auth: false + +room_prejoin_state: + disable_default_event_types: false + +url_preview_enabled: false + +enable_room_list_search: false + +allow_guest_access: false +enable_registration: false +enable_registration_without_verification: false + +database: + name: psycopg2 + args: + user: ${POSTGRES_USER} + password: "${POSTGRES_PASSWORD}" + database: ${POSTGRES_DB} + host: ${POSTGRES_HOST} + cp_min: 5 + cp_max: 10 + +tls_certificate_path: "/data/certs/${SERVER_DOMAIN}.crt" +tls_private_key_path: "/data/certs/${SERVER_DOMAIN}.key" + +password_config: + enabled: false + +#Online offline status +presence: + enabled: false + +oidc_providers: + # https://element-hq.github.io/synapse/latest/openid.html#keycloak + - idp_id: keycloak + idp_name: "Keycloak" + issuer: "https://${KCDOMAIN}:9443/realms/${KCREALM}" + client_id: "${CLIENT_ID}" + client_secret: "${CLIENT_SECRET}" + scopes: ["openid", "profile"] + user_mapping_provider: + config: + localpart_template: "{{ user.preferred_username }}" + display_name_template: "{{ user.name }}"