Skip to content

raspberry pi en

Marcel Waldvogel edited this page Aug 23, 2018 · 45 revisions

Your personal autonomous federated file, calendar, and chat server

🇩🇪 Diesen Artikel auf Deutsch lesen

aka Setup of Nextcloud+JSXC+ejabberd on a Raspberry Pi

…or any other computer running Debian Stretch or Ubuntu 18.04 LTS aka bionic. For any other setup, follow the generic instructions in the wiki.

⚠️ If you use an older distribution, please install the latest ejabberd manually instead of using the distribution-provided version.

Basic setup

  • On your Router:
    • Assign the Raspberry Pi an (internal) fixed IP address
    • Forward ports 80, 443, 5222, 5223, 5269, and 7777 on the router to the Raspberry Pi
    • Activate DynDNS with a Provider (assuming you have a dynamic IP address only)
    • If possible, add the following DNS entries. Even without them, 1:1 text and video chat works, but you will experience the following restrictions:
      • Group chats: Are only possible between local users; members in the federation cannot join your group chats
      • Social network functions on top of XMPP will not work, e.g. those provided by Movim
  • On the Raspberry Pi
    • Install Raspbian Stretch
    • Optional: Attach an external disk and mount it at /var/www/nextcloud/data (after creating the path)

In the following code snippets, a capital SERVERNAME should be replaced with the name you got from your DynDNS provider.

