This documentation applies to all editions of Realm Object Server. For features specific to the Professional and/or Enterprise Editions, consult the PE/EE Documentation.
Install Realm Object Server
macOS
On macOS, you can install Realm Object Server via the macOS Realm Bundle:
Open the realm-mobile-platform folder. You can start the Realm Object Server by double-clicking start-object-server.command.
Linux
Under Linux, Realm’s package repositories are managed through a service called PackageCloud. Follow the directions for your Linux distribution below.
# Setup Realm's package repository
curl -s https://packagecloud.io/install/repositories/realm/realm/script.rpm.sh | sudo bash
# Install the Realm Object Server
sudo yum -y install realm-object-server-developer
# Enable and start the service
sudo chkconfig realm-object-server on
sudo service realm-object-server start # Setup Realm's package repository
curl -s https://packagecloud.io/install/repositories/realm/realm/script.rpm.sh | sudo bash
# Install the Realm Object Server
sudo yum -y install realm-object-server-developer
# Enable and start the service
sudo systemctl enable realm-object-server
sudo systemctl start realm-object-server # Setup Realm's package repository
curl -s https://packagecloud.io/install/repositories/realm/realm/script.deb.sh | sudo bash
# Update repositories
sudo apt-get update
# Install the Realm Object Server
sudo apt-get install realm-object-server-developer
# Enable and start the service
sudo systemctl enable realm-object-server
sudo systemctl start realm-object-server We also provide public AMIs for Amazon EC2, based on Ubuntu 16.04. For details on the difference between Paravirtual and HVM see this guide.
| Paravirtual | HVM | |
|---|---|---|
| ap-northeast-1 (Tokyo) | ami-13313074 | ami-a03233c7 |
| eu-west-1 (Ireland) | ami-58f3e23e | ami-aecfdec8 |
| us-east-1 (N. Virginia) | ami-5e6c2648 | ami-8a62289c |
You can launch these AMIs just as any other Amazon EC2 AMI. Make sure you open port 22/TCP (ssh) and 9080/TCP (dashboard and client access). The default SSH user is ubuntu.
Configuring The Server
Realm Object Server includes a configuration file in YAML format that comes with sensible defaults for a development environment. The configuration file can be edited to customize the installation and make it production-ready. In the following we will refer to the configuration file as configuration.yml.
The various configuration options available in configuration.yml are described below. The default location of the configuration file depends on your platform:
The configuration file is in /etc/realm/configuration.yml.
The configuration file is in realm-object-server/object-server inside your Realm Mobile Platform folder.
Paths in the configuration file can be either absolute or relative. If relative, they are resolved according to the current working directory. We recommend always using absolute paths to avoid confusion.
Mandatory Settings
A few options are mandatory to set in order to be able to start Realm Object Server. We recommend specifying these in configuration.yml, but they can also be given as command line arguments.
The mandatory configuration defines:
- An existing directory where Realm Object Server will store all its files,
- Paths to a key pair used for securing access to ROS to only allow authenticated clients to access it. The keys given must be in PEM format and they must be a matching pair.
Here is a summary of the settings:
| Configuration key | CLI argument | Description |
|---|---|---|
storage.root_path | --root | Path to the directory where ROS will store all its data files |
auth.public_key_path | --public-key | Path to the public key (stored in PEM format) used to authenticate client tokens |
auth.private_key_path | --private-key | Path to the private key (stored in PEM format) used to authenticate client tokens |
The Realm Object Server must have read/write access to the direectory pointed to by the storage.root_path setting (or the --root CLI argument). If you change this setting, make sure the realm user has access to the new storage directory (i.e., chown -R realm:realm /new/storage/path).
Network
In its default configuration Realm Object Server runs internal backend services as well as a proxy module. The backend services are only reachable from the host running the server, and all traffic to them are passed through the proxy module which listen on all interfaces. The following diagram should explain the default configuration:
In the following we show how to change this default configuration.
Backend Services
Realm Object Server internally starts two backend services. The sync service is responsible for core synchronization functionality, and listens on port 27800. The http service handles requests for authentication and the dashboard and listens on port 27080. By default, the services only listen on the host’s IPv4 loopback address (127.0.0.1) and requests are routed through the proxy module.
Should you wish to disable the proxy module and let backend services listen to all IPv4 and IPv6 interfaces this can be achieved by setting the appropriate listen_address to ::. Similarly, the listening ports can be changed by modifying the appropriate listen_port.
Here is a summary of the settings:
| Configuration key | Default | Description |
|---|---|---|
network.sync.listen_address | 127.0.0.1 | Address the sync service should bind to |
network.sync.listen_port | 27800 | Port the sync service should bind to |
network.http.listen_address | 127.0.0.1 | Address the http service should bind to |
network.http.listen_port | 27080 | Port the sync service should bind to |
Proxy Module
The included reverse proxy module dispatches all incoming traffic to the appropriate backend service. This proxy is capable of handling both HTTP, WebSocket, HTTPS and Secure WebSocket traffic (but exclusively traffic destined for the Realm Object Server, this is not a general purpose proxy). In the default configuration, the HTTP proxy listens on all IPv4 and IPv6 interfaces on port 9080, but the HTTPS proxy is disabled. Both variants of the proxy can be enabled simultaneously.
It is recommended that you keep the Sync and HTTP services listening on localhost (default) and simply use the proxy for external access.
If you wish, you can disable the included proxy module and replace it with a standalone proxy installation or use ROS by exposing the backend services on the network for direct client access.
Here is a summary of the proxy’s configuration settings:
| Configuration key | Default | Description |
|---|---|---|
proxy.http.enable | true | Set to false to disable the HTTP Proxy |
proxy.http.listen_address | :: | Supply an interface address, 0.0.0.0 for all IPv4 interfaces or :: for all IPv4 and IPv6 interfaces |
proxy.http.listen_port | 9080 | Supply an alternative port for the HTTP Proxy |
proxy.https.enable | false | Set to true to enable the HTTPS Proxy |
proxy.https.listen_address | :: | Supply an interface address, 0.0.0.0 for all IPv4 interfaces or :: for all IPv4 and IPv6 interfaces |
proxy.https.listen_port | 9443 | Supply an alternative port for the HTTPS Proxy |
proxy.https.certificate_path | Path to the HTTPS Proxy’s certificate file, in PEM format | |
proxy.https.private_key_path | Path to the HTTPS Proxy’s private key file, in PEM format |
If you wish to enable the HTTPS Proxy, you must provide certificate and private key files in PEM format by setting the proxy.https.certificate_path and proxy.https.private_key_path options. The certificate cannot be self-signed.
You must also choose a port number above 1024, as the Realm Object Server does not run as root. It is recommended to use the default port (9443).
If you would like to be able to connect to Realm Object Server on a port lower than 1024, such as the default HTTPS port 443, you can forward traffic to the port that Realm Object Server is listening on:
sudo iptables -A PREROUTING -t nat -p tcp --dport 443 -j REDIRECT --to-port 9443 Here is an example of a working proxy configuration with HTTPS:
proxy:
https:
enable: true
listen_address: ‘::'
http:
enable: false Logging
Realm Object Server logs messages information about its state and progress. Logs can be written to the console or to a file depending on the logging.path configuration, and the logging detail can be tuned by changing the logging.level option.
The default value for logging.path depends on the platform:
Logs are written to /var/log/realm-object-server.log.
Logs are output on the terminal that launched Realm Object Server.
The value for logging.level can be one of 9 possible values:
logging.level | Detail level |
|---|---|
all | all possible messages |
trace | used to trace protocol and internal server state |
debug | internal server debugging messages |
detail | shows summary of synchronization transactions |
info | good for production (default) |
warn | log only warning messages |
error | log only errors |
fatal | errors that cause the ROS to exit |
off | all output suppressed |
Here is a summary of the settings:
| Configuration key | Default macOS | Default linux | Description |
|---|---|---|---|
logging.path | /var/log/realm-object-server.log | Path to the file where logs should be written. If no value is set, output is written to stdout/stderr. | |
logging.level | info | info | The amount of detail in the log output, see valid values above |
Running the Server
The Realm Object Server service uses standard service commands:
sudo service realm-object-server status
sudo service realm-object-server start
sudo service realm-object-server stop
sudo service realm-object-server restart The Realm Object Server service definition uses standard systemctl commands:
sudo systemctl status realm-object-server
sudo systemctl start realm-object-server
sudo systemctl stop realm-object-server
sudo systemctl restart realm-object-server To start the server double-click on the start-object-server.command file in the realm-mobile-platform directory you originally downloaded.
To stop the macOS version of the server, simply press CTRL-C in the terminal window that was opened by the start-object-server.command.
The Realm Dashboard

