Merge pull request #84 from spantaleev/non-root-containers

Make containers start as non-root, without capabilities and with a read-only filesystem
This commit is contained in:
Slavi Pantaleev 2019-01-29 19:00:59 +02:00 committed by GitHub
commit 3f5b1ad1a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 339 additions and 72 deletions

View file

@ -1,3 +1,31 @@
# 2019-01-29
## Running container processes as non-root, without capabilities and read-only
To improve security, this playbook no longer starts container processes as the `root` user.
Most containers were dropping privileges anyway, but we were trusting them with `root` privileges until they would do that.
Not anymore -- container processes now start as a non-root user (usually `matrix`) from the get-go.
For additional security, various capabilities are also dropped (see [why it's important](https://github.com/projectatomic/atomic-site/issues/203)) for all containers.
Additionally, most containers now use a read-only filesystem (see [why it's important](https://www.projectatomic.io/blog/2015/12/making-docker-images-write-only-in-production/)).
Containers are given write access only to the directories they need to write to.
A minor breaking change is the `matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size` variable having being renamed to `matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb` (note the `_mb` suffix). The new variable expects a number value (e.g. `25M` -> `25`).
If you weren't customizing this variable, this wouldn't affect you.
## matrix-mailer is now based on Exim, not Postfix
While we would have preferred to stay with [Postfix](http://www.postfix.org/), we found out that it cannot run as a non-root user.
We've had to replace it with [Exim](https://www.exim.org/) (via the [devture/exim-relay](https://hub.docker.com/r/devture/exim-relay) container image).
The internal `matrix-mailer` service (running in a container) now listens on port `8025` (used to be `587` before).
The playbook will update your Synapse and mxisd email settings to match (`matrix-mailer:587` -> `matrix-mailer:8025`).
Using the [devture/exim-relay](https://hub.docker.com/r/devture/exim-relay) container image instead of [panubo/postfix](https://hub.docker.com/r/panubo/postfix/) also gives us a nice disk usage reduction (~200MB -> 8MB).
# 2019-01-17
## (BC Break) Making the playbook's roles more independent of one another

View file

@ -22,7 +22,7 @@ Using this playbook, you can get the following services configured on your serve
- (optional, default) an [mxisd](https://github.com/kamax-io/mxisd) Matrix Identity server
- (optional, default) a [Postfix](http://www.postfix.org/) mail server, through which all Matrix services send outgoing email (can be configured to relay through another SMTP server)
- (optional, default) an [Exim](https://www.exim.org/) mail server, through which all Matrix services send outgoing email (can be configured to relay through another SMTP server)
- (optional, default) an [nginx](http://nginx.org/) web server, listening on ports 80 and 443 - standing in front of all the other services. Using your own webserver [is possible](docs/configuring-playbook-own-webserver.md)
@ -98,7 +98,7 @@ This playbook sets up your server using the following Docker images:
- [ewoutp/goofys](https://hub.docker.com/r/ewoutp/goofys/) - the [Goofys](https://github.com/kahing/goofys) Amazon [S3](https://aws.amazon.com/s3/) file-system-mounting program (optional)
- [panubo/postfix](https://hub.docker.com/r/panubo/postfix/) - the [Postfix](http://www.postfix.org/) email server (optional)
- [devture/exim-relay](https://hub.docker.com/r/devture/exim-relay/) - the [Exim](https://www.exim.org/) email server (optional)
- [devture/matrix-corporal](https://hub.docker.com/r/devture/matrix-corporal/) - [Matrix Corporal](https://github.com/devture/matrix-corporal): reconciliator and gateway for a managed Matrix server (optional)

View file

@ -1,6 +1,6 @@
# Adjusting email-sending settings (optional)
By default, this playbook sets up a [postfix](http://www.postfix.org/) email server through which all Matrix services send emails.
By default, this playbook sets up an [Exim](https://www.exim.org/) email server through which all Matrix services send emails.
The email server would attempt to deliver emails directly to their final destination.
This may or may not work, depending on your domain configuration (SPF settings, etc.)
@ -28,8 +28,6 @@ matrix_mailer_relay_auth_username: "another.sender@example.com"
matrix_mailer_relay_auth_password: "some-password"
```
Keep in mind that postfix will look up the MX record of your relay host (`matrix_mailer_relay_host_name`) and, if available, will actually use that instead of what you've defined. This behavior is [documented here](http://www.postfix.org/postconf.5.html#relayhost). If you'd like to suppress this and use the relay host value as is, wrap it in square brackets (e.g. `matrix_mailer_relay_host_name: "[mail.example.com]"`).
## Troubleshooting

View file

@ -125,7 +125,7 @@ matrix_mxisd_dns_overwrite_homeserver_client_value: "http://{{ 'matrix-corporal:
# By default, we send mail through the `matrix-mailer` service.
matrix_mxisd_threepid_medium_email_identity_from: "{{ matrix_mailer_sender_address }}"
matrix_mxisd_threepid_medium_email_connectors_smtp_host: "matrix-mailer"
matrix_mxisd_threepid_medium_email_connectors_smtp_port: 587
matrix_mxisd_threepid_medium_email_connectors_smtp_port: 8025
matrix_mxisd_threepid_medium_email_connectors_smtp_tls: 0
matrix_mxisd_systemd_wanted_services_list: |
@ -158,7 +158,7 @@ matrix_nginx_proxy_enabled: true
matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "{{ 'matrix-corporal:41080' if matrix_corporal_enabled else 'matrix-synapse:8008' }}"
matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "{{ 'localhost:41080' if matrix_corporal_enabled else 'localhost:8008' }}"
matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size: "{{ matrix_synapse_max_upload_size_mb }}M"
matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb: "{{ matrix_synapse_max_upload_size_mb }}"
matrix_nginx_proxy_proxy_matrix_enabled: true
matrix_nginx_proxy_proxy_riot_enabled: "{{ matrix_riot_web_enabled }}"
@ -269,7 +269,7 @@ matrix_synapse_database_database: "{{ matrix_postgres_db_name }}"
matrix_synapse_email_enabled: "{{ matrix_mailer_enabled }}"
matrix_synapse_email_smtp_host: "matrix-mailer"
matrix_synapse_email_smtp_port: 587
matrix_synapse_email_smtp_port: 8025
matrix_synapse_email_smtp_require_transport_security: false
matrix_synapse_email_notif_from: "Matrix <{{ matrix_mailer_sender_address }}>"
matrix_synapse_email_riot_base_url: "https://{{ hostname_riot }}"

View file

@ -12,6 +12,8 @@ ExecStartPre=-/usr/bin/docker rm matrix-corporal
ExecStart=/usr/bin/docker run --rm --name matrix-corporal \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--network={{ matrix_docker_network }} \
{% if matrix_corporal_container_expose_ports %}
-p 127.0.0.1:41080:41080 \

View file

@ -12,6 +12,9 @@ ExecStartPre=-/usr/bin/docker rm matrix-coturn
ExecStart=/usr/bin/docker run --rm --name matrix-coturn \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/var/tmp:rw,noexec,nosuid,size=100m \
-p 3478:3478 \
-p 3478:3478/udp \
-p {{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}:{{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}/udp \

View file

@ -2,7 +2,12 @@ matrix_mailer_enabled: true
matrix_mailer_base_path: "{{ matrix_base_data_path }}/mailer"
matrix_mailer_docker_image: "panubo/postfix:latest"
matrix_mailer_docker_image: "devture/exim-relay:4.91-r1-0"
# The user/group that the container runs with.
# These match the `exim` user/group within the container image.
matrix_mailer_container_user_uid: 100
matrix_mailer_container_user_gid: 101
matrix_mailer_sender_address: "matrix@{{ hostname_identity }}"
matrix_mailer_relay_use: false

View file

@ -1,8 +1,7 @@
MAILNAME={{ hostname_matrix }}
{% if matrix_mailer_relay_use %}
RELAYHOST={{ matrix_mailer_relay_host_name }}:{{ matrix_mailer_relay_host_port }}
SMARTHOST={{ matrix_mailer_relay_host_name }}::{{ matrix_mailer_relay_host_port }}
{% endif %}
{% if matrix_mailer_relay_auth %}
RELAYHOST_AUTH=yes
RELAYHOST_PASSWORDMAP={{ matrix_mailer_relay_host_name }}:{{ matrix_mailer_relay_auth_username }}:{{ matrix_mailer_relay_auth_password }}
SMTP_USERNAME={{ matrix_mailer_relay_auth_username }}
SMTP_PASSWORD={{ matrix_mailer_relay_auth_password }}
{% endif %}

View file

@ -9,8 +9,13 @@ ExecStartPre=-/usr/bin/docker kill matrix-mailer
ExecStartPre=-/usr/bin/docker rm matrix-mailer
ExecStart=/usr/bin/docker run --rm --name matrix-mailer \
--log-driver=none \
--user={{ matrix_mailer_container_user_uid }}:{{ matrix_mailer_container_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/var/spool/exim:rw,noexec,nosuid,size=100m \
--network={{ matrix_docker_network }} \
--env-file={{ matrix_mailer_base_path }}/env-mailer \
--hostname={{ hostname_matrix }} \
{{ matrix_mailer_docker_image }}
ExecStop=-/usr/bin/docker kill matrix-mailer
ExecStop=-/usr/bin/docker rm matrix-mailer

View file

@ -12,16 +12,23 @@ Wants={{ service }}
Type=simple
ExecStartPre=-/usr/bin/docker kill matrix-mxisd
ExecStartPre=-/usr/bin/docker rm matrix-mxisd
# mxisd writes an SQLite shared library (libsqlitejdbc.so) to /tmp and executes it from there,
# so /tmp needs to be mounted with an exec option.
ExecStart=/usr/bin/docker run --rm --name matrix-mxisd \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/tmp:rw,exec,nosuid,size=10m \
--network={{ matrix_docker_network }} \
{% if matrix_mxisd_container_expose_port %}
-p 127.0.0.1:8090:8090 \
{% endif %}
-v {{ matrix_mxisd_config_path }}:/etc/mxisd:ro \
-v {{ matrix_mxisd_data_path }}:/var/mxisd \
-v {{ matrix_mxisd_data_path }}:/var/mxisd:rw \
{{ matrix_mxisd_docker_image }}
ExecStop=-/usr/bin/docker kill matrix-mxisd
ExecStop=-/usr/bin/docker rm matrix-mxisd
Restart=always

View file

@ -1,5 +1,8 @@
matrix_nginx_proxy_enabled: true
# We use an official nginx image, which we fix-up to run unprivileged.
# An alternative would be an `nginxinc/nginx-unprivileged` image, but
# those as more frequently out of date.
matrix_nginx_proxy_docker_image: "nginx:1.15.8-alpine"
matrix_nginx_proxy_data_path: "{{ matrix_base_data_path }}/nginx-proxy"
@ -41,7 +44,10 @@ matrix_nginx_proxy_proxy_matrix_identity_api_addr_sans_container: "localhost:809
matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "matrix-synapse:8008"
matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "localhost:8008"
# This needs to be equal or higher than the maximum upload size accepted by Synapse.
matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size: "25M"
matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb: 25
# The tmpfs at /tmp needs to be large enough to handle multiple concurrent file uploads.
matrix_nginx_proxy_tmp_directory_size_mb: "{{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb * 50 }}"
# A list of strings containing additional configuration blocks to add to the matrix domain's server configuration.
matrix_nginx_proxy_proxy_matrix_additional_server_configuration_blocks: []

View file

@ -21,23 +21,30 @@
- "{{ matrix_nginx_proxy_data_path }}"
- "{{ matrix_nginx_proxy_confd_path }}"
- name: Ensure Matrix nginx-proxy configured (main config override)
template:
src: "{{ role_path }}/templates/nginx/nginx.conf.j2"
dest: "{{ matrix_nginx_proxy_data_path }}/nginx.conf"
mode: 0644
when: "matrix_nginx_proxy_enabled"
- name: Ensure Matrix nginx-proxy configured (generic)
template:
src: "{{ role_path }}/templates/nginx-conf.d/nginx-http.conf.j2"
src: "{{ role_path }}/templates/nginx/conf.d/nginx-http.conf.j2"
dest: "{{ matrix_nginx_proxy_confd_path }}/nginx-http.conf"
mode: 0644
when: "matrix_nginx_proxy_enabled"
- name: Ensure Matrix nginx-proxy configuration for matrix domain exists
template:
src: "{{ role_path }}/templates/nginx-conf.d/matrix-synapse.conf.j2"
src: "{{ role_path }}/templates/nginx/conf.d/matrix-synapse.conf.j2"
dest: "{{ matrix_nginx_proxy_confd_path }}/matrix-synapse.conf"
mode: 0644
when: "matrix_nginx_proxy_proxy_matrix_enabled"
- name: Ensure Matrix nginx-proxy configuration for riot domain exists
template:
src: "{{ role_path }}/templates/nginx-conf.d/matrix-riot-web.conf.j2"
src: "{{ role_path }}/templates/nginx/conf.d/matrix-riot-web.conf.j2"
dest: "{{ matrix_nginx_proxy_confd_path }}/matrix-riot-web.conf"
mode: 0644
when: "matrix_nginx_proxy_proxy_riot_enabled"
@ -104,3 +111,8 @@
state: absent
when: "not matrix_nginx_proxy_proxy_riot_enabled"
- name: Ensure Matrix nginx-proxy configuration for main config override deleted
file:
path: "{{ matrix_nginx_proxy_data_path }}/nginx.conf"
state: absent
when: "not matrix_nginx_proxy_enabled"

View file

@ -15,6 +15,7 @@
mode: 0770
owner: "{{ matrix_user_username }}"
group: "{{ matrix_user_username }}"
recurse: true
with_items:
- "{{ matrix_ssl_log_dir_path }}"
- "{{ matrix_ssl_config_dir_path }}"

View file

@ -19,12 +19,16 @@
/usr/bin/docker run
--rm
--name=matrix-certbot
--net=host
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
-p 80:8080
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt
{{ matrix_ssl_lets_encrypt_certbot_docker_image }}
certonly
--non-interactive
--work-dir=/tmp
--http-01-port 8080
{% if matrix_ssl_lets_encrypt_staging %}--staging{% endif %}
--standalone
--preferred-challenges http
@ -42,13 +46,17 @@
/usr/bin/docker run
--rm
--name=matrix-certbot
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:80
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:8080
--network={{ matrix_docker_network }}
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt
{{ matrix_ssl_lets_encrypt_certbot_docker_image }}
certonly
--non-interactive
--work-dir=/tmp
--http-01-port 8080
{% if matrix_ssl_lets_encrypt_staging %}--staging{% endif %}
--standalone
--preferred-challenges http

View file

@ -1,5 +1,5 @@
server {
listen 80;
listen {{ 8080 if matrix_nginx_proxy_enabled else 80 }};
server_name {{ matrix_nginx_proxy_proxy_riot_hostname }};
server_tokens off;
@ -8,7 +8,7 @@ server {
{% if matrix_nginx_proxy_enabled %}
{# Use the embedded DNS resolver in Docker containers to discover the service #}
resolver 127.0.0.11 valid=5s;
set $backend "matrix-certbot:80";
set $backend "matrix-certbot:8080";
proxy_pass http://$backend;
{% else %}
{# Generic configuration for use outside of our container setup #}
@ -22,8 +22,8 @@ server {
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen {{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2;
listen [::]:{{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2;
server_name {{ matrix_nginx_proxy_proxy_riot_hostname }};
@ -43,7 +43,7 @@ server {
{% if matrix_nginx_proxy_enabled %}
{# Use the embedded DNS resolver in Docker containers to discover the service #}
resolver 127.0.0.11 valid=5s;
set $backend "matrix-riot-web:80";
set $backend "matrix-riot-web:8080";
proxy_pass http://$backend;
{% else %}
{# Generic configuration for use outside of our container setup #}

View file

@ -1,5 +1,5 @@
server {
listen 80;
listen {{ 8080 if matrix_nginx_proxy_enabled else 80 }};
server_name {{ matrix_nginx_proxy_proxy_matrix_hostname }};
server_tokens off;
@ -8,7 +8,7 @@ server {
{% if matrix_nginx_proxy_enabled %}
{# Use the embedded DNS resolver in Docker containers to discover the service #}
resolver 127.0.0.11 valid=5s;
set $backend "matrix-certbot:80";
set $backend "matrix-certbot:8080";
proxy_pass http://$backend;
{% else %}
{# Generic configuration for use outside of our container setup #}
@ -22,8 +22,8 @@ server {
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen {{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2;
listen [::]:{{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2;
server_name {{ matrix_nginx_proxy_proxy_matrix_hostname }};
@ -116,7 +116,7 @@ server {
proxy_set_header X-Forwarded-For $remote_addr;
client_body_buffer_size 25M;
client_max_body_size {{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size }};
client_max_body_size {{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb }}M;
proxy_max_temp_file_size 0;
}

View file

@ -0,0 +1,45 @@
# This is a custom nginx configuration file that we use in the container (instead of the default one),
# because it allows us to run nginx with a non-root user.
#
# For this to work, the default vhost file (`/etc/nginx/conf.d/default.conf`) also needs to be removed.
#
# The following changes have been done compared to a default nginx configuration file:
# - various temp paths are changed to `/tmp`, so that a non-root user can write to them
# - the `user` directive was removed, as we don't want nginx to switch users
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View file

@ -12,15 +12,22 @@ Wants={{ service }}
Type=simple
ExecStartPre=-/usr/bin/docker kill matrix-nginx-proxy
ExecStartPre=-/usr/bin/docker rm matrix-nginx-proxy
ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_nginx_proxy_tmp_directory_size_mb }}m \
--network={{ matrix_docker_network }} \
-p 80:80 \
-p 443:443 \
-p 80:8080 \
-p 443:8443 \
-v {{ matrix_nginx_proxy_data_path }}/nginx.conf:/etc/nginx/nginx.conf:ro \
-v {{ matrix_nginx_proxy_confd_path }}:/etc/nginx/conf.d:ro \
-v {{ matrix_ssl_config_dir_path }}:{{ matrix_ssl_config_dir_path }}:ro \
-v {{ matrix_static_files_base_path }}:{{ matrix_static_files_base_path }}:ro \
{{ matrix_nginx_proxy_docker_image }}
ExecStop=-/usr/bin/docker kill matrix-nginx-proxy
ExecStop=-/usr/bin/docker rm matrix-nginx-proxy
ExecReload=/usr/bin/docker exec matrix-nginx-proxy /usr/sbin/nginx -s reload

View file

@ -3,19 +3,23 @@
# For renewal to work, matrix-nginx-proxy (or another webserver, if matrix-nginx-proxy is disabled)
# need to forward requests for `/.well-known/acme-challenge` to the certbot container.
#
# This can happen inside the container network by proxying to `http://matrix-certbot:80`
# This can happen inside the container network by proxying to `http://matrix-certbot:8080`
# or outside (on the host) by proxying to `http://localhost:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}`.
docker run \
--rm \
--name=matrix-certbot \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--network="{{ matrix_docker_network }}" \
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:80 \
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:8080 \
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt \
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt \
{{ matrix_ssl_lets_encrypt_certbot_docker_image }} \
renew \
--non-interactive \
--work-dir=/tmp \
--http-01-port 8080
{% if matrix_ssl_lets_encrypt_staging %}
--staging \
{% endif %}

View file

@ -60,18 +60,20 @@
set_fact:
matrix_postgres_import_command: >-
/usr/bin/docker run --rm --name matrix-postgres-import
--user={{ matrix_user_uid }}:{{ matrix_user_gid }}
--cap-drop=ALL
--network={{ matrix_docker_network }}
--env-file={{ matrix_postgres_base_path }}/env-postgres-psql
-v {{ server_path_postgres_dump }}:{{ server_path_postgres_dump }}:ro
-v {{ server_path_postgres_dump }}:/{{ server_path_postgres_dump|basename }}:ro
--entrypoint=/bin/sh
{{ matrix_postgres_docker_image_latest }}
-c 'cat {{ server_path_postgres_dump }} |
-c 'cat /{{ server_path_postgres_dump|basename }} |
{{ 'gunzip |' if server_path_postgres_dump.endswith('.gz') else '' }}
psql -v ON_ERROR_STOP=1 -h matrix-postgres'
- name: Note about Postgres importing alternative
debug:
msg: >
msg: >-
Importing Postgres database using the following command: `{{ matrix_postgres_import_command }}`.
If this crashes, you can stop Postgres (`systemctl stop matrix-postgres`),
delete its existing data (`rm -rf {{ matrix_postgres_data_path }}/*`), start it again (`systemctl start matrix-postgres`)

View file

@ -79,11 +79,12 @@
detach: no
cleanup: yes
entrypoint: /usr/local/bin/python
command: "/usr/local/bin/synapse_port_db --sqlite-database {{ server_path_homeserver_db }} --postgres-config /data/homeserver.yaml"
command: "/usr/local/bin/synapse_port_db --sqlite-database /{{ server_path_homeserver_db|basename }} --postgres-config /data/homeserver.yaml"
user: "{{ matrix_user_uid }}:{{ matrix_user_gid }}"
cap_drop: ['all']
volumes:
- "{{ matrix_synapse_config_dir_path }}:/data"
- "{{ matrix_synapse_run_path }}:/matrix-run"
- "{{ server_path_homeserver_db }}:/{{ server_path_homeserver_db }}:ro"
- "{{ server_path_homeserver_db }}:/{{ server_path_homeserver_db|basename }}:ro"
networks:
- name: "{{ matrix_docker_network }}"

View file

@ -70,6 +70,7 @@
- name: Perform Postgres database dump
command: |
/usr/bin/docker run --rm --name matrix-postgres-dump \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--network={{ matrix_docker_network }} \
--env-file={{ matrix_postgres_base_path }}/env-postgres-psql \
-v {{ postgres_dump_dir }}:/out \
@ -104,6 +105,8 @@
- name: Perform Postgres database import
command: |
/usr/bin/docker run --rm --name matrix-postgres-import \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--network={{ matrix_docker_network }} \
--env-file={{ matrix_postgres_base_path }}/env-postgres-psql \
-v {{ postgres_dump_dir }}:/in:ro \

View file

@ -10,9 +10,13 @@ ExecStartPre=-/usr/bin/docker rm matrix-postgres
ExecStart=/usr/bin/docker run --rm --name matrix-postgres \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/tmp:rw,noexec,nosuid,size=100m \
--tmpfs=/run/postgresql:rw,noexec,nosuid,size=100m \
--network={{ matrix_docker_network }} \
--env-file={{ matrix_postgres_base_path }}/env-postgres-server \
-v {{ matrix_postgres_data_path }}:/var/lib/postgresql/data \
-v {{ matrix_postgres_data_path }}:/var/lib/postgresql/data:rw \
-v /etc/passwd:/etc/passwd:ro \
{{ matrix_postgres_docker_image_to_use }}
ExecStop=-/usr/bin/docker stop matrix-postgres

View file

@ -8,6 +8,8 @@ fi
docker run \
-it \
--rm \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--env-file={{ matrix_postgres_base_path }}/env-postgres-psql \
--network {{ matrix_docker_network }} \
{{ matrix_postgres_docker_image_to_use }} \

View file

@ -3,6 +3,8 @@
docker run \
-it \
--rm \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--env-file={{ matrix_postgres_base_path }}/env-postgres-psql \
--network {{ matrix_docker_network }} \
{{ matrix_postgres_docker_image_to_use }} \

View file

@ -27,6 +27,7 @@
group: "{{ matrix_user_username }}"
with_items:
- {src: "{{ role_path }}/templates/config.json.j2", name: "config.json"}
- {src: "{{ role_path }}/templates/nginx.conf.j2", name: "nginx.conf"}
- {src: "{{ matrix_riot_web_homepage_template }}", name: "home.html"}
when: matrix_riot_web_enabled

View file

@ -0,0 +1,60 @@
# This is a custom nginx configuration file that we use in the container (instead of the default one),
# because it allows us to run nginx with a non-root user.
#
# For this to work, the default vhost file (`/etc/nginx/conf.d/default.conf`) also needs to be removed.
# (mounting `/dev/null` over `/etc/nginx/conf.d/default.conf` works well)
#
# The following changes have been done compared to a default nginx configuration file:
# - default server port is changed (80 -> 8080), so that a non-root user can bind it
# - various temp paths are changed to `/tmp`, so that a non-root user can write to them
# - the `user` directive was removed, as we don't want nginx to switch users
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

View file

@ -11,11 +11,17 @@ ExecStartPre=-/usr/bin/docker kill matrix-riot-web
ExecStartPre=-/usr/bin/docker rm matrix-riot-web
ExecStart=/usr/bin/docker run --rm --name matrix-riot-web \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--read-only \
--tmpfs=/tmp:rw,noexec,nosuid,size=10m \
-v {{ matrix_riot_web_data_path }}/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /dev/null:/etc/nginx/conf.d/default.conf:ro \
-v {{ matrix_riot_web_data_path }}/config.json:/etc/riot-web/config.json:ro \
-v {{ matrix_riot_web_data_path }}/home.html:/etc/riot-web/home.html:ro \
--network={{ matrix_docker_network }} \
{% if matrix_riot_web_container_expose_port %}
-p 127.0.0.1:8765:80 \
-p 127.0.0.1:8765:8080 \
{% endif %}
{{ matrix_riot_web_docker_image }}
ExecStop=-/usr/bin/docker kill matrix-riot-web

View file

@ -39,6 +39,9 @@ matrix_synapse_max_upload_size_mb: 10
matrix_synapse_max_log_file_size_mb: 100
matrix_synapse_max_log_files_count: 10
# The tmpfs at /tmp needs to be large enough to handle multiple concurrent file uploads.
matrix_synapse_tmp_directory_size_mb: "{{ matrix_synapse_max_upload_size_mb * 50 }}"
# Log levels
# Possible options are defined here https://docs.python.org/3/library/logging.html#logging-levels
# warning: setting log level to DEBUG will make synapse log sensitive information such

View file

@ -14,8 +14,10 @@
group: "{{ matrix_user_username }}"
when: "matrix_mautrix_telegram_enabled"
- stat: "path={{ matrix_mautrix_telegram_base_path }}/config.yaml"
register: mautrix_config_file
- name: Check if a mautrix-telegram configuration file exists
stat:
path: "{{ matrix_mautrix_telegram_base_path }}/config.yaml"
register: mautrix_telegram_config_file_stat
- name: Ensure Matrix Mautrix telegram config installed
template:
@ -24,7 +26,18 @@
mode: 0644
owner: "{{ matrix_user_username }}"
group: "{{ matrix_user_username }}"
when: "matrix_mautrix_telegram_enabled and mautrix_config_file.stat.exists == False"
when: "matrix_mautrix_telegram_enabled and not mautrix_telegram_config_file_stat.stat.exists"
- name: (Migration) Fix up old configuration
lineinfile:
path: "{{ matrix_mautrix_telegram_base_path }}/config.yaml"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backrefs: yes
with_items:
- {'regexp': '^(\s+)filename: \./mautrix-telegram.log', 'line': '\1filename: /data/mautrix-telegram.log'}
- {'regexp': '^(\s+)database:', 'line': '\1database: sqlite:////data/mautrix-telegram.db'}
when: "matrix_mautrix_telegram_enabled and mautrix_telegram_config_file_stat.stat.exists"
- name: Ensure matrix-mautrix-telegram.service installed
template:
@ -33,13 +46,23 @@
mode: 0644
when: "matrix_mautrix_telegram_enabled"
- stat:
- name: Check if a mautrix-telegram registration file exists
stat:
path: "{{ matrix_mautrix_telegram_base_path }}/registration.yaml"
register: mautrix_telegram_registration_file
register: mautrix_telegram_registration_file_stat
- name: Generate matrix-mautrix-telegram registration.yaml if it doesn't exist
shell: /usr/bin/docker run --rm --name matrix-mautrix-telegram-gen -v {{ matrix_mautrix_telegram_base_path }}:/data:z {{ matrix_mautrix_telegram_docker_image }} python3 -m mautrix_telegram -g -c /data/config.yaml -r /data/registration.yaml
when: "matrix_mautrix_telegram_enabled and mautrix_telegram_registration_file.stat.exists == False"
shell:
cmd: >-
/usr/bin/docker run
--rm
--user={{ matrix_user_uid }}:{{ matrix_user_gid }}
--cap-drop=ALL
--name matrix-mautrix-telegram-gen
-v {{ matrix_mautrix_telegram_base_path }}:/data:z
{{ matrix_mautrix_telegram_docker_image }}
python3 -m mautrix_telegram -g -c /data/config.yaml -r /data/registration.yaml
when: "matrix_mautrix_telegram_enabled and not mautrix_telegram_registration_file_stat.stat.exists"
- set_fact:
matrix_synapse_app_service_config_file_mautrix_telegram: '/app-registration/mautrix-telegram.yml'

View file

@ -14,8 +14,10 @@
group: "{{ matrix_user_username }}"
when: "matrix_mautrix_whatsapp_enabled"
- stat: "path={{ matrix_mautrix_whatsapp_base_path }}/config.yaml"
register: mautrix_config_file
- name: Check if a mautrix-whatsapp configuration file exists
stat:
path: "{{ matrix_mautrix_whatsapp_base_path }}/config.yaml"
register: mautrix_whatsapp_config_file_stat
- name: Ensure Matrix Mautrix whatsapp config installed
template:
@ -24,7 +26,7 @@
mode: 0644
owner: "{{ matrix_user_username }}"
group: "{{ matrix_user_username }}"
when: "matrix_mautrix_whatsapp_enabled and mautrix_config_file.stat.exists == False"
when: "matrix_mautrix_whatsapp_enabled and not mautrix_whatsapp_config_file_stat.stat.exists"
- name: Ensure matrix-mautrix-whatsapp.service installed
template:
@ -33,13 +35,23 @@
mode: 0644
when: "matrix_mautrix_whatsapp_enabled"
- stat:
- name: Check if a mautrix-whatsapp registration file exists
stat:
path: "{{ matrix_mautrix_whatsapp_base_path }}/registration.yaml"
register: mautrix_whatsapp_registration_file
register: mautrix_whatsapp_registration_file_stat
- name: Generate matrix-mautrix-whatsapp registration.yaml if it doesn't exist
shell: /usr/bin/docker run --rm --name matrix-mautrix-whatsapp-gen -v {{ matrix_mautrix_whatsapp_base_path }}:/data:z {{ matrix_mautrix_whatsapp_docker_image }} /usr/bin/mautrix-whatsapp -g -c /data/config.yaml -r /data/registration.yaml
when: "matrix_mautrix_whatsapp_enabled and mautrix_whatsapp_registration_file.stat.exists == False"
shell:
cmd: >-
/usr/bin/docker run
--rm
--user={{ matrix_user_uid }}:{{ matrix_user_gid }}
--cap-drop=ALL
--name matrix-mautrix-whatsapp-gen
-v {{ matrix_mautrix_whatsapp_base_path }}:/data:z
{{ matrix_mautrix_whatsapp_docker_image }}
/usr/bin/mautrix-whatsapp -g -c /data/config.yaml -r /data/registration.yaml
when: "matrix_mautrix_whatsapp_enabled and not mautrix_whatsapp_registration_file_stat.stat.exists"
- set_fact:
matrix_synapse_app_service_config_file_mautrix_whatsapp: '/app-registration/mautrix-whatsapp.yml'

View file

@ -41,6 +41,7 @@
SYNAPSE_SERVER_NAME: "{{ hostname_matrix }}"
SYNAPSE_REPORT_STATS: "no"
user: "{{ matrix_user_uid }}:{{ matrix_user_gid }}"
cap_drop: ['all']
volumes:
- "{{ matrix_synapse_config_dir_path }}:/data"
when: "not matrix_synapse_config_stat.stat.exists"

View file

@ -26,7 +26,7 @@ appservice:
# Format examples:
# SQLite: sqlite:///filename.db
# Postgres: postgres://username:password@hostname/dbname
database: sqlite:///mautrix-telegram.db
database: sqlite:////data/mautrix-telegram.db
# Public part of web server for out-of-Matrix interaction with the bridge.
# Used for things like login if the user wants to make sure the 2FA password isn't stored in
@ -253,7 +253,7 @@ logging:
file:
class: logging.handlers.RotatingFileHandler
formatter: precise
filename: ./mautrix-telegram.log
filename: /data/mautrix-telegram.log
maxBytes: 10485760
backupCount: 10
console:

View file

@ -9,12 +9,21 @@ After=matrix-synapse.service
Type=simple
ExecStartPre=-/usr/bin/docker kill matrix-mautrix-telegram
ExecStartPre=-/usr/bin/docker rm matrix-mautrix-telegram
ExecStartPre=/usr/bin/docker run --rm --name matrix-mautrix-telegram-db \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
-v {{ matrix_mautrix_telegram_base_path }}:/data:z \
{{ matrix_mautrix_telegram_docker_image }} \
alembic -x config=/data/config.yaml upgrade head
ExecStart=/usr/bin/docker run --rm --name matrix-mautrix-telegram \
--log-driver=none \
-e "UID={{ matrix_user_uid }}" -e "GID={{ matrix_user_gid }}" \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--network={{ matrix_docker_network }} \
-v {{ matrix_mautrix_telegram_base_path }}:/data:z \
{{ matrix_mautrix_telegram_docker_image }}
{{ matrix_mautrix_telegram_docker_image }} \
python3 -m mautrix_telegram -c /data/config.yaml
ExecStop=-/usr/bin/docker kill matrix-mautrix-telegram
ExecStop=-/usr/bin/docker rm matrix-mautrix-telegram
Restart=always

View file

@ -11,10 +11,13 @@ ExecStartPre=-/usr/bin/docker kill matrix-mautrix-whatsapp
ExecStartPre=-/usr/bin/docker rm matrix-mautrix-whatsapp
ExecStart=/usr/bin/docker run --rm --name matrix-mautrix-whatsapp \
--log-driver=none \
-e "UID={{ matrix_user_uid }}" -e "GID={{ matrix_user_gid }}" \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--network={{ matrix_docker_network }} \
-v {{ matrix_mautrix_whatsapp_base_path }}:/data:z \
{{ matrix_mautrix_whatsapp_docker_image }}
--workdir=/data \
{{ matrix_mautrix_whatsapp_docker_image }} \
/usr/bin/mautrix-whatsapp
ExecStop=-/usr/bin/docker kill matrix-mautrix-whatsapp
ExecStop=-/usr/bin/docker rm matrix-mautrix-whatsapp
Restart=always

View file

@ -18,26 +18,31 @@ ExecStartPre=-/usr/bin/docker rm matrix-synapse
# we'd write files to the local filesystem and fusermount will complain.
ExecStartPre=/bin/sleep 5
{% endif %}
ExecStart=/usr/bin/docker run --rm --name matrix-synapse \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--entrypoint=python \
--read-only \
--tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_synapse_tmp_directory_size_mb }}m \
--network={{ matrix_docker_network }} \
-e SYNAPSE_CONFIG_PATH=/data/homeserver.yaml \
-e SYNAPSE_CACHE_FACTOR={{ matrix_synapse_cache_factor }} \
-e UID={{ matrix_user_uid }} \
-e GID={{ matrix_user_gid }} \
{% if matrix_synapse_federation_enabled %}
-p 8448:8448 \
{% endif %}
{% if matrix_synapse_container_expose_client_server_api_port %}
-p 127.0.0.1:8008:8008 \
{% endif %}
-v {{ matrix_synapse_config_dir_path }}:/data \
-v {{ matrix_synapse_run_path }}:/matrix-run \
-v {{ matrix_synapse_config_dir_path }}:/data:ro \
-v {{ matrix_synapse_run_path }}:/matrix-run:rw \
-v {{ matrix_synapse_base_path }}/storage:/matrix-media-store-parent:slave \
{% for volume in matrix_synapse_container_additional_volumes %}
-v {{ volume.src }}:{{ volume.dst }}:{{ volume.options }} \
{% endfor %}
{{ matrix_synapse_docker_image }}
{{ matrix_synapse_docker_image }} \
-m synapse.app.homeserver -c /data/homeserver.yaml
ExecStop=-/usr/bin/docker kill matrix-synapse
ExecStop=-/usr/bin/docker rm matrix-synapse
Restart=always