General Information

This guide helps to install Synapse Matrix Server, Riot Web UI, coturn Turn Server, Dimension integration server, jitsi conferencing system and the matrix user/room admin tool. It assumes there is an apache web-server serving requests from the outside world.

None of the components or the information is originally mine. This is just an attempt to summarize all together in a long how-to.

Note 1: I will be installing all the docker packages at /home/*

Note 2: server.key, server.crt and ca.crt are respectively private key, public key, and certificate-authority certificate to be used by components. I usually have a wildcard certificate for all my subdomains. but if you don’t want to use such a certificate, then you need separate certificates when creating reverse-proxies or configuring your turn-server

Before we begin

You can consider installing portainer to ease the management of dockers. Unfortunately, the docker-compose files cannot be used directly in portainer, as it doesn’t support version: '3' and above. Nevertheless, it provides a nice UI to see the status of each container, to manage it, and to check out the logs.

This could (probably) be used to install portainer container. It will start a web-UI on port 9000 of the docker machine, through which it’s possible to restart, recreate, and modify containers, as well as defining new containers, seeing log files and performance statistics etc.

  • Installation path: /home/portainer
  • Don’t forget to map docker.sock to /var/run/docker.sock
  • Ports: 9000 for UI

Note: Please consider security factors when exposing this container to the internet, as any person with administrative right can install and modify your containers.

version: '3'
services: 
  portainer:
    image: portainer/portainer
    container_name: portainer
    restart: always
    command: -H unix:///var/run/docker.sock
    ports:
      - "9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /home/portainer/data:/data
      - /home/portainer/shared:/shared
    environment:
      - TZ=${TZ}

Configure Turn Server

Let’s start with coturn TURN-Server. it’s independent of other components and can be used for several different purposes.

You can read more about the functionality of TURN and STUN servers here: https://blog.ivrpowers.com/post/technologies/what-is-stun-turn-server/

  • Original Documentation: https://github.com/instrumentisto/coturn-docker-image
  • Installation Path: /home/coturn
  • needed ports: 3478, 5349, 49100-49200
  • docker image: instrumentisto/coturn
  • network_mode is set to host in order to ease the mapping of ports from the container to the outside world.
  • Configuration files are stored in {installation-path}/conf
  • SSL keys and certificates are to be stored in {installation-path}/keys
  • docker-compose.yml as provided
#/home/coturn/docker-compose.yml
version: '3'
services:
   coturn:
      restart: unless-stopped
      container_name: coturn
      image: instrumentisto/coturn
      network_mode: host
      volumes:
          - /home/coturn/conf:/etc/coturn/
          - /home/coturn/keys:/data/keys/
          - /home/coturn/log:/data/log/
  • data/turnserver.conf as provided
    • define your-domain.com
    • static-auth-secret can be any string. I’d recommend selecting a fully randomized hash with a length of at least 32 to ensure security. OpenSSL can be used to create a random value:
      • openssl rand -hex 64 or openssl rand -base64 64
    • define the external-IP to point to your public IP if the server is behind NAT
    • listening-port, tls-listening-port and min|max-port must be opened on outwards facing firewall
#/home/coturn/data/turnserver.conf
listening-port=3478
tls-listening-port=5349
external-ip=<public-ip>[/<private-ip>] #defines a mapping between public and private IPs
min-port=49100
max-port=49200
fingerprint
use-auth-secret
static-auth-secret=<create-your-own>
realm=<your-domain.com>
user-quota=12
total-quota=1200
max-bps=4096000
no-tcp-relay
stale-nonce=600
cert=/data/keys/server.crt
pkey=/data/keys/server.key
CA-file=/data/keys/ca.crt
cipher-list="ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5"
no-tlsv1
no-tlsv1_1
no-sslv3
log-file=/data/log/turn.log
no-multicast-peers
#user=username;password

Matrix-Synapse

Configuring Home-Server

Based on the documentation provided in https://github.com/matrix-org/synapse/blob/master/docker/README.md, it’s a relatively straight-forward job to install the docker container.

  • Installation path: /home/synapse
    • the /home/synapse/data folder must be writable by the container. Usually the 991:991 user:group combination needs to have write-permissions. If this is not guaranteed, the creation of homeserver.db (the database created by the internal sqlite db) will fail and matrix fails to start properly.
  • The first step is to create a new sample homeserver.yaml file using following command. <your-domain.com> is the domain name of your matrix server, and also will be the suffix for your users (@username:<your-domain.com>).
docker run -it --rm -v/home/synapse/data:/data \
    -e SYNAPSE_SERVER_NAME=<your-domain.com> \
    -e SYNAPSE_REPORT_STATS=yes \
    matrixdotorg/synapse:latest generate
  • Following changes are necessary in order to configure the homeserver.
    • openid resource is used by dimension integration server. It should be added to the listeners.resources.names.
    • Provided config causes the server to listen for http connections on port 8008.
    • public_baseurl MUST not be the same as your server_name, but it would make things easier, as the synapse server provides a minimum /.well-known/matrix path.
    • turn_uris (their URL and port) and turn_shared_secret must be set according to the configuration of the turn-server.
    • It’s possible to configure an email server for synapse, in order to allow it to send emails on registrations or other events. client_base_url can point to the riot web-client.
#/home/synapse/data/homeserver.yaml
server_name: "<your-domain.com>"
pid_file: /data/homeserver.pid
public_baseurl: https://<your-domain.com>/
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation,openid]
        compress: false
turn_uris: ["turns:<your-turnserver.com>:5349?transport=udp", "turns:<your-turnserver.com>:5349?transport=tcp", "turn:<your-turnserver.com>:3478?transport=udp", "turn:<your-turnserver.com>:3478?transport=tcp"]
turn_shared_secret: "<your-static-auth-secret-from-turnserver>"
email:
  smtp_host: <your-mail-server.com>
  smtp_port: <smtp-port>
  smtp_user: "<smtp-user>"
  smtp_pass: "<smtp-pass>"
  # require_transport_security: true
  notif_from: "Your Server's Name <your-address@your-domain.com>"
  app_name: "Your Application Name"
  enable_notifs: false
  client_base_url: "<your-riot-url>"
  validation_token_lifetime: 15m
  • docker-compose can be as followed:
services:
  synapse:
    image: matrixdotorg/synapse:latest
    restart: unless-stopped
    container_name: matrix-synapse
    environment:
      - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
    volumes:
      # You may either store all the files in a local folder
      - /home/synapse/data:/data
      # .. or you may split this between different storage points
      # - ./files:/data
      # - /path/to/ssd:/data/uploads
      # - /path/to/large_hdd:/data/media
     ports:
      - 8008:8008/tcp
    #depends_on:
    #  - syanpse-db

Note: It’s possible to use an external database instead of the internal sqlite delivered with the image. It’s possible to use external (also docker container) databases. Please check https://github.com/matrix-org/synapse#using-postgresql and https://github.com/matrix-org/synapse/blob/master/docs/postgres.md for more info and an example on how to use PostgreSQL.

Configuring Synapse Reverse Proxy

Next step is to configure the reverse proxy for synapse server. for detailed info, please visit https://github.com/matrix-org/synapse#using-a-reverse-proxy-with-synapse.

In this guide, the federation port will be the same as the client connection port. Therefore, it’s not necessary to configure the port 8448. In addition to the /_matrix path, there is a reverse-proxy configured for /_synapse which can be used by synapse-admin or other tools to manage the users and other properties of synapse.

  • Don’t forget to replace <synapse-internal-ip> with the IP address of the docker-machine.
  • This config assumes that the http listener is running on port 8008 of the synapse server.
  • It also ensures that the _matrix and _synapse resources are not cached by browsers.
  • The first VirtualHost is there to redirect all http requests to https.
<VirtualHost *:80>
	ServerName <your-domain.com>
	<IfModule rewrite_module>
		RewriteEngine on
		RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
	</IfModule>
</VirtualHost>

<VirtualHost *:443>
        ServerName <your-domain.com>;

        AllowEncodedSlashes NoDecode
        ProxyPass /_matrix http://<synapse-internal-ip>:8008/_matrix nocanon
        ProxyPassReverse /_matrix http://<synapse-internal-ip>:8008/_matrix
        ProxyPass /_synapse http://<synapse-internal-ip>:8008/_synapse nocanon
        ProxyPassReverse /_synapse http://<synapse-internal-ip>:8008/_synapse
        <LocationMatch "^/(_matrix|_synapse)">
		<IfModule mod_headers.c>
			Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
			Header set Pragma "no-cache"
		</IfModule>
	</LocationMatch>
	
        SSLEngine On
	SSLCertificateFile "</path/to/server.crt>"
	SSLCertificateKeyFile "</path/to/server.key>"
	SSLCertificateChainFile "</path/to/ca.crt>"
</VirtualHost>

Creating a new user – Main Admin Account

After configuring the synapse server, it’s necessary to create at least one admin user, in order to be able to use the synapse admin tool. To do so, please use docker exec -it matrix-synapse register_new_matrix_user -c /data/homeserver.yaml https://<server_name> and follow the instructions. Type ‘yes’ if you want to create an admin user. Please note:

  1. matrix-synapse is the name assigned to the synapse server using container_name in respective docker-compose.yml. The name might vary if you have not used that config.
  2. <server_name> should be the same as in your homeserver.yaml.
  3. /data/homeserver.yaml might need to be adjusted according to your configurations.

for more information, please visit https://github.com/matrix-org/synapse/blob/master/INSTALL.md#registering-a-user.

Providing .well-known Service Discovery

Synapse server automatically provides minimal discovery data via /.well-known/matrix/client file. But this might not be enough depending on the needs.

One way to provide this information is to manually create and manage JSON files under /.well-known/matrix/{client|server} files.

To do so:

  • create the path /.well-known/matrix on web-server
  • create the .htaccess file and make sure the web-server is set to consider it.
    • .htaccess is needed to ensure proper CORS headers on client and server files, without which the web-clients and other servers won’t be able to use the discovery information.
    • following headers can be set in .htaccess
#/.well-known/matrix/.htaccess
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
  • create /.well-known/matrix/client with the following contents. this defines where the clients should look for client-server communication with synapse server.
{
  "m.homeserver": {
    "base_url": "https://<server_name>"
  }
}
  • if a local jitsi server is to be used by clients while trying to create conference calls, please add following config to the client file as a new JSON property. Please remember, that the <your-jitsi-domain> doesn’t need the https:// prefix.
"im.vector.riot.jitsi":{
"preferredDomain": "<your-jitsi-domain>"
}
  • Create /.well-known/matrix/server with following contents. this defines the federation information for other servers. if this is not defined, other servers use port 8448 per default to get information when federating, which has not been enabled by the configuration provided here. It’s also only needed to some extent, as the synapse server is already behind our https enabled reverse-proxy.
{
  "m.server":  "<server_name>:443"
}

More information on .well-known server discovery can be found in https://matrix.org/docs/spec/client_server/latest#well-known-uri.

More Information on necessary CORS headers for matrix can be found in https://matrix.org/docs/spec/client_server/latest#cors.

More information on federation delegation and server-server connections can be found in https://github.com/matrix-org/synapse/blob/master/docs/delegate.md.

Installing Synapse-Admin

In order to ease matrix user management, I’d recommend using awesometechnologies/synapse-admin. It’s really easy to install and use.

Note 1: Please do not deactivate users. It’s not possible to reactivate them.

Note 2: Please be careful when exposing this sub-system to the internet. if your admin password is leaked or cracked, then your matrix server can be compromised.

#/home/synapse-admin/docker-compose.yml
version: '3'

services:
  synapse-admin:
    image: awesometechnologies/synapse-admin
    container_name: synapse-admin
    ports:
      - 8001:80

Dimension Integration Server

Installation

Integration servers provide extra services to matrix users. You can read more about integration server for example in https://github.com/turt2live/matrix-dimension.

At the moment, only riot web and desktop can use the services from dimension integration server.

The instructions on the website are pretty good, but a summary here:

  • Installation path: /home/dimension
    • The /home/dimension/data folder should be writable from the docker. if the container cannot start, please check the logs to see if the /data/bot.json file is writable; that might be the cause behind the issue.
  • Ports: 8184 for http requests from clients
  • Before starting the container, create the config.yaml file.
    • Create a user for dimension on matrix server. Its token is needed for configuration of dimension. To obtain the token, login with the user using riot-desktop client, click on the user, go to Settings > Help & About and scroll to the Advanced section. The Access Token can be found there. The token must be provided in accessToken as <dimension-user-token>.
    • homeserver.name is the your matrix’ server_name.
    • homeserver.clientServerUrl is the same as defined in .well-known service discovery’s homeserver.base_url.
    • dimension.baseUrl (<your-dimension-domain.com>) is the (sub-)domain, on which your dimension server is accessible. something like dimension.<your-domain.com>
    • admins is a list of users with administrative rights in matrix-synapse who are allowed to configure and add integration services.
    • web parameters can be left as they are, as there will be a reverse proxy entry for this server’s access over the internet.
#/home/dimension/docker-compose.yml
version: "3"

services:
  dimension:
    container_name: 'dimension'
    image: turt2live/matrix-dimension
    ports:
      - 8184:8184
    volumes:
      - /home/dimension/data/:/data/
#/home/dimension/data/config.yaml
web:
  port: 8184
  address: '0.0.0.0'
homeserver:
  name: "<your-domain.com>"
  clientServerUrl: "https://<your-domain.com>"
  accessToken: "<dimension-user-token>"
admins:
  - "<matrix-admin-user>"
widgetBlacklist:
  - 10.0.0.0/8
  - 172.16.0.0/12
  - 192.168.0.0/16
  - 127.0.0.0/8
database:
  file: "/data/dimension.db"
  botData: "/data/bot.json"
goneb:
  avatars:
    giphy: "mxc://t2bot.io/c5eaab3ef0133c1a61d3c849026deb27"
    imgur: "mxc://t2bot.io/6749eaf2b302bb2188ae931b2eeb1513"
    github: "mxc://t2bot.io/905b64b3cd8e2347f91a60c5eb0832e1"
    wikipedia: "mxc://t2bot.io/7edfb54e9ad9e13fec0df22636feedf1"
    travisci: "mxc://t2bot.io/7f4703126906fab8bb27df34a17707a8"
    rss: "mxc://t2bot.io/aace4fcbd045f30afc1b4e5f0928f2f3"
    google: "mxc://t2bot.io/636ad10742b66c4729bf89881a505142"
    guggy: "mxc://t2bot.io/e7ef0ed0ba651aaf907655704f9a7526"
    echo: "mxc://t2bot.io/3407ff2db96b4e954fcbf2c6c0415a13"
    circleci: "mxc://t2bot.io/cf7d875845a82a6b21f5f66de78f6bee"
    jira: "mxc://t2bot.io/f4a38ebcc4280ba5b950163ca3e7c329"
stickers:
  enabled: true
  stickerBot: "@stickers:t2bot.io"
  managerUrl: "https://stickers.t2bot.io"
dimension:
  publicUrl: "https://<your-dimension-domain.com>"
logging:
  file: /data/logs/dimension.log
  console: true
  consoleLevel: info
  fileLevel: verbose
  rotate:
    size: 52428800 # bytes, default is 50mb
    count: 5

Reverse proxy for dimension

  • define following virtual-host in APACHE.
    • The <dimension-internal-ip> is the IP address of the Docker server, on which the dimension server is installed.
    • Port 8148 is the same as in config.yaml mention in the installation guide above.
    • <your-dimension-domain.com> is also defined in the last step.
  • After restarting APACHE, check the configuration by visiting https://<your-dimension-domain.com>. There should be a page defining how to configure riot web-ui.
  • The first VirtualHost ensures that all traffic goes over HTTPS.
<VirtualHost *:80>
	ServerName <your-dimension-domain.com>
	<IfModule rewrite_module>
		RewriteEngine on
		RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
	</IfModule>
</VirtualHost>

<VirtualHost *:443>
        SSLEngine on
        ServerName <your-dimension-domain.com>;

        ProxyPass / http://<dimension-internal-ip>:8148/
        ProxyPassReverse / http://<dimension-internal-ip>:8148/
	ProxyRequests On
	
        SSLEngine On
	SSLCertificateFile "</path/to/server.crt>"
	SSLCertificateKeyFile "</path/to/server.key>"
	SSLCertificateChainFile "</path/to/ca.crt>"
</VirtualHost>

Riot Web Client

Installation

The https://riot.im/app/ web-application can work with a self-hosted server as long as the server is available over the internet. but it’s not that “nice” to provide that link to customers or even friends as it might cause some confusion when trying to configure the home-server and other features.

It’s possible to use a self-hosted version of riot web-ui to customize the feeling. This can be done using following guide or by reading the configuration reference in https://github.com/vector-im/riot-web/blob/develop/docs/config.md:

  • Installation path: /home/riot/
  • Ports: 8080 for http connections
  • Mapping /app/themes/<your-theme> is not necessary, but if you want to customize the experience, like adding your own logo and background, it’s easier to manage this folder. For more information on customization, please check the config-reference, the part with branding.
  • Either create an empty /home/riot/data/config.json or copy the example from https://riot.im/develop/config.json and start modifying/adding the configurations you want.
    • a minimal/ optimal example can be found here below.
#/home/riot/docker-compose.yml
version: '3'

services:
  riot-ui:
    image: vectorim/riot-web
    container_name: riot-ui
    restart: unless-stopped
    volumes:
      - /home/riot/data/config.json:/app/config.json
      - /home/riot/data/themes/<your-theme>/:/app/themes/<your-theme>
    ports:
      - 8080:80
  • A complete list of configuration and their functionality can be found in the configuration reference mentioned above. My minimal config.json is as follows.
    • if you don’t have your own jitsi server, you can omit the jitsi config part. In that case, riot uses jitsi.riot.im when creating conference rooms.
    • you need to define <your-riot-domain.com>, which is going to be used below when creating the reverse-proxy.
    • if you want to have your permalinks and share links to be served from your own domain, please set permalinkPrefix to <your-riot-domain.com>, otherwise you can use the default value (which points to matrix.to) by omitting the option.
{
    "default_server_name": "<your-domain.com>",
    "piwik":false,
    "brand": "<your riot's name - appearing in title bar>",
    "disable_guests":true,
    "default_federate": false,
    "disable_custom_urls":true,
    "branding":{
        "authHeaderLogoUrl":"/themes/<your-theme>/<your-logo>",
        "welcomeBackgroundUrl":[
            "/themes/<your-theme>/<your 1st bg>",
            "/themes/<your-theme>/<your 2nd bg>",
            ...
        ]
    },
    "integrations_ui_url": "https://<your-dimension-domain.com>/riot",
    "integrations_rest_url": "https://<your-dimension-domain.com>/api/v1/scalar",
    "integrations_widgets_urls": [
        "https://<your-dimension-domain.com>/widgets"
    ],
    "integrations_jitsi_widget_url":"https://<your-dimension-domain.com>/widgets/jitsi",
    "hosting_signup_link": "",
    "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
    "features": {
        "feature_pinning": "labs",
        "feature_custom_status": "labs",
        "feature_custom_tags": "labs",
        "feature_state_counters": "labs",
        "feature_many_integration_managers": "labs",
        "feature_mjolnir": "labs",
        "feature_dm_verification": "labs",
        "feature_cross_signing": "enable",
        "feature_invite_only_padlocks": "enable",
        "feature_event_indexing": "disable",
        "feature_bridge_state": "labs",
        "feature_presence_in_room_list": "labs",
        "feature_custom_themes": "labs"
    },
    "roomDirectory": {
        "servers": [
            "<your-domain.com>"
        ]
    },
    "enable_presence_by_hs_url": {
        "https://<your-domain.com>": true
    },
    "jitsi":{
        "prefferedDomain":"<your-jitsi-domain.com-without-https>"
    },
    "permalinkPrefix":"https://<your-riot-domain.com>",
    "terms_and_conditions_links": [
        {
            "url": "https://riot.im/privacy",
            "text": "Privacy Policy"
        },
        {
            "url": "https://matrix.org/legal/riot-im-cookie-policy",
            "text": "Cookie Policy"
        }
    ]
}

Reverse Proxy

  • as always, I’ll assume the port on which riot runs is the same as in provided configuration (i.e. 8080)
  • <riot-internal-ip> should be the IP address of the docker machine.
  • riot will be accessible on <your-riot-domain.com>/
  • Again, the first VirtualHost is there to redirect all your traffic over https.
<VirtualHost *:80>
	ServerName <your-riot-domain.com>
	<IfModule rewrite_module>
		RewriteEngine on
		RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
	</IfModule>
</VirtualHost>
<VirtualHost *:443>
	ServerName <your-riot-domain.com>
	ProxyPass / http://<riot-internal-ip>:8080/
	ProxyPassReverse / http://<riot-internal-ip>:8080/
	ProxyRequests On
	
        SSLEngine On
	SSLCertificateFile "</path/to/server.crt>"
	SSLCertificateKeyFile "</path/to/server.key>"
	SSLCertificateChainFile "</path/to/ca.crt>"
</VirtualHost>

Jitsi Conferencing tool

Installation

Jitsi installation follows the instructions on the DevOPs Guide (Docker) from Jitsi Meet Handbook found at https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker. The ports and configuration paths can be changed as needed (as done in my instance).

Note 1: At the moment, it’s not possible to somehow protect the rooms created by riot. The rooms made by riot will not be password protected and as riot cannot use prosody‘s user list, it’s not possible to protect jitsi rooms per default, which means anyone who knows there is a jitsi server on your machine, can connect to it and use is as a conferencing tool.

Note 2: Please make sure port 10000/udp (the same port as in JVB_PORT in .env) is also open, otherwise, your calls will drop constantly.

  • Installation Path: /home/jitsi
  • create the installation path, go it and clone jitsi/docker-jitsi-meet into it using: git clone https://github.com/jitsi/docker-jitsi-meet .. Please note, that the . in the command is mandatory to force cloning into the current directory, which it’s supposed be /home/jitsi.
  • copy env.example to .env.
  • use ./gen-passwords.sh to automatically create randomized password strings for the .env file.
  • create config directories {web/letsencrypt,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} under jitsi-meet-cfg.
  • go through .env parameters and check their validity or configure as needed. A list of available configurations can be found in the link posted above, but here an overview of the “important” ones:
    • CONFIG is the path to your local configuration paths (defined in last step under jitsi-meet-cfg).
    • TZ is your timezone
    • HTTP_PORT and HTTPS_PORT are the ports which are to be exposed respectively for http and https connections on docker.
    • PUBLIC_URL is where your jitsi UI is located. something like https://<your-jitsi-domain.com>
    • you can enable let's encrypt if you want to forward requests directly to jitsi, or you can use the reverse proxy and define your certificates on that – as with the previous dockers.
    • JVB_PORT is the Jitsi-VideoBridge port, mentioned above, which needs to be accessible from the outside world, otherwise, the video connections will drop constantly.
  • there is no need to change docker-compose.yml, as it uses the .env variables.

Reverse Proxy

<VirtualHost *:443>
	ServerName <your-jitsi-domain.com>
	ProxyPass / https://<jitsi-internal-ip>:8043/
	ProxyPassReverse / https://<jitsi-internal-ip>:8043/
	ProxyRequests On
	SSLProxyEngine on
	SSLProxyVerify none
	SSLProxyCheckPeerCN Off
	SSLProxyCheckPeerName Off
	SSLProxyCheckPeerExpire Off
		
	SSLEngine On
	SSLCertificateFile "</path/to/server.crt>"
	SSLCertificateKeyFile "</path/to/server.key>"
	SSLCertificateChainFile "</path/to/ca.crt>"
</VirtualHost>

Comments are closed, but trackbacks and pingbacks are open.