The Dashboard is a browser-based administration application for the Realm Application Server that provides the following:
- Dashboard: System status, including real-time displays of data rate in/out, bytes in/out, open connections, and open Realms
- Realms: Paths, permissions, and owners of Realms synced to this Object Server, with the ability to “drill down” and display the models and contents of individual Realms
- Users: User information and management for this Object Server, including granting and removing administrative privileges
- Functions: Management and entry of Realm Functions
- Logs: System logs for the Object Server, with selectable detail level
To access the Dashboard on the same machine at the default port (9080), open a new browser window and go to http://localhost:9080/. If your server is not your local machine, replace localhost with its hostname or IP address.
The first time you access the Dashboard, you will be prompted to create an admin user by supplying an email address and password. After registering, you can log in using those credentials.
Data Browser
The Realm Browser is only available for macOS.
The Realm Browser allows developers to observe and edit Realms. The Realm Browser can connect to either macOS or Linux instances of the Realm Object Server.
You can use the Connect to Object Server option in Realm Browser in one of two ways:
- Specifying the username and password of an administrator account
- Providing the admin token generated by the Object Server
The admin token is stored in a text file on the server. Under Linux, view the token with:
cat /etc/realm/admin_token.base64 On macOS, the token file is in the realm-object-server folder, inside the Realm Mobile Platform folder. Navigate to that folder and view the token:
cd path-to/realm-mobile-platform
cat realm-object-server/admin_token.base64 
Upgrading
Upgrading macOS
Upgrades to the macOS version of the Object Server are delivered by a new macOS download bundle from Realm
Upgrading Linux
If you are upgrading from a version prior to 1.0.0-BETA-4.8, we have renamed the package. Please follow the uninstall documentation followed by the install documentation.
Realm’s package service for stand-alone servers makes the upgrade process is very simple:
# Stop the service before upgrading
sudo service realm-object-server stop
# Install a new version if available
sudo yum -y upgrade realm-object-server-developer
# Restart the server to continue operation
sudo service realm-object-server start # Stop the service before upgrading
sudo systemctl stop realm-object-server
# Install a new version if available
sudo yum -y upgrade realm-object-server-developer
# Restart the server to continue operation
sudo systemctl start realm-object-server # Update the package definitions
sudo apt-get update
# Stop the service before upgrading
sudo systemctl stop realm-object-server
# Install a new version if available
sudo apt-get upgrade realm-object-server-developer
# Restart the server to continue operation
sudo systemctl start realm-object-server For information on upgrading to the Professional and Enterprise editions, visit the PE/EE Documentation.
Uninstalling
Should you need to uninstall Realm Object Server, the process is straightforward:
# Stop the service before uninstalling
sudo service realm-object-server stop
# Optional/Recommended: Backup your data:
# cp -a /var/lib/realm{,.backup}
# Remove the packages. Data is retained under /var/lib/realm.
sudo yum -y erase realm-object-server-developer
# Remove the packages (older than 1.0.0-BETA-4.8)
sudo yum -y erase realm-object-server-de # Stop the service before uninstalling
sudo systemctl stop realm-object-server
# Optional/Recommended: Backup your data:
# cp -a /var/lib/realm{,.backup}
# Remove the packages. Data is retained under /var/lib/realm.
sudo yum -y erase realm-object-server-developer
# Remove the packages (older than 1.0.0-BETA-4.8)
sudo yum -y erase realm-object-server-de # Stop the service before uninstalling
sudo systemctl stop realm-object-server
# Optional/Recommended: Backup your data:
# cp -a /var/lib/realm{,.backup}
# Remove the packages. Data is retained under /var/lib/realm.
sudo apt-get remove realm-object-server-developer
# Remove the packages (older than 1.0.0-BETA-4.8)
sudo apt-get remove realm-object-server-de # Stop the service before uninstalling
Press CTRL-C in the controlling terminal window
# Remove the packages
Drag the realm-mobile-platform folder to the trash Troubleshooting
Verify Port Access
Certain factors may impact external (non-localhost) access to the Realm Object Server’s synchronization facility, and the Realm Dashboard. In order to enable access, it may be necessary to open port 9080 on your server(s).
Using the standard Linux tools, these commands will open access to the port:
sudo iptables -A INPUT -p tcp -m tcp --dport 9080 -j ACCEPT
sudo service iptables save Please refer to the CentOS 6 Documentation for more information regarding how to configure your firewall.
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --add-port=9080/tcp --permanent
sudo firewall-cmd --reload sudo ufw allow 9080/tcp
sudo ufw reload If your environment does not use your distribution’s standard firewall, you will have to modify these instructions to fit your environment.
Configuration Errors
Generally the default settings will work well for most installations. Most settings inside the Realm config file are commented out (the system has pre-programmed default values) and show examples of how they can be to customized. If the configuration file has been customized and there is a problem, error messages will be written to the default log location (in the terminal window under macOS or /var/log/realm-object-server.log on Linux systems).
If the Realm Object Server will not start, an error in the configuration file is usually the cause. To debug the config file, you can use the built-in checker by starting a terminal and using:
realm-object-server --check-configuration /etc/realm/configuration.yml If running under macOS, replace the configuration file path with the path to your configuration.yml.
When an error occurs, the server’s parser will print a detailed error message stating the problem and possibly highlighting the line the error occurred on. Once all errors (if any) were corrected, the server will start; stop the server by pressing ^C and then start it normally by rebooting the system or restarting the Realm Object Server using systemd on Linux or the start-object-server.command on macOS.
Error messages are usually self-explanatory, but here are some potential hints:
- To be able to run ROS, the following settings are mandatory:
- Storage root directory: Where Realm Object Server should store all its files. Please set
storage.root_pathor give the--rootCLI argument. The directory must exist before ROS can start. - Authentication key pair: For securing access to ROS to only authenticated clients. Please set
auth.private_key_pathor give the--private-keyCLI argument, and please setauth.public_key_pathor give the--public-keyCLI argument. The keys given must be in PEM format and they must be a matching pair.
- Storage root directory: Where Realm Object Server should store all its files. Please set
-
The configuration for listening ports must not be overlapping, meaning that
listen_portvalues must be unique in the file. Additionally, the ports must not be bound in another process. - The HTTPS proxy will only start if given paths to a valid certificate and private key in
proxy.https.certificate_pathandproxy.https.private_key_path. The certificate and private key must be in PEM format and they must be a matching pair. The certificate cannot be self-signed.
Operational Errors
Occasionally it can be useful for debugging purposes to check the Realm Object Server logs - which are in the terminal window on macOS or /var/log/realm-object-server.log on Linux systems - ROS produces two specific classes of error and warning diagnostics that may be useful to system admins and developers.
Session Specific Errors
-
204 “Illegal Realm path (BIND)” Indicates that the Realm path is not valid for the user.
-
207 “Bad server file identifier (IDENT)” Indicates that the local Realm specifies a link to a server-side Realm that does not exist. This is most likely because the server state has been completely reset.
-
211 “Diverging histories (IDENT)” Indicates that the local Realm specifies a server version that does not exists. This is most likely because the server state has been partially reset (for example because a backup was restored).
Client Level Errors
-
105 “Wrong protocol version (CLIENT)” The client and the server use different versions of the sync protocol due to a mismatch in upgrading.
-
108 “Client file bound in other session (IDENT)” Indicates that multiple sync sessions for the same client-side Realm file overlap in time.
-
203 “Bad user authentication (BIND, REFRESH)” Indicates that the server has produced a bad token, or that the SDK has done something wrong.
-
206 “Permission denied (BIND, REFRESH)” Indicates that the user does not have permission to access the Realm at the given path.
Conflict Resolution
One of the defining features of mobile is the fact that you can never count on being online. Loss of connectivity is a fact of life, and so are slow networks and choppy connections. But people still expect their apps to work!
This means that you may end up having two or more users making changes to the same piece of data independently, creating conflicts. Note that this can happen even with perfect connectivity as the latency of communicating between the phone and the server may be slow enough that they can end up creating conflicting changes at the same time.
What Realm does in this case is that it merges the changes after the application of specific rules that ensure that both sides always end up converging to the same result even, though they may have applied the changes in different order.
This means that you no longer have the kind of perfect consistency that you could have in a traditional database, what you have now is rather what is termed “strong eventual consistency”. The tradeoff is that you have to be aware of the rules to ensure the consistent result you want, but the upside is that by following a few rules you can have devices working entirely offline and still converging on meaningful results when they meet.
At a very high level the rules are as follows:
-
Deletes always win. If one side deletes an object it will always stay deleted, even if the other side has made changes to it later on.
-
Last update wins. If two sides update the same property, the value will end up as the last updated.
-
Inserts in lists are ordered by time. If two items are inserted at the same position, the item that was inserted first will end up before the other item. This means that if both sides append items to the end of a list they will end up in order of insertion time.
Primary Keys
A primary key is a property whose value uniquely identifies an object in a Realm (just like a primary key in a conventional relational database is a field that uniquely identifies a row in a table). Primary keys aren’t required by Realm, but you can enable them on any object type. Add a property to a Realm model class that you’d like to use as the primary key (such as id), and then let Realm know that property is the primary key. The method for doing that is dependent on the language you’re using; in Cocoa, you override the primaryKey() class method, whereas Java and .NET use annotations. (Consult the documentation for your language binding for more details.)
Once a Realm model class has a primary key, Realm will ensure that no other object can be added to the Realm with the same key value. You can update the existing object; in fact, you can update only a subset of properties on a specified object without fetching a copy of the object from the Realm. Again, consult the documentation for your language binding for specifics.
For more information, read the Primary Keys Tutorial.
Strings
Note: Strings are not exposed in client APIs yet.
Strings are special in that you can see them both as scalar values and as lists of characters. This means that you can set the string to a new string (replacing the entire string) or you can edit the string. If multiple users are editing the same string, you want conflicts to be handled at the character level (similar to the experience you would have in something like Google docs).
Counters
Note: Counters are not exposed in client APIs yet.
Using integers for counting is also a special case. The way that most programming languages would implement an increment operation (like v += 1), is to read the value, increment the result, and then store it back. This will obviously not work if you have multiple parties doing it simultaneously (they may both read 10, increment it to 11, and when it merges you would get the result of 11 rather than the intended 12).
To support this common use case we offer a way to express the intent that you are incrementing (or decrementing) the value, giving enough hints to the merge that it can reach the correct result. Just as with the strings above, it gives you the choice of updating the entire value, or editing it in a way that conveys more meaning, and allow you to get more precise control of the conflict resolution.
Custom Conflict Resolution
The standard way to do custom conflict resolution is to just change the value into a list. Then each side can add its updates to the list and apply any conflict resolution rules it wants directly in the data model.
You can use this technique to implement max, min, first write wins, last write wins and pretty much any kind of resolution you can think of.
Realm Functions
Realm Functions provide a way to add “serverless” logic that responds to changes in Realms. Using the Dashboard, you can create, edit, start, stop, and delete Functions that respond to changes on all Realms or changes on Realms that match specific patterns (e.g., any user’s Realm that contains /settings/ in its path).

