A self-hosted sync server designed for individual use and built for single-user setups, keeping your Linkora apps in sync. Now with built-in HTTPS support and compatibility with the Linkora browser extension for comprehensive syncing.
- Delta-Sync: Only transfers changed data for efficiency.
- Two-Way Sync: Changes flow in both directions between the server and clients.
- Real-Time Updates: Live updates via WebSocket connections.
- Last-Write-Wins: If multiple devices update the same data, the latest write wins the conflict.
- Secure HTTPS: Secure connections are supported by automatically generating self-signed certificates and keystore files.
- Browser Extension Support: Works with the Linkora browser extension for seamless web activity synchronization.
- Multi-Database Support: Works with MySQL, PostgreSQL, SQLite, and other SQL databases supported by JetBrains Exposed.
- Flexible Deployment: Local JAR, Docker containers, or cloud hosting.
For JAR deployment:
- Java 11 or later
For Docker deployment:
- Docker (handles all dependencies, no Java installation required)
Supported Databases:
- Tested: MySQL, PostgreSQL, SQLite
- Untested: Other databases supported by JetBrains Exposed
Warning: Untested databases may have compatibility issues. Sticking to MySQL, PostgreSQL, or SQLite is recommended for the best experience.
The server automatically handles HTTPS setup by generating self-signed certificates and keystore files on its first run. This means you get secure connections out-of-the-box without manual certificate configuration. These server-signed certificates have a validity period of 365 days. To use these certificates, you may need to import them into your system's trust store or directly into your browser, as the browser extension requires the certificate to be recognized. Some browsers, like Firefox, may reject self-signed certificates, requiring you to manually add an exception for the IPv4 address and port used by HTTPS.
To generate new certificates and keystore files, you have two options:
- Restart the server: If the existing certificate and keystore files are removed from the server's directory, restarting the server will trigger the automatic generation of new ones.
- Use the server's API endpoint: Navigate to
/generate/certs-and-keystore
in your browser. You will be prompted to enter yourserverAuthToken
. Once entered, you will have two options: to only generate new certificates and keystore files (which will be saved in the same directory where the server JAR is located), or to generate and download them. If you choose to generate and download, the server will respond with a ZIP file containing all the newly generated files. If an incorrect authentication token is provided, the server will reject the request.
Get the Linkora browser extension to sync your web-based data. Find detailed setup instructions on the Linkora Browser Extension GitHub repository.
You can configure the server using either a configuration file or environment variables.
This file is auto-generated on the first run; the server will prompt you for required values. The hostAddress
and
serverPort
fields are automatically detected and set by the server.
{
"databaseUrl": "mysql://localhost:3306/linkora",
"databaseUser": "your_username",
"databasePassword": "your_password",
"hostAddress": "xxx.xxx.xxx.xxx",
"serverPort": 45454,
"httpsPort": 54545,
"keyStorePassword": "your_keystore_password",
"serverAuthToken": "your_secure_token"
}
HTTPS Configuration Details:
httpsPort
: This optional field sets the port for HTTPS connections (default:54545
).keyStorePassword
: This password for your keystore is auto-generated by the server.- For HTTPS connections, the server always uses the machine's IPv4 address. The
hostAddress
field in the configuration file primarily applies to HTTP connections.
Use these for containerized deployments, cloud hosting, or any scenario where you prefer environment variables over
configuration files. LINKORA_HOST_ADDRESS
, LINKORA_SERVER_PORT
, LINKORA_HTTPS_PORT
, and
LINKORA_KEY_STORE_PASSWORD
are all optional, as the server can auto-detect/set them.
LINKORA_SERVER_USE_ENV_VAL=true
LINKORA_DATABASE_URL=mysql://localhost:3306/linkora
LINKORA_DATABASE_USER=your_username
LINKORA_DATABASE_PASSWORD=your_password
LINKORA_HOST_ADDRESS=xxx.xxx.xxx.xxx
LINKORA_SERVER_PORT=45454
LINKORA_HTTPS_PORT=54545
LINKORA_KEY_STORE_PASSWORD=your_keystore_password
LINKORA_SERVER_AUTH_TOKEN=your_secure_token
Database | URL Format |
---|---|
MySQL | mysql://hostname:port/database_name |
PostgreSQL | postgresql://hostname:port/database_name |
SQLite | sqlite:/path/to/database/file.db |
Important: For SQLite, leave databaseUser
and databasePassword
empty.
-
Download the latest release JAR file.
-
Create a dedicated folder for the server.
-
Critical: Run from your terminal (never double-click the JAR):
java -jar linkoraSyncServer.jar
Recommendation: Place the JAR file in a separate folder since
linkoraConfig.json
, as well as the server's certificates and keystore files, are generated in the same directory.
# Pull the latest version of the image
docker pull sakethpathike/linkora-sync-server:latest
# Run the server with environment variables
# LINKORA_HOST_ADDRESS, LINKORA_SERVER_PORT, LINKORA_HTTPS_PORT, and LINKORA_KEY_STORE_PASSWORD are optional
docker run -d \
-e LINKORA_SERVER_USE_ENV_VAL=true \
-e LINKORA_DATABASE_URL=mysql://your-db-url \
-e LINKORA_DATABASE_USER=your-username \
-e LINKORA_DATABASE_PASSWORD=your-password \
-e LINKORA_HOST_ADDRESS=xxx.xxx.xxx.xxx \
-e LINKORA_SERVER_PORT=45454 \
-e LINKORA_HTTPS_PORT=54545 \
-e LINKORA_KEY_STORE_PASSWORD=your_keystore_password \
-e LINKORA_SERVER_AUTH_TOKEN=your-secure-token \
-p 45454:45454 \
-p 54545:54545 \
--name linkora-sync-server \
sakethpathike/linkora-sync-server:latest
For cloud hosting platforms:
- Set
LINKORA_SERVER_USE_ENV_VAL=true
in your environment variables. - Configure all required environment variables through your platform's interface.
- Ensure your database is accessible.
Create a service file in /etc/systemd/system
and enable it to run at startup.
Config & JAR files are in the same folder path.
Add the below to your file (change values as per your setup) and name the file as linkora.service
.
[Unit]
Description=linkora service
After=network.target
[Service]
SuccessExitStatus=143
User=root
Group=root
Type=simple
EnvironmentFile=PATH_TO_CONFIG/linkoraConfig.json
WorkingDirectory=PATH_TO_JAR_FILE
ExecStart=/usr/bin/java -jar linkoraSyncServer.jar
ExecStop=/bin/kill -15 $MAINPID
[Install]
WantedBy=multi-user.target
Once saved, reload the daemon & start the service:
systemctl daemon-reload
systemctl start linkora.service
systemctl enable linkora.service
If you can't connect to the server, ensure the necessary ports are allowed through your firewall:
# Allow the HTTP port (default: 45454)
sudo firewall-cmd --add-port=45454/tcp --permanent
# Allow the HTTPS port (default: 54545)
sudo firewall-cmd --add-port=54545/tcp --permanent
sudo firewall-cmd --reload
# Verify the ports are open
sudo firewall-cmd --list-ports
- Authentication Token: Treat
serverAuthToken
as a password—never share it publicly. - Network Access: When connecting from other devices, use the server machine's IPv4 address (or the one detected and
used by the server) instead of
localhost
. For HTTPS connections, the server exclusively uses IPv4. - Client-Server Compatibility: Always verify client-server version compatibility. Mismatched versions may cause sync failures.
Cannot connect to server from Linkora app
- Check if the server port(s) (HTTP: 45454, HTTPS: 54545) are allowed through your firewall.
- Ensure you're using the server machine's IPv4 address (or the one detected and used by the server) instead of
localhost
when connecting from other devices. - Verify the
serverAuthToken
matches between the server and client.
Server fails to start
- Ensure Java 11+ is installed and accessible.
- Check database connectivity and credentials.
- Verify the database URL format is correct for your database type.
- For JAR deployment, ensure you're running from the terminal, not double-clicking.
Database connection errors
- Confirm your database server is running and accessible.
- Verify database URL, username, and password are correct.
- For SQLite, ensure the file path is accessible and the directory exists.
Configuration issues
- Ensure
LINKORA_SERVER_USE_ENV_VAL=true
when using environment variables. - Verify all required fields are properly set in your chosen configuration method.
For detailed technical information about the synchronization mechanism, read the technical blog post.
Beyond the core sync logic, the Linkora Sync-Server also handles rendering user interfaces for specific functions. For
example, the Linkora browser extension's UI is built and served directly by this sync server. The interface for the
certificate generation endpoint is also handled this way. These UIs are generated using my Kotlin Multiplatform library,
Kapsule. Kapsule helps simplify creating static HTML by using a familiar Jetpack Compose-style approach with
kotlinx.html
.
- Single User Design: Designed exclusively for individual use, not multi-user environments.
- Configuration File Location: For JAR deployments,
linkoraConfig.json
is created in the same directory as the JAR file when you first run the server. - Database Compatibility: Linkora supports multiple databases through Exposed. The server has been tested with MySQL, SQLite, and PostgreSQL.
- Environment Variables: For local JAR hosting,
linkoraConfig.json
is recommended. For Docker and cloud hosting, use environment variables. - Host Address: The
hostAddress
field automatically defaults to the machine's current network IPv4 address. The server detects this automatically, so no manual configuration is needed for HTTP connections. When connecting from Linkora apps, use this address instead oflocalhost
. - HTTPS Certificates & Keystore: The server automatically generates required certificates and keystore files.
Star the repo if you find Linkora useful
Contributions are welcome! You can help by:
- Reporting bugs and issues
- Suggesting new features
- Submitting pull requests
- Improving documentation
This project is licensed under the MIT License - see the LICENSE file for details.