Install the software

  • Log in to the Raspberry Pi using ssh from a Terminal window (on Windows, use putty)
    User name: "pi" Passwort: "raspberry"

  • Change the password using the passwd command, before anyone else takes control of your device

  • All the following commands will be executed as the superuser: sudo -s

  • Install the software (Apache+PHP, Let's Encrypt/CertBot, ejabberd, and git)

apt update && apt upgrade
apt install dirmngr
echo deb http://http.debian.net/debian stretch-backports main > /etc/apt/sources.list.d/backports.list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8B48AD6246925553
echo deb https://dl.jsxc.org nightly main > /etc/apt/sources.list.d/jsxc.list
wget -qO - https://dl.jsxc.org/archive.key | apt-key add -
apt update
apt install apache2 libapache2-mod-php php-gd php-json php-sqlite3 php-curl php-mbstring php-intl php-imagick php-xml php-zip
apt install python-certbot-apache ejabberd xcauth

⚠️ If you have trouble with the PHP modules, check the Nextcloud installation instructions

cd /var/www
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
tar xfj latest.tar.bz2
chown -R www-data:www-data nextcloud
rm latest.tar.bz2

See also the offical Nextcloud install instructions.

Configuration of Apache including HTTPS

Replace the contents of /etc/apache2/sites-available/000-default.conf with (adapted from the Nextcloud admin documentation:

<VirtualHost *:80>
  ServerName SERVERNAME

  DocumentRoot /var/www/nextcloud
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  ProxyPass /http-bind/ http://localhost:5280/http-bind/
  ProxyPassReverse /http-bind/ http://localhost:5280/http-bind/
  ProxyPreserveHost On
</VirtualHost>

<Directory /var/www/nextcloud/>
  Options +FollowSymlinks
  AllowOverride All

 <IfModule mod_dav.c>
  Dav off
 </IfModule>

 SetEnv HOME /var/www/nextcloud
 SetEnv HTTP_HOME /var/www/nextcloud
</Directory>

Create a new file /etc/apache2/sites-available/userdata.conf with these contents:

<VirtualHost *:80>
  ServerName userdata.SERVERNAME
  # Mostly to satisfy certbot
  ServerAlias conference.SERVERNAME pubsub.SERVERNAME
  # This DocumentRoot is irrelevant, but match ejabberd.conf anyway
  DocumentRoot /var/userdata
  ErrorLog ${APACHE_LOG_DIR}/userdata_error.log
  CustomLog ${APACHE_LOG_DIR}/userdata_access.log combined
  ProxyPass / http://localhost:5288/
  ProxyPassReverse / http://localhost:5288/
  ProxyPreserveHost On
</VirtualHost>

Finalize the configuration:

mkdir --mode=660 /var/www/userdata
chown ejabberd:ejabberd /var/www/userdata
a2enmod headers env dir mime proxy proxy_http
mkdir /var/userdata
a2ensite userdata

Activate HTTPS encryption (and automatic certificate renewal):

(if you did not obtain the extra DNS entries, then instead of the certbot line below, use certbot run --authenticator standalone --installer apache --redirect --uir --hsts --staple-ocsp -d $S)

S=SERVERNAME
apache2ctl stop
certbot run --authenticator standalone --installer apache --redirect --uir --hsts --staple-ocsp -d $S -d userdata.$S -d conference.$S -d pubsub.$S
chgrp -R ssl-cert /etc/letsencrypt/{archive,live}
chmod -R g+rX,o-rwx /etc/letsencrypt/{archive,live}
apache2ctl start

Configure Nextcloud

Point your Webbrowser to the host name and configure Nextcloud (keep sqlite as the database for now; if you want, you can change it later, if the need arises). Install the JSXC App (JavaScript XMPP Client in social).

Create (at least) two users for the following experiments.

👀 Milestone 1: Try the internal chat

Log in as two of the users and send messages or start a video chat. For this, we recommend two separate machines. Two machines are required for video chat, but if you use a different browser (e.g., Firefox and Chrome) for each of the users, sending text messages does not require a second machine.

😢 Disadvantage: This is a closed system and only works inside Nextcloud, not between different servers and only from the browser.

Activate federated chat

NextcloudSettingsJavaScript XMPP Client: Switch to Managed Chat, click Register. (This takes about 30 seconds; most of it is waiting for the required Let's Encrypt certificates.)

👀 Milestone 2a: Try federated chat

  • In the workshop, talk among users from different Raspberries.
  • At home, talk to someone who already has an XMPP account somewhere else.
  • If your friends are not yet into XMPP, create a free account on a public XMPP server such as Movim or Chinwag

Chat between these Nextcloud/JSXC instances (text or video). Z.B. zwischen [email protected] und [email protected] (:warning: For users on the managed server, the domain ends in jsxc.ch!)

👀 Milestone 2b: Federated file sharing

📌 The commands in this section can be skipped, if you do not know a user which has another Nextcloud+JSXC+XMPP server. Then, just read it to know the motivation for the following steps.

Of course, Nextcloud also allows you to share files between the instances as part of their file sharing function.

Share files or directories between the users user1@SERVERNAME und user2@SOME-OTHER-SERVERNAME

😢 Disadvantage: The domain name differs between applications, as the servers providing the services (files or chat) are under different management. This is, because the managed server is operated somewhere else (and provides domains ending in jsxc.ch).

Set up your own XMPP server on the Raspberry Pi under your own Domain

This setup will result in a server which achieves 100% compatibility in the Conversations Compliance Chart.

Replace the contents of /etc/ejabberd/ejabberd.yml with the following:

define_macro:
  'CIPHERS': "ECDH:DH:!3DES:!aNULL:!eNULL:!MEDIUM@STRENGTH:!AES128"
  'TLSOPTS':
    - "no_sslv3"
  # generated with: openssl dhparam -out dhparams.pem 2048
  'DHFILE': "/etc/ejabberd/dhparams.pem" 

certfiles:
  - "/etc/letsencrypt/live/*/fullchain.pem"
  - "/etc/letsencrypt/live/*/privkey.pem"
s2s_use_starttls: required
s2s_protocol_options: 'TLSOPTS'
s2s_ciphers: 'CIPHERS'
s2s_dhfile: 'DHFILE'
c2s_dhfile: 'DHFILE'

hosts:
  - "SERVERNAME"

loglevel: 4
log_rotate_size: 10485760
log_rotate_date: ""
log_rotate_count: 1
log_rate_limit: 100
trusted_proxies:
  - "127.0.0.1"
  - "::1"
  - "localhost"
  - "::FFFF:127.0.0.1" # This is the one which works here, but others might catch in other environments
auth_method: external
extauth_program: "/usr/bin/socket localhost 23662"
auth_use_cache: false

shaper:
  normal: 1000
  fast: 50000
  proxy: 1000000
max_fsm_queue: 1000
acl:
  admin:
    user:
# Replace with the server admins you want
#      - "admin1@SERVERNAME"
#      - "admin2@SERVERNAME"
  local:
    user_regexp: ""
  loopback:
    ip:
      - "127.0.0.0/8"
  proxy65_access:
    local: allow
    all: deny
  proxy65_shaper:
    admin: none
    proxy_users: proxyrate

shaper_rules:
  ## Maximum number of simultaneous sessions allowed for a single user:
  max_user_sessions: 10
  ## Maximum number of offline messages that users can have:
  max_user_offline_messages:
    - 5000: admin
    - 500
  ## For C2S connections, all users except admins use the "normal" shaper
  c2s_shaper:
    - none: admin
    - normal
  ## All S2S connections use the "fast" shaper
  s2s_shaper: fast
access_rules:
  ## This rule allows access only for local users:
  local:
    - allow: local
  ## Only non-blocked users can use c2s connections:
  c2s:
    - deny: blocked
    - allow
  ## Only admins can send announcement messages:
  announce:
    - allow: admin
  ## Only admins can use the configuration interface:
  configure:
    - allow: admin
  ## Only accounts of the local ejabberd server can create rooms:
  muc_create:
    - allow: local
  ## Only accounts on the local ejabberd server can create Pubsub nodes:
  pubsub_createnode:
    - allow: local
  ## In-band registration allows registration of any possible username.
  ## To disable in-band registration, replace 'allow' with 'deny'.
  register:
    - deny
  ## Only allow to register from localhost
  trusted_network:
    - allow: loopback
api_permissions:
  "console commands":
    from:
      - ejabberd_ctl
    who: all
    what: "*"
  "admin access":
    who:
      - access:
          - allow:
            - ip: "127.0.0.1/8"
            - acl: admin
      - oauth:
        - scope: "ejabberd:admin"
        - access:
          - allow:
              - ip: "127.0.0.1/8"
              - acl: admin
    what:
      - "*"
      - "!stop"
      - "!start"
  "public commands":
    who:
      - ip: "127.0.0.1/8"
    what:
      - "status"
      - "connected_users_number"
language: "en"

modules: # See manual
  # Ad-Hoc Commands (XEP-0050)
  mod_adhoc: {}
  # Additional ejabberdctl commands
  mod_admin_extra: {}
  # Send global announcements
  mod_announce: # recommends mod_adhoc
    access: announce
  # Transparently convert between vcard and pubsub avatars
  mod_avatar: {} # Requires ejabberd >= 17.09, mod_vcard, mod_vcard_xupdate, mod_pusub
  # Simple Communications Blocking (XEP-0191)
  mod_blocking: {} # requires mod_privacy
  # Exchange entity (client) capabilities, e.g. Jingle (XEP-0115)
  mod_caps: {}
  # Send messages to all clients of a user (XEP-0280)
  mod_carboncopy: {}
  # Queue and filter stanzas for inactive clients (improves mobile client battery life, XEP-0352)
  mod_client_state: {}
  # Server configuration with Ad-Hoc commands
  mod_configure: {} # requires mod_adhoc
  # Service discovery, e.g. for MUC, Pub/Sub, HTTP Upload (XEP-0030)
  # (and, announcing an abuse contact)
  mod_disco:
    server_info:
    -
      modules: all
      name: "abuse-address"
      urls: ["mailto:abuse@SERVERNAME"]
  # (XMPP over) BOSH: HTTP tunneling for web clients such as JSXC (XEP-0124, XEP-0206)
  mod_bosh: {}
  # Last activity (XEP-0012)
  mod_last: {}
  # Message Archive Management (XEP-0313): Allows clients to catch up
  mod_mam:
    default: roster
  # Queue messages for offline users (XEP-0160)
  mod_offline:
    access_max_user_messages: max_user_offline_messages
  # XMPP Ping and periodic keepalives (XEP-0199)
  mod_ping: {}
  # Limit status spam (a full presence authorization requires 4 messages)
  # See also Anti-Spam Workshop
  mod_pres_counter:
    count: 50
    interval: 600
  # Block some senders (XEP-0016)
  mod_privacy: {}
  # Private XML storage (XEP-0049)
  mod_private: {}
  # Allow direct file transfer (obsoleted by HTTP upload, but required by the XMPP Compliance Suite)
  # Needs restart, not just reload when changing ip/port
  mod_proxy65:
    host: "proxy.@HOST@"
    name: "File Transfer Proxy"
    ip: "::"
    port: 7777
    max_connections: 10
    auth_type: plain
    access: local
    shaper: proxy65_shaper
  # Allows clients to request push notifications
  mod_push: {} # Requires ejabberd >= 17.08
  # The roster. You want this. With versioning.
  mod_roster:
    versioning: true
    store_current_id: true
  # If you want to pre-configure rosters for workgroups
  mod_shared_roster: {}
  # Allow users to create a vcard, visible to authorized peers (XEP-0054)
  mod_vcard:
    search: false # Privacy
  # vcard-based Avatars (XEP-0153)
  mod_vcard_xupdate: {}
  # Return version information
  mod_version: {}
  # Stream management (XEP-0198): Continuity after network interruptions
  mod_stream_mgmt: {}
  # Ask for a dialback, if the certificate does not match (XEP-0220)
  mod_s2s_dialback: {}

  # Additional services

  # Publish/subscribe, e.g. for Movim
  mod_pubsub:
    host: "pubsub.@HOST@" # "hosts:" for multiple pubsub services
    access_createnode: local
    ignore_pep_from_offline: false
    last_item_cache: false
    max_items_node: 1000
    default_node_config:
      max_items: 1000
    plugins:
      - "flat"
      - "pep" # Requires mod_caps.
  # Multi-User (group) Chat
  mod_muc:
    host: "conference.@HOST@"
    access:
      - allow
    access_admin:
      - allow: admin
    access_create: muc_create
    access_persistent: muc_create
  # File transfer via HTTP Upload
  mod_http_upload:
    host: "userdata.@HOST@"
    docroot: "/var/userdata/" # Or wherever you would like to have them stored
    put_url: "https://userdata.@HOST@/ud"
    custom_headers:
      "Access-Control-Allow-Origin": "*"
      "Access-Control-Allow-Methods": "OPTIONS, HEAD, GET, PUT"
      "Access-Control-Allow-Headers": "Content-Type"
  # Expire files on server after specified period
  mod_http_upload_quota:
    max_days: 30

listen:
  -
    port: 5222
    ip: "::"
    module: ejabberd_c2s
    starttls_required: true
    protocol_options: 'TLSOPTS'
    dhfile: 'DHFILE'
    ciphers: 'CIPHERS'
    max_stanza_size: 65536
    shaper: c2s_shaper
    access: c2s
  -
    port: 5223
    ip: "::"
    module: ejabberd_c2s
    tls: true
    protocol_options: 'TLSOPTS'
    dhfile: 'DHFILE'
    ciphers: 'CIPHERS'
    max_stanza_size: 65536
    shaper: c2s_shaper
    access: c2s
  - 
    port: 5269
    ip: "::"
    module: ejabberd_s2s_in
    max_stanza_size: 131072
    shaper: s2s_shaper
  -
    port: 5280
    ip: "::"
    module: ejabberd_http
    http_bind: true # Will map to "/http-bind"
  -
    port: 5288
    ip: "::"
    module: ejabberd_http
    request_handlers:
      "": mod_http_upload

At a later time, you might want to adapt loglevel (less output with 3) and acladminusers (list of users that can send administrative commands) above.

Modify /etc/xcauth.conf for the following contents (replace SECURE-API-TOKEN with the secure API token shown in the Nextcloud JSXC admin settings):

# Example xcauth.py configuration file
#
# Preferably put this in /etc,
# and make it readable only for the user the XMPP server is running under
#
# Config files are only supported if ConfigArgParse python module
# is installed. Install e.g. using "pip install ConfigArgParse".
# If "xcauth.py -h" shows the "-c" option, it is installed.

# Type: ejabberd or prosody
#
type=ejabberd

# URL: Where JSXC for Nextcloud (>=3.2.0) can be queried
# Shown in the Nextcloud JSXC administration settings
#
url=https://SERVERNAME/index.php/apps/ojsxc/ajax/externalApi.php

# Secret: Secure API token
# Shown in the Nextcloud JSXC administration settings
# :warning: Should not fall into the wrong hands!
#
#secret=0123456789ABCDEF
secret=SECURE-API-TOKEN

# Log: Log directory
# In this directory, extauth.{log,err} will be created
#
log=/var/log/xcauth

# Debug: Log more
#
#debug

Execute the following commands:

service xcauth restart
adduser ejabberd ssl-cert
openssl dhparam -out /etc/ejabberd/dhparams.pem 2048
chown xcauth:xcauth /etc/xcauth.conf
chmod 640 /etc/xcauth.conf
service ejabberd restart

Now change the Nextcloud JSXC settings as follows.

  • XMPP Domain: Change to your DynDNS name
  • BOSH URL: Change to https://SERVERNAME/http-bind/
  • External Services: Delete all, then add userdata.SERVERNAME Everything else is already set correctly by the managed server settings.

😢 For video chat, you need a STUN or better a TURN server, to facilitate setting up a connection between clients behind NAT. This is not easily possible from a machine itself behind NAT or using a dynamic IP address. Therefore, we retain turn.jsxc.ch.

👀 Milestone 3: Try the chat with your own domain

Now the users are called user1@SERVERNAME, both for XMPP as well as for Nextcloud. Now, only mail addresses are missing for that domain…

Applications

If you do not want to solely use this from the web browser, there are several apps to chose from:

😎 Enjoy the liberty and privacy of your own server!

References

This how-to was compiled using information from:

Clone this wiki locally