Realm Functions use the Event Handling capability of the Realm Object Server; the Functions themselves are Node.js functions that will be called by the Object Server’s global listening API and passed changeEvent objects.
Realm Functions are available in the Developer Edition of the Realm Mobile Platform, but you will be limited to three active functions with DE. You can create as many functions as you wish, but only three may be running at any given time. This limitation is removed on the Professional and Enterprise Editions. (The traditional server-side Event Handling capabilities of the Realm Mobile Platform Realm Functions are available only on Professional and Enterprise Editions.)
To create a function, you’ll need to provide three things to the Object Server on the Create New Function form:
- The name of your function script, as it will appear on the Dashboard.
- A regular expression to match against Realm URL paths.
- The function body.
Specifying Realm URL Path Regular Expressions
The regular expression (“regex”) for a function defines which Realms send change notifications to the function. Only Realms whose Realm URL is matched by the regex will trigger the function. While a full regular expression tutorial is beyond the scope of this documentation, here are a few basics that will be useful for matching Realm URL paths:
- Most characters simply match themselves. A regex of
catwill match any pattern that contains the string “cat,” including “catch”, “Alcatraz” and the word “cat” itself. - The character
.(period) matches any single character. A regex ofc.twill match the patterns “cat,” “cot,” “cut,” and any other pattern with a “c” followed by one single character and “t” after that. (So it would not match “ct” or “coot.”) - The character
*means “match zero or more of the previous characters.” A regex ofca*t, therefore, will match “cat”, “caat”, “caaaaaaaat” and “ct” (zero “a” characters). - The character
+means “match one or more of the previous characters.” So,ca+twould work likeca*tbut would not match “ct,” because it requires at least one “a.” - Follow
.with+or*to make a wildcard match. A regex ofc.*tmatches any string that has a “c” character followed somewhere by a “t.”
So, a few practical examples based on that:
- Match all Realms:
/.*(this is the default) - Match a public “catalog” Realm:
/catalog - Match any user-owned “settings” Realm:
/.+/settings
Writing Functions
When you click Create New Function, you’ll get an editing screen which displays the following snippet of skeleton code:
module.exports = function(changeEvent){
//your code goes here!
} Access Control
Realm Object Server includes access control mechanisms to restrict which users can sync which Realm files. In order to grant a user access to a Realm, Realm Object Server authenticates the user to verify their identity, then authorizes that the user has the correct permissions to access the Realm.
- Realm Object Server uses configurable authentication providers to validate user credentials and authenticate users. A client connects to the server using some user credentials, and these are given to an appropriate provider for validation. If the credentials are valid, the user is granted access to Realm Object Server. A new user account is created if the credentials are not coupled to an existing account.
- After the client is granted access as a user, it can request read or write access to a specific path identifying a Realm. If the user has the requested access permissions for the given path, the user is authorized to access the Realm, and normal sync operations can begin.
Authentication
Authentication providers allow developers to utilize third-party authentication mechanisms to control access to Realm apps that go beyond Realm’s own username/password mechanism. Realm supports Facebook, Google, and Apple’s iCloud.
These third-party providers currently operate at the single-server level, and will need to be set up on each server that needs to make use of a given authentication mechanism. The setup is done by providing a set of key-value pairs that identify the authentication mechanism and the required keys/secrets.
This information goes into the auth.providers section of the Realm configuration.yml file.
Below are examples that demonstrate how to integrate each of these third-party authentication providers and where applicable links to the developer pages for those services. Complete examples of all authentication providers can be found in the Realm Object Server configuration.yml file.
Username/Password
This standard authentication method is always enabled.
After getting Google OAuth2.0 API Access, uncomment the google provider and add your client ID:
google:
clientId: '012345678901-abcdefghijklmnopqrstvuvwxyz01234.apps.googleusercontent.com' To enable Facebook Authentication, just uncomment the facebook provider:
facebook: {} Note that the Realm Object Sever must be able to access Facebook APIs to validate received client tokens.
Azure Active Directory
Uncomment the azuread provider and add your Directory ID from the Azure Portal (under “Properties”):
azuread:
tenant_id: '81560d038272f7ffae5724220b9e9ea75d6e3f18' iCloud
You will need to create a public key for the Object Server to access CloudKit. The steps are slightly different for Linux and macOS. Note that iCloud client support is only available on Apple platforms: iOS, macOS, tvOS, and watchOS.
-
Open a terminal and
cdto the Realm Mobile Platform directory. -
Generate a private key:
openssl ecparam -name prime256v1 -genkey -noout -out cloudkit_eckey.pem -
Generate a public key to be submitted to the CloudKit Dashboard:
openssl ec -in cloudkit_eckey.pem -pubout
-
Generate a private key:
sudo openssl ecparam -name prime256v1 -genkey -noout -out /etc/realm/cloudkit_eckey.pem -
Generate a public key to be submitted to the CloudKit Dashboard:
openssl ec -in /etc/realm/cloudkit_eckey.pem -pubout

