How to Install EteSync 2.0 (Etebase) Server on Ubuntu

This tutorial is going to show you how to install EteSync server on Ubuntu. EteSync is an open-source, end-to-end encryption solution for syncing your calendars, contacts, tasks and notes.

EteSync Features

The latest version is EteSync 2.0, which features

  • End-to-end encryption.
  • No separate encryption password needed. You just need one password that’s used for both the encryption, and the login.
  • Zero-knowledge proof to authenticate to the server making sure your password never leaves your device.
  • Instant synchronization between your devices.
  • The ability to share data with other users
  • Clients are available for the desktop (DAV bridge), the web, Android, and iOS.
  • Integration with GNOME and KDE desktops (EteSync backend for Evolution and Akonadi).
  • An add-on for Mozilla Thunderbird.
  • Upgrade to the new Etebase protocol.

In the near future, EteSync will also add support for secure location sharing. EteSync provides hosted service at etesync.com. I will show you how to run a self-hosted instance on Ubuntu server and how to use the client software on various platforms.

How to Install EteSync 2.0 (Etebase) Server on Ubuntu

Step 1: Install the Latest Stable Version of MariaDB Server on Ubuntu

By default, EteSync stores user information in SQLite database. If you prefer to use MariaDB, follow the instructions below.

You should use the latest stable version of MariaDB, which is 10.5, because there will be problems if you run EteSync with MariaDB 10.3. To install the latest stable version, run the following commands to add the MariaDB repository on Ubuntu 20.04.

sudo apt-get install software-properties-common

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8

sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] http://mirror.lstn.net/mariadb/repo/10.5/ubuntu focal main'

To add the repository on Ubuntu 18.04, simply replace focal with bionic in the third command.

Then update package index and install MariaDB server.

sudo apt update

sudo apt install mariadb-server

If you are upgrading an existing MariaDB server to the latest version, you might see the following message.  I recommend choosing N to keep the current version and examine what needs to change later.

install mariadb 10.5 on Ubuntu 20.04 18.04

If there’s a package dependency problem, you can run the following command to fix it.

sudo apt --fix-broken install

Once the installation finishes, MariaDB server automatically starts. You can check its status with:

systemctl status mariadb

As you can see, it’s active and running.

systemctl status mariadb

Hint: Press Q to gain back control of the terminal if the above command doesn’t quit immediately.

If it’s not running, you can manually start it with:

sudo systemctl start mariadb

To enable auto-start at boot time, run

sudo systemctl enable mariadb

Step 2: Create a Database and User for EteSync in MariaDB Database Server

Log into MariaDB database server with the following command. Since MariaDB is now using unix_socket plugin to authenticate user login, there’s no need to enter MariaDB root password. We just need to prefix the mysql command with sudo.

sudo mysql

Then create a database for EteSync. This tutorial names the database etebase. You can use whatever name you like.

create database etebase;

Create the database user. Again, you can use your preferred name for this user. Replace your-password with your preferred password.

create user etebase@localhost identified by 'your-password';

Grant this user all privileges on the etebase database.

grant all privileges on etebase.* to etebase@localhost;

Flush privileges and exit.

flush privileges;

exit;

etebase mariadb ubuntu

Step 3: Install EteSync 2.0 Server on Ubuntu

Install Python3 virtual environment creator and some package-building tools.

sudo apt install python3-virtualenv python3-pip gcc build-essential

Go to your home directory.

cd

Clone the EteSync repository from Github.

git clone https://github.com/etesync/server.git etebase

Change to the newly-created directory.

cd etebase

Create a Python3 virtual environment.

virtualenv -p python3 .venv

source .venv/bin/activate

pip install -r requirements.txt

Copy the example configuration file.

cp etebase-server.ini.example etebase-server.ini

Edit the file.

nano etebase-server.ini

Find the following line

;media_root = /path/to/media

Uncomment it and change the value.

media_root = /home/username/etebase/media/

Find the following line,

allowed_host1 = example.com

Use a sub-domain like etebase.example.com.

allowed_host1 = etebase.example.com

By default, EteSync stores user information in SQLite database. If you prefer to use MariaDB database server, then comment out the following two lines (Add a semicolon at the beginning of each line).