Log in to Apple’s CloudKit Dashboard and select your application. In the left-hand side of the dashboard, select “API Access”, then select “Server-to-Server Keys”. Select “Add Server-to-Server Key”. Give the new key a name and paste in the public key generated above. Click “Save.” After a few seconds, a key will be generated and displayed in the “Key ID” section at the top of the page.
Security note: Create a new private key for each application you plan on using with Realm CloudKit authentication. Reusing private keys can compromise all Realms using the shared key if the private key itself becomes compromised or needs to be revoked.
Uncomment the cloudkit provider in the configuration file and enter the Key ID, private key path, container ID and environment information:
cloudkit:
key_id: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
private_key_path: 'cloudkit_eckey.pem'
container: "iCloud.io.realm.exampleApp.ios"
# For production deployment on the App Store, you must specify 'production'
environment: 'development' Please ensure the path to the private_key_path is correct. If you followed the steps above, on Linux the path will be /etc/realm/cloudkit_eckey.pem.
Custom Authentication
The Realm Object Server supports the ability to use external authentication providers. This allow users to authenticate users against legacy databases or APIs, or integrate with providers that are not supported out-of-the-box by the Realm Object Server. This section of the manual will walk you through the process of writing and setting up a third-party authentication provider.
The basics of authentication in the Realm Object Server are simple: when a client tries to login, it provides some credentials to the server. The server checks those credentials, typically against an external server or API, and grants rights to the client based on the response.
Custom authentication providers can be installed anywhere, but by default, the server is configured to look in /usr/local/lib/realm/auth/providers. An authentication provider takes the shape of a NodeJS script which uses one of our development APIs.
Writing an authentication provider
Create the directory indicated above if it doesn’t exist yet, and create a file with a .js extension. The filename itself can be anything you want, but we recommend using something significant for the type of authentication provider you are implementing. For example, github.js, or something along those lines. In this example, we will create the FooAuth sample provider, which asks an external server to verify the token given by the client.
This is the main boilerplate of the class that you have to create:
# fooauth.js
/**
* This will be called when the server is started.
*
* It should return the constructor for the authentication provider.
*
* @param {object} deps - The dependencies passed from the running server
* to this implementation.
* @param {function} deps.BaseAuthProvider - the base class to use
* @param {object} deps.problem - a set of exception to throw on failure
* @param {object} deps.models - the models of the admin-Realm
* @returns {function}
*/
module.exports = function(deps) {
return class FooAuthProvider extends deps.BaseAuthProvider {
// This is used by the ROS when it loads the available
// authentication providers. This function is required.
static get name() {
return 'custom/fooauth';
}
// This is used by ROS when it parses the configuration
// file, to ensure that required default options are
// available. This function is optional.
static get defaultOptions() {
return {
auth_server: 'https://my.auth.server.example',
}
}
constructor(name, options, requestPromise) {
super(name, options, requestPromise);
// Here you can set your instance variables as usual
this.httpMethod = 'GET';
}
};
} Please note one important thing: the name of custom authentication providers has to start with custom/. This is done to ensure that there is no collision between the Realm-provided authentication providers, and the ones vendored by third parties.
Now comes the real meat of our FooAuth authentication provider: the HTTP request! The BaseAuthProvider class gives us access to a promise-based HTTP request. Let’s create a method that will be called by the authentication system when somebody is trying to log in:
# fooauth.js (continued)
verifyIdentifier(req) {
// The token submitted by the client
const token = req.body.data;
// The client SDKs also support sending additional information
// in the form of a map/dictionary. This is accessible through
// the `req.body.user_info` key.
// The information required to reach your API server that can
// validate the token. Obviously, this assumes a REST-like API.
// Please note that `this.options` comes from the configuration file or
// `defaultOptions()` method defined above. Similarly, `this.httpMethod` is
// an instance variable defined in the constructor above.
const httpOptions = {
uri: `${this.options.authServer}/api/auth?token=${token}`,
method: this.httpMethod,
json: true,
};
return this.request(httpOptions)
.catch((err) => {
// Please see src/node/services/problem/http_problem.js
// for other error cases
throw new problem.HttpProblem.Unauthorized({
detail: `Something bad happened: ${err.toString()}`,
});
})
.then((result) => {
// This userID has to be unique, and will be used to either
// - create a user in the ROS
// - login the user, if it already exists
return result.userID;
});
} The snippet above assumes a number of things:
- The server returned a JSON dictionary that contained (at least) a field named userID. This is the unique identifier that will be used as a username of sorts. This unique identifier will in the future be used to search for users through the upcoming user search API.
- The client retrieved the (valid) token through some way or another.
Configuring the authentication provider
Now that custom authentication provider has been written, the configuration needs to be updated to tell the server to load it. This is done by adding a few lines to the global configuration file:
# configuration.yml
auth:
providers:
# The name of a custom authentication provider must start with `custom/` to
# differentiate it from ROS-vendored authentication providers.
custom/fooauth:
# This refers to the `fooauth.js` file.
implementation: fooauth
# This is an option, as defined in the custom authentication provider.
auth_server: 'https://another.server.example' By simply adding this configuration, the ROS will automatically load the JS file and enable the authentication provider.
Using the custom provider on the client
All the client SDKs support custom authentication out of the box. It is only a matter of sending the correct information using the right login function. For more details, consult the documentation for your language bindings, and find “Authentication” under the “Sync” heading.
Authorization
Each Realm managed by the Realm Object Server has access permissions that can be set on it; permissions are the fundamental authorization control for the server. Permissions are set on each Realm using three boolean flags:
- The
mayReadflag indicates the user can read from the Realm. - The
mayWriteflag indicates the user can write to the Realm. - The
mayManageflag indicates the user can change permissions on the Realm for other users.
Permissions for a Realm can be set on a default basis and a per-user basis. When a user requests access for a Realm, first the Object Server checks to see if there are per-user permissions set for that user on that Realm. If there are no per-user permissions set for that user, the default permissions for the Realm are used. For example, a Realm might have mayRead set true by default, with individual users being granted mayWrite permissions.
By default, a Realm is exclusive to its owner: the owner has all permissions on it, and no other user has any permissions for it. Other users must be explicitly granted access.
Note that admin users are always granted all permissions to all Realms on the Object Server.
The Management Realm
All access management operations are performed by writing special permission change objects to a Management Realm. This is a special synchronized Realm; objects created in it are effectively requests to the server to change default and per-user permissions on other Realms.
Consult the documentation for the binding you’re using to learn how to access the Management Realm. Generally, it’s retrieved by calling a method on a user object (e.g., SyncUser.managementRealm() for Swift).
Permission Change Objects
A user adds PermissionChange objects to the Management Realm to change permissions; both per-user permissions and default Realm permissions are set the same way. The user must have the mayManage permission for the Realm they’re trying to manage to make modifications.
There are five fields in PermissionChange objects. The first two are required; the permission fields are all optional:
realmUrl(string): the URL of the Realm, or*for all Realms owned by the requesting useruserId(string): the identify of the user whose permissions are being modified, or*for the Realm default permissionsmayRead(boolean): read access to the RealmmayWrite(boolean): write access to the RealmmayManage(boolean): management permission for the Realm
If one of the may* flags is not set in the PermissionChange object, it will remain unchanged. Per-user permissions always take higher priority than default permissions, so changing the default permissions for a Realm will not remove permissions already set on individual users.
The PermissionChange object will be modified by the Object Server after it attempts to apply the permissions. If the permission change succeeds, the statusCode field will be populated and set to 0, and a description may be added in the statusMessage field. If an error occurs, statusCode will be set to a value higher than 0, and the error message will be in statusMessage.
For the specifics of how to create and use PermissionChange objects, please consult the documentation for your client binding.
Permission Offer and Response
The PermissionOffer and PermissionOfferResponse mechanism allows flexible sharing management between users. A PermissionOffer object functions similarly to a PermissionChange object, but creates a token that can be sent to another user to grant them permissions. The steps are, roughly:
- Create the
PermissionOfferobject and add it to the Management Realm. - Wait for the server to process the object and populate a
tokenproperty on it. - Send the
tokento another user via an external method: email, chat, your own API, etc. - The receiving user creates a
PermissionOfferResponseobject with the token and adds it to their Management Realm. - Wait for the server to process the object and return a successful status.
- Use the
realmUrlproperty now populated on thePermissionOfferResponseobject for syncing with that Realm.
Consult the documentation for your client binding for details.
The Admin Realm
Ultimately, changes made via the Management Realm are made to a single global, authoritative store containing the complete set of permissions for all Realm files and users controlled by a Realm Object Server instance. This Admin Realm is only modifiable by the Object Server itself, and is not accessible to Realm Mobile Database applications.
High Availability
One of the unique aspects of Realm Mobile Platform is that it is designed to be offline-first. Architecturally, clients retain a local copy of data from the server and read or write directly to their copy. The client SDK then sends the changes asynchronously when network connectivity is available and Realm Object Server automatically integrates these changes in a deterministic manner. Such a system is inherently highly available from the perspective of the client. Reads and writes can always occur locally irrelevant of the network conditions or server operations.
Realm is currently working on a clustering solution that supports automatic failover. This functionality will be available in the Enterprise Edition. To learn more and get early access, please contact us.
Backup
The Realm Object Server provides one or two backup systems, depending on your Edition.
- The manual backup system is included in all versions of Realm Mobile Platform via a command line utility. It can be triggered during server operations to create a copy of the data in the Object Server.
- The continuous backup system, available only in the Enterprise Edition, is a backup server running alongside the main process in the Realm Object Server. It continuously watches for changes across all synchronized Realms and sends changes to one or more backup clients.
Both systems create a directory of Realms from which the Realm Object Server can be restarted after a server crash. The backed up data includes the user Realms, all user account information, and all other metadata used by the Object Server. Both manual and continuous backups can be made from a running Realm Object Server without taking it offline.
The following documentation applies to the Manual Backup feature. For more about Continous Backup, read Continuous Backup in the Enterprise Edition documentation.
The manual backup is a console command that backs up a running instance of the Realm Object Server. This command can be executed on a server without shutting it down, any number of times, in order to create an “at rest” backup that can be stored on long-term storage for safekeeping. In order to be as agnostic as possible regarding the way the backup will be persisted, the command simply creates a directory structure containing everything the server needs to get started again in the event of a disk failure.
It is recommended that the resulting directory is compressed and sent to an off-site location, such as Amazon S3 or Online C14.
Because Realms can be modified during the backup process, the backup command uses Realm’s transaction features to take a consistent snapshot of each Realm. However, since the server is running continuously, the backed up Realms do not represent the state of the server at one particular instant in time. A Realm added to the server while a backup is in progress might be completely left out of the backup. Such a Realm will be included in the next backup.
To run realm-backup at the command line, type:
realm-backup SOURCE TARGET SOURCEis the data directory of the Realm Object Server (typically configured in/etc/realm/configuration.ymlunderstorage.root_path).TARGETis the directory where the backup files will be placed. This directory must be empty or absent when the backup starts for safety reasons.
After the backup command completes, TARGET will be a directory with the same sub directory structure as SOURCE and a backup of all individual Realms.
Server Recovery From A Backup
If the data of a Realm Object Server is lost or otherwise corrupted, a new Realm Object Server can be restarted with the backed up data. This is done simply by stopping the server and copying the latest backup directory (e.g., the TARGET directory in the manual backup procedure, or the storage.root_path directory specified by a continuous backup client) into the Realm Object Server’s data directory (e.g., the SOURCE directory in the manual backup procedure). After the backup has been fully copied into the Realm Object Server’s data directory, the server may be restarted.
Client Recovery From A Backup
Any data added to the Object Server after its most recent backup will be lost when the server is restored from that backup. Since Realm Mobile Database clients communicate with the Object Server continuously, though, it’s possible for them to have been updated with that newer data that’s no longer on the server.
In the case of such an inconsistency, the Realm Object Server will send an error message to the client, and refuse to synchronize data. The error messages relating to synchronization inconsistencies are:
- 207 “Bad server file identifier (INTENT)”
- 208 “Bad client file identifier (IDENT)”
- 209 “Bad server version (IDENT, UPLOAD)”
- 211 “Diverging histories (IDENT)”
If the client receives one of these error messages, the only way to continue synchronization from the server is to start over: erase all the data in the local copy of the Realm that received the error, and re-sync with the server. This way, the client will have all the data (and only the data) on the Object Server and will be in a consistent state.
Note that if this happens, the client will lose any data that only existed on its local, inconsistent copy of the synchronized Realm (i.e., data that was added to it between the time the Object Server crashed and was restored from its backup). The best way to minimize this potential data loss is to use the continuous backup system. If you can’t do that, run the manual backup system frequently.