engine = django.db.backends.sqlite3
name = db.sqlite3

Then add the following lines at the end of this file. This tells EteSync how to access the etebase database in MariaDB, which is created in step 1. Obviously you need to use your own password for the etebase user.

engine = django.db.backends.mysql
name = etebase
user = etebase
password = your-password
host = 127.0.0.1
port = 3306

Save and close the file. Etebase server is a Django application, we can use Daphne (the Django Channels HTTP/WebSocket server) to run Etebase. Install Daphne with:

pip3 install daphne

Since we use MySQL/MariaDB as the database engine, we also need to install the mysqlclient module.

sudo apt install libmysqlclient-dev

pip3 install mysqlclient

Install the aioredis module in order to use Redis cache.

pip3 install aioredis

Create Django’s static files.

./manage.py collectstatic

Initialize the app.

./manage.py migrate

Start EteSync 2.0 (Etebase) server.

daphne -b 0.0.0.0 -p 8001 etebase_server.asgi:application

daphne start etebase server

Step 4: Run EteSync as a Systemd Service

We can manually start EteSync with daphne -b 0.0.0.0 -p 8001 etebase_server.asgi:application, but it’s more convenient to run EteSync as a systemd service in the background. Press Ctrl+C to stop the current EteSync instance.

Create a systemd service unit file for EteSync with the following command.

sudo nano /etc/systemd/system/etebase.service

Put the following lines into the file. Replace username with your real username.

[Unit]
Description=EteSync: End-to-End Encryption to Sync Calender, Contacts, Tasks and Notes.

[Service]
WorkingDirectory=/home/username/etebase/
ExecStart=/home/username/etebase/.venv/bin/daphne -b 127.0.0.1 -p 8001 -u /tmp/etebase_server.sock etebase_server.asgi:application
User=username
Group=username
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

Run EteSync as a Systemd Service

Save and close the file. Now we can start and enable the etebase systemd service.

sudo systemctl start etebase

sudo systemctl enable etebase

Check status.

systemctl status etebase

systemctl status etebase

If the etebase service isn’t active (running), you can run the following command to see what’s wrong.

sudo journalctl -eu etebase

Step 5: Set Up Reverse Proxy

Now we need to set up a reverse proxy for the Django application, so later we can access EteSync via a domain name and easily enable HTTPS. We can use Apache or Nginx to accomplish this.

Apache

If you prefer Apache, then install Apache web server by using the following command.

sudo apt install apache2

To use Apache as a reverse proxy, we need to enable the proxy modules and the header module.

sudo a2enmod proxy proxy_http headers proxy_wstunnel

Then create a virtual host file for EteSync.

sudo nano /etc/apache2/sites-available/etebase.conf

Put the following configurations into the file. Replace etebase.example.com with your actual domain name. Don’t forget to create DNS A record for this sub-domain. If you don’t have a real domain name, I recommend going to NameCheap to buy one. The price is low and they give whois privacy protection free for life.

<VirtualHost *:80>
   ServerName etebase.example.com
   ErrorDocument 404 /404.html

   ErrorLog ${APACHE_LOG_DIR}/etebase_error.log
   CustomLog ${APACHE_LOG_DIR}/etebase_access.log combined

   ProxyPreserveHost On
   ProxyPass / http://127.0.0.1:8001/
   ProxyPassReverse / http://127.0.0.1:8001/
   Alias /static /home/username/etebase/static

</VirtualHost>

Save and close the file. Then enable this virtual host.

sudo a2ensite etebase.conf

Restart Apache

sudo systemctl restart apache2

Now you can access EteSync web interface using the domain name etebase.example.com.

Nginx

If you prefer Nginx web server, then install Nginx with.

sudo apt install nginx

Create a virtual host file in Nginx for EteSync.

sudo nano /etc/nginx/conf.d/etebase.conf

Put the following lines into the file. Replace the placeholders as necessary and you should create a DNS A record for the sub-domain.

upstream etebase {
    server unix:///tmp/etebase_server.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name etebase.example.com;

    charset     utf-8;
    access_log /var/log/nginx/etebase.access;
    error_log /var/log/nginx/etebase.error;

    # max upload size
    client_max_body_size 75M;

    location /static/ {
        alias /home/username/etebase/static/;
    }

    location / {
        proxy_pass http://etebase;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $server_name;
    }
}

Save and close the file. Then test Nginx configurations.

sudo nginx -t

If the test is successful, reload Nginx for the change to take effect.

sudo systemctl reload nginx

Now you can access EteSync web interface at etebase.example.com.

Troubleshooting

If you see the bad request (400) error while trying to access EteSync web interface, make sure you have added the etesync server name to the allowd_hosts list in etebase-server.ini file. Then restart etebase (sudo systemctl restart etebase).

You can also enable debug mode in the etebase-server.ini file, i.e, change

debug = false

To

debug = true

Then restart etebase.

sudo systemctl restart etebase

Then check the systemd service log.

sudo journalctl -eu etebase

Step 6: Enable HTTPS

To encrypt the HTTP traffic, we can enable HTTPS by installing a free TLS certificate issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client (certbot) on Ubuntu server.

sudo apt install certbot

If you use Apache, then you also need to install the Certbot Apache plugin.

sudo apt install python3-certbot-apache

Next, run the following command to obtain and install TLS certificate.

sudo certbot --apache --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d etebase.example.com

If you use Nginx, then you also need to install the Certbot Nginx plugin.

sudo apt install python3-certbot-nginx

Next, run the following command to obtain and install TLS certificate.

sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d etebase.yourdomain.com

Where:

  • --apache: Use the Apache plugin.
  • --nginx: Use the nginx plugin.
  • --agree-tos: Agree to terms of service.
  • --redirect: Force HTTPS by 301 redirect.
  • --hsts: Add the Strict-Transport-Security header to every HTTP response. Forcing browser to always use TLS for the domain. Defends against SSL/TLS Stripping.
  • --staple-ocsp: Enables OCSP Stapling. A valid OCSP response is stapled to the certificate that the server offers during TLS.

The certificate should now be obtained and automatically installed.

etebase server ubuntu certbot https

Step 7: Create User Accounts

Create a super admin user.

./manage.py createsuperuser

etebase ubuntu create super user

Then go to etebase.example.com/admin and log into the admin console. Next, you can create individual user accounts to be used for syncing calendars, contacts, tasks, and notes. Notice that you don’t need to create passwords for users in the EteSync admin console, as Etebase uses zero-knowledge proof for authentication.

etesync create users

Now we need to set up clients to use EteSync.

How to Install the Evolution EteSync Module on Ubuntu Desktop

Evolution is the default groupware suite in GNOME desktop environment. You can install it on your Ubuntu desktop with:

sudo apt install evolution

To use EteSync in Evolution, we need to install the EteSync module for Evolution by following the steps below.

Clone the libetebase repository.

sudo apt install git

git clone https://github.com/etesync/libetebase.git

Change to the newly-created directory.

cd libetebase/

Install the required packages to build the package from source.

sudo apt install build-essential libssl-dev cargo

Compile the source package.

make

Install the binary.

sudo make install

Then go back to the previous directory.

cd ..

Clone the Evolution-EteSync repository.

git clone https://gitlab.gnome.org/GNOME/evolution-etesync

Change to the newly-created directory.

cd evolution-etesync/

Install the required packages to build the package from source.

sudo apt install cmake intltool evolution-data-server-dev evolution-dev libedata-book1.2-dev libedata-cal2.0-dev libecal2.0-dev libebook1.2-dev

Compile and install the package.

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make -j
sudo make -j install

Using EteSync in Evolution

Now launch the Evolution app on your Ubuntu desktop. Click the New button in the toolbar and add a new collection account.

evolution add a new collection account ubuntu

Then enter your EteSync usename and server address. Note that you need to add https:// as the prefix of the server address. Select Look up for an EteSync account and untick all other options. Then click the Look Up button.

add an etesync account in Evolution ubuntu

It will asks you to enter password to continue. This is actually the time to set the password, so click the Enter password link and set a password.

etesync zero knowledge proof ubuntu

After entering a password, click Try again button and it should find one candidate. Click the Next button to continue.

etesync collection account ubuntu

Sync with NextCloud

If you have a self-hosted Nextcloud server and installed the Calendar, Tasks or Contacts app on your Nextcloud server, you can add your Nextcloud DAV server in Evolution, so they can be synced. Simply add another collection account in Evolution, enter your Nextcloud username and CalDAV/CardDAV address, select Look up for a CalDAV/CardDAV server, untick all other options. Then enter your Nextcloud password. The Nextcloud CalDAV/CardDAV address should be https://nextcloud.yourdomain.com/remote.php/dav.

etesync nextcloud ubuntu

Using the iOS EteSync App

To sync your calendar, contacts, and tasks on iOS, first you need to set up a CalDAV/CardDAV account in iOS. Go to the Settings app -> Calendar -> Accounts -> Add Account -> Other,  and add a CalDAV and CardDAV account. CalDAV is used to sync calendars and CardDAV is used to sync contacts on your devices.

If you have a self-hosted Nextcloud server, you can use your Nextcloud CalDAV/CardDAV account. If you don’t have one, simply use a fake account.

ios add caldav carddav account

Next, install the EteSync app from the app store. Then add your EteSync account.

etesync ios client

After log into your EteSync account, go to the settings menu in the EteSync app. In the Advanced section, select your CardDAV account for Sync contacts and select your CalDAV account for Sync calendars and reminders.

ios etesync caldav carddav sync

Wrapping Up

I hope this post helped you set up your own EteSync server on Ubuntu. As always, if you found this post useful, then subscribe to our free newsletter for more tips and tricks 🙂

Rate this tutorial
[Total: 0 Average: 0]

3 Responses to “How to Install EteSync 2.0 (Etebase) Server on Ubuntu

  • Danran
    1 year ago

    After multiple attempts to install I get the following errors after running

    ./manage.py migrate

    :

    Traceback (most recent call last):
      File "/home/boo/etebase/./manage.py", line 21, in 
        main()
      File "/home/boo/etebase/./manage.py", line 17, in main
        execute_from_command_line(sys.argv)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
        utility.execute()
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 413, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/base.py", line 354, in run_from_argv
        self.execute(*args, **cmd_options)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/base.py", line 398, in execute
        output = self.handle(*args, **options)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/base.py", line 89, in wrapped
        res = handle_func(*args, **kwargs)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/commands/migrate.py", line 75, in handle
        self.check(databases=[database])
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/management/base.py", line 419, in check
        all_issues = checks.run_checks(
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/checks/registry.py", line 76, in run_checks
        new_errors = check(app_configs=app_configs, databases=databases)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/core/checks/database.py", line 13, in check_database_backends
        issues.extend(conn.validation.check(**kwargs))
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/mysql/validation.py", line 9, in check
        issues.extend(self._check_sql_mode(**kwargs))
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/mysql/validation.py", line 13, in _check_sql_mode
        if not (self.connection.sql_mode & {'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES'}):
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/mysql/base.py", line 405, in sql_mode
        sql_mode = self.mysql_server_data['sql_mode']
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/mysql/base.py", line 366, in mysql_server_data
        with self.temporary_connection() as cursor:
      File "/usr/lib/python3.10/contextlib.py", line 135, in __enter__
        return next(self.gen)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/base/base.py", line 603, in temporary_connection
        with self.cursor() as cursor:
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/utils/asyncio.py", line 33, in inner
        return func(*args, **kwargs)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/base/base.py", line 259, in cursor
        return self._cursor()
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/base/base.py", line 235, in _cursor
        self.ensure_connection()
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/utils/asyncio.py", line 33, in inner
        return func(*args, **kwargs)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/base/base.py", line 219, in ensure_connection
        self.connect()
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/utils/asyncio.py", line 33, in inner
        return func(*args, **kwargs)
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/base/base.py", line 199, in connect
        conn_params = self.get_connection_params()
      File "/home/boo/etebase/.venv/lib/python3.10/site-packages/django/db/backends/mysql/base.py", line 217, in get_connection_params
        options = settings_dict['OPTIONS'].copy()
    AttributeError: 'SectionProxy' object has no attribute 'copy'
    

    What should I do to fix this?

    • I have the same, did you find a solution?

      • I was able to find a solution for this – https://github.com/etesync/server/issues/161

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here